开发者

how do i test cookie expiry in rails rspec

开发者 https://www.devze.com 2023-03-15 12:02 出处:网络
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

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?


Browsers do not send cookie attributes back to the server. This is why you can only send the key-value pair to the action.

Since you can assume that Rails, Rack and browsers do the right thing with the arguments, all you really need to test is the arguments your code is passing to the CookieJar.

To test that expiry is being set properly in the controller setting the cookie, you could stub out the #cookies method and make sure the right settings are being passed to it.

# app/controllers/widget_controller.rb
...
def index
    cookies[:expiring_cookie] = { :value   => 'All that we see or seem...', 
                                  :expires => 1.hour.from_now }
end
...

# spec/controllers/widget_controller_spec.rb
...
it "sets the cookie" do
  get :index
  response.cookies['expiring_cookie'].should eq('All that we see or seem...')
                                               # is but a dream within a dream.
                                               #                - Edgar Allan Poe
end

it "sets the cookie expiration" do
  stub_cookie_jar = HashWithIndifferentAccess.new
  controller.stub(:cookies) { stub_cookie_jar }

  get :index
  expiring_cookie = stub_cookie_jar['expiring_cookie']
  expiring_cookie[:expires].to_i.should be_within(1).of(1.hour.from_now.to_i)
end
...

Testing much more than this is boiling the ocean. At some point, you have to assume that the stack you are sitting on (e.g., Rails, Rack, the web server, TCP/IP, OS, web browsers, etc) works properly and focus on the code you control.


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


Another option using Timecop:

Timecop.freeze(Time.now)

expect(controller.send(:cookies)).to receive(:[]=).with('cookie_name',
  value:   'whatever',
  expires: 1.hour.from_now
)

get :index


set request.cookies['transaction_code'] as a CGI::Cookie in your spec. http://www.ruby-doc.org/stdlib/libdoc/cgi/rdoc/classes/CGI/Cookie.html#M000169


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/
  )
0

精彩评论

暂无评论...
验证码 换一张
取 消