how do i test cookie expiry in rails rspec

Viewed 7473

There is a lot of confusion about setting cookies in rspec http://relishapp.com/rspec/rspec-rails/v/2-6/dir/controller-specs/file/cookies

in your controller, normally you can write

cookies['transaction_code'] = { :expires => 300.seconds.from_now, :value => c }

but in rspec i can only write

request.cookies['transaction_code'] = transaction_code

if i say

request.cookies['transaction_code'] = { :expires => 300.seconds.from_now, :value => c }

i get the hash back as value of cookies['transaction_code'] in my controller.

Now my question is: how do i set/test cookie expiry then in an rspec controller test example?

UPDATE: On seconds thought: What i mean is: how do i test if the controller is reacts to an expired cookie as expected, but in fact an expired cookie is just like no cookie if i trust cookie implementation, which i should do, so after all maybe my question makes no sense. If this is the case, i need to test if (another) controller action sets an expiring cookie correctly, but how do i do it if cookies['transaction_code'] in the test only gives the value back?

5 Answers

I came from the future with this:

  it 'sets the cookie expiration' do
    stub_cookie_jar = HashWithIndifferentAccess.new
    allow(controller).to receive(:cookies).and_return(stub_cookie_jar)
    get :index
    expiracy_date = stub_cookie_jar[:expires]
    expect(expiracy_date).to be_between(1.hour.from_now - 1.minutes, 
                                        1.hour.from_now)
  end

If you want to check several cookie attributes at once, inspect the Set-Cookie header, something like this:

it 'expires cookie in 15 minutes' do
  travel_to(Date.new(2016, 10, 25))
  post 'favorites', params: { flavor: 'chocolate' }
  travel_back

  details = 'favorite=chocolate; path=/; expires=Tue, 25 Oct 2016 07:15:00 GMT; HttpOnly'
  expect(response.header['Set-Cookie']).to eq details
end

This is a bit brittle, in that other, non-critical attributes of the cookie may break this string. But it does keep you out of Rails internals, and lets you check several attributes at once.

A better way is to match just one attribute at a time, this is a much more robust method that is not so vulnerable to changes in how the Set-Cookie string is constructed, or what other attributes you might add to the cookie in the future:

  expect(response.header['Set-Cookie']).to match(
    /favorite=chocolate.*; expires=Tue, 25 Oct 2016 07:15:00 GMT/
  )
Related