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

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

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Reactions: 17
  • Comments: 20 (6 by maintainers)

Most upvoted comments

@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 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.

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.

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

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.

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

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.

Confirmed.