Rspec-rails: Signed cookies not available in controller specs - rspec-rails 3.5.0, rails 5.0

Created on 6 Jul 2016  ·  19Comments  ·  Source: rspec/rspec-rails

I am unable to test the presence of a signed cookie in a controller. I would expect the test case below to pass and it was passing before I upgraded rails and rspec-rails gems. Is this an issue with rspec-rails or a mistake on my side?

class ApplicationController < ActionController::Base
  helper_method :user_signed_in?
  def user_signed_in?
    cookies.signed[:user_session_key].present?
  end
end

RSpec.describe ApplicationController do
  describe "user_signed_in?" do
    context "when logged in" do
      it "returns true" do
        cookies.signed[:user_session_key] = "1234"
        expect(subject.user_signed_in?).to eq(true)
      end
    end
  end
end
Hacktoberfest Has reproduction case

Most helpful comment

@ivko999 's solution worked for me - thanks!

Even cleaner, just put it in a spec/support file:

# spec/support/cookies.rb
class ActionDispatch::Cookies::CookieJar
  def encrypted; self; end
  def signed; self; end
  def permanent; self; end # I needed this, too
end

All 19 comments

This functionality is all Rails as far as I'm aware, have you added the rails-controller-test gem?

I have a similar problem, I can't set a cookies.encrypted key like I could in Rails 4.2/RSpec 3.4. I was looking at the docs for help, but they seem a little outdated.

Edit: I'm using rails-controller-test and only seems to be a problem when testing an Anonymous controller in ApplicationController.

Looks like we have the same issue @dsandstrom, it only seems to be the case when I'm using subject as the controller. I'm also using rails-controller-test gem.

Signed cookies work fine in the Rails application itself, just not when they are set in the controller spec for a test

Thanks for the issue. Your reproduction spec above is useful, but it'd be great if we had a repository we could clone to reproduce this.

Could you please provide us with a rails app that we can clone that demonstrates the issue. Specifically it'd be great if

1) you could rails new an application and commit
2) make all the changes necessary to reproduce the issue and commit

then, provide us with a description of how to clone your application and reproduce the issue.

Thanks :)

@samphippen https://github.com/dsandstrom/rspec_cookies_5

Check out tests in application_controller_spec.rb. The first one pases, but the second one, that uses the ApplicationController method, doesn't.

Confirmed.

I spent some time trying to figure out where the bug is, but was not successful. I also tried to reproduce with minitest, but couldn't figure out how to set an encrypted cookie. I don't have a lot of experience with the built in test framework.

I have the same problem. With Rails 4.2.1 all Rspec tests regarding signed cookies passed. However, since I have upgraded to Rails 5.0.0 the value returned for all signed cookies keys is nil.

ae29142142324545a328948e059e8b8118fd7a33 is the commit in rails which introduces this

the cause is that "subject.cookies" (i.e. the cookies on the controller) returns a different cookiejar object to the cookies in the spec because of this line: https://github.com/rails/rails/commit/ae29142142324545a328948e059e8b8118fd7a33#diff-873380f872919a451b4e8ce9dcbd57f7R22

I've been looking into this issue more and found a weird work around: call cookies from the AnonymousController:

def index
  cookies
  render text: "success"
end

The cookie gets encrypted and set correctly, but for some reason, it doesn't get passed along until it's manually access. I have no idea why this works, but hopefully it helps with debugging.

From the linked commit, it looks like we need to send the cookie along with the request, but I couldn't figure out how to do that with neither headers nor env params. There is also a Rails test that kinda does what we want: https://github.com/rails/rails/blob/v5.0.0.1/actionpack/test/dispatch/cookies_test.rb#L597 . However, that seems overly complicated and, again, I couldn't get it to work.

@sgrif hi

Hi,
a workaround could be this:

cookies.signed[:foo] = 'bar'
allow(controller).to receive(:cookies).and_return(cookies)

So we'll force the controller to use the cookiejar object of the test.

This issue is not a bug in rspec. It can be reproduced with Rails alone using a normal Rails controller test. I have opened https://github.com/rails/rails/issues/27145 with a reproduction script. This issue can be closed.

cc @samphippen

Maybe like this?

Put this in config/initializers/signed_cookies_patch_test.rb:

if Rails.env.test?
  class ActionDispatch::Cookies::CookieJar
    def encrypted; self; end
    def signed; self; end
  end
end

@ivko999 's solution worked for me - thanks!

Even cleaner, just put it in a spec/support file:

# spec/support/cookies.rb
class ActionDispatch::Cookies::CookieJar
  def encrypted; self; end
  def signed; self; end
  def permanent; self; end # I needed this, too
end

This worked for me

before(:each) do
  allow_any_instance_of(Rack::Test::CookieJar).to receive(:encrypted) { |object| object }
  allow_any_instance_of(ActionDispatch::Cookies::CookieJar).to receive(:encrypted) { |object| object }
end

It didn't pollute other tests.

I needed both because setting seemed to use rack and reading used action dispatch. Odd but I got green only when both were present.

Was this page helpful?
0 / 5 - 0 ratings