Cookies - how to set in controller specs?

I’ve been searching Google, the mailing list, etc, etc. and can’t for
the life of me get a cookie to be set in a controller spec. From
everything I’ve read on the web, it appears all I need to do is the
typical:

cookies[:name] = value

or

cookies[:name] = { :value => something, :expires => 1.year.from_now }

I have also see things like doing “@request.cookies[:name]…” or
setting the value to doing CGI::Cookie.new(…), and so on.

I do not want to mock cookies, I want to actually test them, as that
is the logic I’m trying to test. I know that my actual code works as
I’ve run through this by directly testing in the browser, but of
course I want specs to test it. Can someone show a test of setting a
cookie, getting a page/action (and then optionally testing cookie
after that)?


Christopher B.
Cobalt Edge LLC
http://cobaltedge.com

On Tue, Jul 1, 2008 at 6:37 PM, Christopher B.
[email protected] wrote:

I have also see things like doing “@request.cookies[:name]…” or
setting the value to doing CGI::Cookie.new(…), and so on.

I do not want to mock cookies, I want to actually test them, as that
is the logic I’m trying to test. I know that my actual code works as
I’ve run through this by directly testing in the browser, but of
course I want specs to test it. Can someone show a test of setting a
cookie, getting a page/action (and then optionally testing cookie
after that)?

This is just one of those goofy things in Rails testing. I’m not sure
the best way to make it easier in rspec without breaking existing
examples in the process. Regardless, here’s how you interact with
cookies from an example:

To set a cookie:

request.cookies[:cookie_key] = CGI::Cookie.new(‘cookie_key’, ‘cookie
value’)

To read a cookie

response.cookies[:cookie_key].should == [“expected value”]

or

cookies[:cookie_key].should == [“expected value”]

Rails provides a cookies object that is actually response.cookies, so
you don’t have to reference it through the response object. I would,
however, as I’ve been known to try to set a cookie in an example using
cookies when I should have been using request.cookies. So I try to
keep them explicit.

HTH,
David

On Wed, Jul 2, 2008 at 4:06 AM, David C. [email protected]
wrote:

This is just one of those goofy things in Rails testing. I’m not sure
the best way to make it easier in rspec without breaking existing
examples in the process. Regardless, here’s how you interact with
cookies from an example:

To set a cookie:

request.cookies[:cookie_key] = CGI::Cookie.new(‘cookie_key’, ‘cookie value’)

When I do this, in order to get to this cookie in my controller code,
I have to do

cookies[:cookie_key][:cookie_key]

Basically, it appears that what it does is assign that key a hash of
its own. That makes sense of course, as I realize a cookie is really
a hash of name, value, path, expires, and so on. However, it doesn’t
jive with the retrieval, as you shouldn’t have to double reference it
(which I believe is essentially the point of the [] method on
ActionController::CookieJar and is not how things are documented).

However, what’s really behaving weird, is if I do:

cookies[:cookie_key] = “1234”

Then, in my controller code, if I look at “cookies”, it shows that
cookies is a hash, and if I call .keys on it, it spits out
“:cookie_key”, and if I call .values on it, it says “1234”, but if I
then go and do cookies[:cookie_key], it gives me nil.

Again, I have to suspect something weird going on with Rails test
environment/RSpec, since all this works fine outside of tests. Any
suggestions on how to debug this further or what might be wrong?

I should note I’m using Rails 2.1, and RSpec and rspec-rails from
about a week ago (from GitHub).

however, as I’ve been known to try to set a cookie in an example using
cookies when I should have been using request.cookies. So I try to
keep them explicit.

HTH,
David


rspec-users mailing list
[email protected]
http://rubyforge.org/mailman/listinfo/rspec-users


Christopher B.
Cobalt Edge LLC
http://cobaltedge.com

On Wed, Jul 2, 2008 at 9:41 AM, David C. [email protected]
wrote:

Sorry Christopher - try this:

request.cookies[:cookie_key] = ‘cookie value’

