9
votes

This is a problem with the cookies collection in a controller spec in the following environment:

  • rails 3.1.0.rc4
  • rspec 2.6.0
  • rspec-rails 2.6.1

I have a simple controller spec that creates a Factory user, calls a sign in method which sets a cookie, and then tests to see if the signed in user may access a page. The problem is that all cookies seem to disappear between the authentication cookie being set and the "show" action being called on my controller.

My code works fine when run in a browser on the rails dev server. The even stranger behavior while running the spec is that everything set though the cookies hash disappears but everything set through the session hash persists. Am I just missing something about how cookies work when using rspec?

Spec code

it "should be successful" do
  @user = Factory(:user)
  test_sign_in @user
  get :show, :id => @user
  response.should be_success
end

Sign in code

def sign_in(user, opts = {})
  if opts[:remember] == true
    cookies.permanent[:auth_token] = user.auth_token
  else
    cookies[:auth_token] = user.auth_token
  end
  session[:foo] = "bar"
  cookies["blah"] = "asdf"
  self.current_user = user
  #there are two items in the cookies collection and one in the session now
end

Authentication check on the get :show request fails here because cookies[:auth_token] is nil

def current_user
 #cookies collection is now empty but session collection still contains :foo = "bar"... why?
 @current_user ||= User.find_by_auth_token(cookies[:auth_token]) if cookies[:auth_token]
end

Is this a bug? Is it some sort of intended behavior that I don't understand? Am I just looking past something obvious?

3
I get the same problem - I have tried a lot of permutations and rooting around and I can't get this to function correctlyRichard Jordan

3 Answers

7
votes

This is how I solved this:

def sign_in(user)
 cookies.permanent.signed[:remember_token] = [user.id, user.salt]
 current_user = user
 @current_user = user
end

def sign_out
 current_user = nil
 @current_user = nil
 cookies.delete(:remember_token)
end

def signed_in?
 return !current_user.nil?
end

For some reason you have to set both @current_user and current_user for it to work in Rspec. I'm not sure why but it drove me completely nuts since it was working fine in the browser.

3
votes

Ran into the same problem. Try using @request.cookie_jar from your tests.

2
votes

The extra lines above are not necessary. I found that simply calling the self.current_user = user setter method can automatically update the instance variable. For some reason, calling it without self doesn't call the setter method.

Here's my code without the extra lines:

def sign_in(user)
  cookies.permanent.signed[:remember_token] = [user.id, user.salt]
  self.current_user = user
end

def sign_out
  cookies.delete(:remember_token)
  self.current_user = nil
end

def current_user=(user)
  @current_user = user
end

I still don't know why, maybe an Rspec bug