web-dev-qa-db-ja.com

RSpecテストは、GETパラメーターを使用してURLにリダイレクトします

redirect_to_bazメソッドを持つFoosControllerがあるとします。

class FoosController < ApplicationController

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

end

これを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

できます。ただし、誰かがクエリ文字列パラメーター(例:http://example.com/?bar=2&baz=3&foo=1)を交換すると、テストは失敗します。

これをテストする正しい方法は何ですか?

私は次のようなことをしたいと思います:

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

documentation を見て、response.parametersを検索してみましたが、そのようなものは見つかりませんでした。 Hash#to_queryでもこの問題を解決できないようです。

どんな助けでも大歓迎です。

27
Simone

documentation から、予期されるリダイレクトパスは正規表現と一致する可能性があります。

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

リダイレクト場所のクエリ文字列を確認することは、もう少し複雑に思えます。レスポンスの場所にアクセスできるので、これを実行できるはずです。

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

次のようにクエリ文字列パラメータを抽出できるはずです。

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

それから、リダイレクトパラメータが正しいことを確認するのは簡単です。

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

ただし、この種のロジックを複数回実行する必要がある場合は、それをすべてカスタムのrspecマッチャーにラップすると便利です。

26
hjing

プレーンな文字列ではなく、ルートヘルパーを使用できますか?その場合は、ハッシュパラメータをルートヘルパーに渡すだけで、クエリ文字列パラメータに変換されます。

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'))

それは役に立ちますか、それともルートヘルパーではなく文字列の使用に制限されていますか?

もう1つの考えは、クエリ文字列paramsがparamsハッシュにシリアル化されるため、url +クエリ文字列ではなく、paramsハッシュの値を直接アサートするだけでよいということです...

6
Cade

私は似たようなものが必要で、これで終わりました:

テストを記述でき、クエリパラメータの順序を気にしませんでした。

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

以下を./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