I tried that (see below in my email - I just mistakenly wrote it
without the “request.” at the beginning). When I do this, it appears
to set it, but then trying to retrieve it in my controller fails (even
though the key is there, and the value is there, when then requesting
cookies[:cookie_key] I get no value back). Pretty weird.

However, what’s really behaving weird, is if I do:
suggestions on how to debug this further or what might be wrong?

cookies[:cookie_key].should == [“expected value”]
rspec-users mailing list


rspec-users mailing list
[email protected]
http://rubyforge.org/mailman/listinfo/rspec-users


rspec-users mailing list
[email protected]
http://rubyforge.org/mailman/listinfo/rspec-users


Christopher B.
Cobalt Edge LLC
http://cobaltedge.com

My pair and I struggled with this a little bit last week. We decided
to just use a hash to represent cookies in specs, since that’s how
we’re interacting with it. You can see the specs that we wrote here:
http://pastie.org/226443 .

Regards,
Craig

First, nevermind! Oy! I finally figured it out. The reason it
wasn’t working in my controller code was that I was checking for
“cookies[:cookie_key]”, not “request.cookies[:cookie_key]”! It’s a
bit strange how that manifested, given the fact that referencing just
“cookies” was a hash with values, but alas, that’s what was happening.

So, thank you very much for your time (that I essentially wasted :frowning:

On Wed, Jul 2, 2008 at 9:57 AM, Christopher B.
[email protected] wrote:

cookies from an example:

However, what’s really behaving weird, is if I do:
suggestions on how to debug this further or what might be wrong?

cookies[:cookie_key].should == [“expected value”]
rspec-users mailing list



Christopher B.
Cobalt Edge LLC
http://cobaltedge.com


Christopher B.
Cobalt Edge LLC
http://cobaltedge.com

On Jul 2, 2008, at 11:15 AM, Christopher B. wrote:

request.cookies[:cookie_key] = CGI::Cookie.new(‘cookie_key’,
‘cookie value’)

When I do this, in order to get to this cookie in my controller code,
I have to do

cookies[:cookie_key][:cookie_key]

Sorry Christopher - try this:

request.cookies[:cookie_key] = ‘cookie value’

Cheers,
David

On Jul 2, 2008, at 12:42 PM, Christopher B. wrote:

First, nevermind! Oy! I finally figured it out. The reason it
wasn’t working in my controller code was that I was checking for
“cookies[:cookie_key]”, not “request.cookies[:cookie_key]”! It’s a
bit strange how that manifested, given the fact that referencing just
“cookies” was a hash with values, but alas, that’s what was happening.

According to the rails API docs you shouldn’t have to do that:

http://api.rubyonrails.org/classes/ActionController/Cookies.html

I figured out how to make this work. Here were the steps I took to get
there and the solution:

def some_action
puts cookies.inspect, cookies[:cookie_key], cookies.class
end

=> {:cookie_key=>“cookie value”}
=> nil
=> ActionController::CookieJar

So the object is not a Hash, it’s a CookieJar, which acts as a proxy
to a Hash. And guess what it does when it accesses the Hash?

@cookies[name.to_s]

:slight_smile:

So …

This will actually work! I’ve proven it with an example that I’ve
added to rspec-rails -
http://github.com/dchelimsky/rspec-rails/tree/master/spec/rails/example/controller_spec_spec.rb
(look for “should support setting a cookie in the request”):

request.cookies[‘cookie_key’] =
CGI::Cookie.new(‘cookie_key’,‘cookie value’)

That will let you access the cookies as documented in the action.

I’m going to add some sort of support to rspec to make this a bit more
user-friendly and less error prone. I’ll follow up when I’ve done so.

Cheers,
David

On Wed, Jul 2, 2008 at 10:52 AM, David C. [email protected]
wrote:

ActionController::Cookies
=> ActionController::CookieJar
This will actually work! I’ve proven it with an example that I’ve added to
user-friendly and less error prone. I’ll follow up when I’ve done so.
And really, from my interpretation and experiments, if you look at
CookieJar, you can set the value by just passing a string, or a hash.
Passing an actual CGI::Cookie object you’re sort of getting lucky due
to how CGI::Cookie.new happens to parse the “value” key/value pair in
the Hash that it gets sent by CookieJar.[]= method. Unless I’m not
reading it right, what happens when you do:

request.cookies[‘cookie_key’] = CGI::Cookie.new(‘cookie_key’,‘cookie
value’)

is that in CookieJar.[]=, it will wind up doing:

CGI::Cookie.new( { “name” => name.to_s, “value” =>
the_cookie_object_you_passed } )

If you try that in script/console for example, you’ll find that
CGI::Cookie.new happens to parse the value (your cookie object
instance) properly and extract out the actual value. But instead, you
can just simplify that all by simply doing:

request.cookies[‘cookie_key’] = ‘cookie value’

This seems like one of those cases where people were trying to be too
tricky with Ruby code, and mixing symbols and strings in unclear ways
and so on.

the best way to make it easier in rspec without breaking existing

cookies[:cookie_key] I get no value back). Pretty weird.

