環境
- Rails 5.2.3
- RSpec 3.9.0
問題/やりたいこと
そのままでは request spec 内で signed cookie 及び encrypted cookie にアクセス出来ません。
具合的には、以下のようなエラーが出ます。
NoMethodError:
undefined method `signed' for #<Rack::Test::CookieJar:0x00007fbc6751fa38>
これは、request spec 内で使われている cookies オブジェクトが ActionDispatch::Cookies::CookieJar
ではなく Rack::Test::CookieJar
のインスタンスであり、signed
や encrypted
メソッドを実装していないためです。
解決方法
ActionDispatch::Cookies::CookieJar
を使います。
it do
get some_url
expect(response).to have_http_status(:success)
jar = ActionDispatch::Cookies::CookieJar.build(request, cookies.to_hash) # ここ
expect(jar.signed['foo']).to eq('something') # signed cookie も
expect(jar.encrypted['bar']).to eq('something_else') # encrypted cookie も読み取れるようになる
end
補足
ただこれだけでは、secure: true
(httpsサーバにだけcookieを送信する設定)の場合には動きません。(jar.signed['foo']
の部分が nil
になってしまいます)
cookies.signed[:foo] = {
value: 'your_value_comers_here',
expires: 1.day.from_now,
secure: true, # この設定
httponly: true
}
その場合、development
及び test
環境では、 secure: true
を使わないようにしましょう。
def method_that_uses_cookie
foo = 'foo'
cookies.encrypted[:foo] = build_cookies(foo)
end
def build_cookies(value)
cookie = {
value: value,
expires: 1.day.from_now,
httponly: true
}
if Rails.env.development? || Rails.env.test?
cookie
else
cookie.merge(secure: true)
end
end
補足2
↑の補足の代替案として、rspec を ssl モードで動かす方法も試しました。
https://stackoverflow.com/questions/6785261/test-an-https-ssl-request-in-rspec-rails に書かれているように protocol: 'https://'
や protocol: :https'
を試しましたが、駄目でした。
ArgumentError: unknown keyword: protocol
と言われるので、そもそも protocol
が rspec でサポートされていないようです。
元ネタ
こちらの記事を参考にさせてもらいました。
https://philna.sh/blog/2020/01/15/test-signed-cookies-in-rails/