web-dev-qa-db-fra.com

Test RSpec rediriger vers l'URL avec les paramètres GET

Disons que j'ai un FoosController avec un redirect_to_baz méthode.

class FoosController < ApplicationController

  def redirect_to_baz
    redirect_to 'http://example.com/?foo=1&bar=2&baz=3'
  end

end

Je teste cela avec spec/controllers/foos_controller_spec.rb:

require 'spec_helper'

describe FoosController, :type => :controller do

  describe "GET redirect_to_baz" do
    it "redirects to example.com with params" do
      get :redirect_to_baz
      expect(response).to redirect_to "http://example.com/?foo=1&bar=2&baz=3"
    end
  end

end

Ça marche. Cependant, si quelqu'un échange les paramètres de la chaîne de requête (par exemple http://example.com/?bar=2&baz=3&foo=1), le test échoue.

Quelle est la bonne façon de tester cela?

Je voudrais faire quelque chose comme:

expect(response).to redirect_to("http://example.com/", params: { foo: 1, bar: 2, baz: 3 })

J'ai regardé le documentation et j'ai essayé de rechercher response.parameters, mais je n'ai rien trouvé de tel. Même Hash#to_query ne semble pas résoudre ce problème.

Toute aide serait grandement appréciée.

27
Simone

Dans documentation , le chemin de redirection attendu peut correspondre à une expression régulière:

expect(response).to redirect_to %r(\Ahttp://example.com)

Pour vérifier la chaîne de requête de l'emplacement de redirection, cela semble un peu plus compliqué. Vous avez accès à l'emplacement de la réponse, vous devriez donc pouvoir le faire:

response.location
# => http://example.com?foo=1&bar=2&baz=3

Vous devriez pouvoir extraire les paramètres de chaîne de requête comme ceci:

redirect_params = Rack::Utils.parse_query(URI.parse(response.location).query)
# => {"foo"=>"1", "bar"=>"2", "baz"=>"3"}

Et à partir de là, il devrait être simple de vérifier que les paramètres de redirection sont corrects:

expect(redirect_params).to eq("foo" => "1", "baz" => "3", "bar" => "2")
# => true

Si vous devez faire ce type de logique plus d'une fois, il serait certainement pratique de tout regrouper dans un matcher rspec personnalisé.

26
hjing

Êtes-vous en mesure d'utiliser vos aides d'itinéraire plutôt qu'une simple chaîne? Si c'est le cas, vous pouvez simplement passer des paramètres de hachage à un assistant d'itinéraire et ils seront convertis en paramètres de chaîne de requête:

root_url foo: 'bar', baz: 'quux'
=> "http://www.your-root.com/?baz=quux&foo=bar"
expect(response).to redirect_to(root_url(foo: 'bar', baz: 'quux'))

Cela vous aide-t-il ou êtes-vous limité à utiliser des chaînes plutôt que des aides de route?

Une autre pensée est que vous pouvez simplement affirmer directement sur les valeurs du hachage des paramètres plutôt que sur la chaîne de requête url +, car les paramètres de la chaîne de requête seront sérialisés dans le hachage des paramètres ...

6
Cade

J'avais besoin de quelque chose de similaire et je me suis retrouvé avec ceci:

A pu écrire des tests et ne pas se soucier de l'ordre des paramètres de requête.

expect(response.location).to be_a_similar_url_to("http://example.com/?beta=gamma&alpha=delta")

Déposez ce qui suit dans ./spec/support/matchers/be_a_similar_url_to.rb

RSpec::Matchers.define :be_a_similar_url_to do |expected|
  match do |actual|
    expected_uri = URI.parse(expected)
    actual_uri = URI.parse(actual)

    expect(actual_uri.Host).to eql(expected_uri.Host)
    expect(actual_uri.port).to eql(expected_uri.port)
    expect(actual_uri.scheme).to eql(expected_uri.scheme)
    expect(Rack::Utils.parse_nested_query(actual_uri.query)).to eql(Rack::Utils.parse_nested_query(expected_uri.query))
    expect(actual_uri.fragment).to eql(expected_uri.fragment)
  end

  # optional
  failure_message do |actual|
    "expected that #{actual} would be a similar URL to #{expected}"
  end

  # optional
  failure_message_when_negated do |actual|
    "expected that #{actual} would not be a similar URL to #{expected}"
  end
end
2
Ben Walding