ActionController::CookieJar and is not how things are documented).
Again, I have to suspect something weird going on with Rails test

or
David
Cobalt Edge LLC

rspec-users mailing list
[email protected]
http://rubyforge.org/mailman/listinfo/rspec-users


Christopher B.
Cobalt Edge LLC
http://cobaltedge.com

On Jul 2, 2008, at 1:21 PM, Christopher B. wrote:

happening.
puts cookies.inspect, cookies[:cookie_key], cookies.class
@cookies[name.to_s]
for “should support setting a cookie in the request”):
And really, from my interpretation and experiments, if you look at

This seems like one of those cases where people were trying to be too
tricky with Ruby code, and mixing symbols and strings in unclear ways
and so on.

I’m thinking of replacing the existing cookies() method (in the
example) with one that returns a CookieJarProxy that will allow you to
do any of the following:

cookies[‘cookie_key’] = ‘cookie value’
cookies[:cookie_key] = ‘cookie value’

cookies[‘cookie_key’].should == ‘cookie value’
cookies[:cookie_key].should == ‘cookie value’

WDYT about that?

WDYT about that?
David, do you plan to allow checks that other values are set as we’d
expect? Other values include:

  • :value
  • :path
  • :domain
  • :expires
  • :secure
  • :http_only

http://www.railsbrain.com/api/rails-2.1.0/doc/index.html?a=M000352&name=cookies

For example, I’d like to verify that I update the value and expiration
date:

it “resets the cookie with the value and new expiration date” do
get_index
cookies[:project_sort][:value].should == “name”
cookies[:project_sort][:expires].beginning_of_day.should ==
1.year.from_now.beginning_of_day
end

Thanks,
Craig

On Jul 2, 2008, at 1:21 PM, Christopher B. wrote:

happening.
puts cookies.inspect, cookies[:cookie_key], cookies.class
@cookies[name.to_s]
for “should support setting a cookie in the request”):
And really, from my interpretation and experiments, if you look at

CGI::Cookie.new( { “name” => name.to_s, “value” =>
the_cookie_object_you_passed } )

If you try that in script/console for example, you’ll find that
CGI::Cookie.new happens to parse the value (your cookie object
instance) properly and extract out the actual value. But instead, you
can just simplify that all by simply doing:

request.cookies[‘cookie_key’] = ‘cookie value’

This doesn’t work for me unless I reference request.cookies in the
controller, which I shouldn’t have to do according to the rails docs.
So for the moment, I’m sticking with:

request.cookies[‘cookie_key’] = CGI::Cookie.new(‘cookie_key’,
‘cookie value’)

This seems like one of those cases where people were trying to be too
tricky with Ruby code, and mixing symbols and strings in unclear ways
and so on.

Totally agree.

So, thank you very much for your time (that I essentially wasted :frowning:

This is NOT at all a waste of time.

Cheers,
David

On Jul 2, 2008, at 1:44 PM, Craig D. wrote:

cookies[:cookie_key].should == ‘cookie value’

  • :secure
    cookies[:project_sort][:expires].beginning_of_day.should ==
    1.year.from_now.beginning_of_day

I had not planned that, no :slight_smile:

Let me get the basics working first and we can talk about beefing it
up like this later.