Background
Rails offers several methods to manage Show archive.org snapshot three types of different cookies along with a session storage for cookies Show archive.org snapshot . These are normal, signed and encrypted Show archive.org snapshot cookies.
By following the happy path of testing a web application, that is only the main use-case is tested as a integration test and the rest as isolated (more unit like) tests, one might want to test some cookie dependent behavior as a request, helper or model spec too.
Since the rspec documentation Show archive.org snapshot on testing cookies is rather sparse and only focuses on controller specs, which recommended usage have been limited since Rails 5+ ( see "Rails: Support for Rails 5" Show archive.org snapshot ), this card will summarize some guidance on how to spec with cookies.
Warning
Note that using
request.cookies
andresponse.cookies
is not recommend Show archive.org snapshot by RSpec anymore as can be read in the documentation link Show archive.org snapshot above.
Model specs
Whenever you have to use the same cookie dependent logic between controllers and some controller helpers, you should extract that into a class to DRY up your code and write solid unit tests.
Beware that your class will not be able to read the cookies, since they are only available within the controller and view context. Because of that, consider passing the required cookie value to the model initialization:
class Movie::FavoriteMovieCookies
attr_reader :favorite_movie_ids
def initialize(cookies, movie_id)
@favorite_movies_cookie_value = cookies.signed[:favorite_movies]
@movie_id = movie_id
@cookies = cokies
set_favorite_movie_ids # read out from the cookie values
end
... # some methods to parse and manipulate the cookies value
end
Tip
Session cookies will do the parsing of JSON by default.
If it is not an option to stub the cookies jar object, you can create one by using:
cookies_jar = ActionDispatch::Cookies::CookieJar.build(nil, {})
cookies_jar.signed[:test] = 'test'
However #signed
or #encrypted
won't work within the model context on cookies_jar
and will require stubbing these method or having to assure some of the cookies dependencies.
Helper Specs
Setting cookies in a helper spec Show archive.org snapshot shows that the cookies can simply set or expect by using one of the following options:
helper.cookies[:foo] = "bar"
helper.cookies.signed[:foo] = "bar"
helper.cookies.encrypted[:foo] = "bar"
Request Specs
In request specs you can simply access the current cookies by calling cookies
. If you want
to add a cookie before a request
Show archive.org snapshot
you can simply set the cookie on the cookies
object as usual.
Signed and encrypted cookies
Even though the cookies
method is available within the request spec, it is not working for signed and encrypted cookies.
Solution
One can
simply decrypt the cookies by creating
Show archive.org snapshot
an object of ActionDispatch::Cookies::CookieJar
. The reason for this is, that request specs use a Rack::Test::CookieJar
object, while only ActionDispatch::Cookies::CookieJar
supports the #encrypt
and #signed
methods.
If you do have to set an encrypted or signed cookie before the request you can use a ActionDispatch::Cookies::CookieJar
object for this as well:
cookies_jar = ActionDispatch::Cookies::CookieJar.build(request, cookies.to_hash)
cookies_jar.signed[:user_id] = 1
cookes[:user_id] = cookies_jar[:user_id]
get "/movies/#{user_id}/favorite"
Example:
describe '/movies/:id/favorite' do
def cookies_jar
ActionDispatch::Cookies::CookieJar.build(request, cookies.to_hash)
end
it 'sets the cookies' do
movie = create(:movie)
user = sign_in(role: 'admin')
patch "/movies/#{movie.id}/favorite"
expect(cookies_jar.signed[:favorite_movies]).to eq "{\"#{user.id}\":[\"#{movie.id}\"]}"
end
end