Recently I’ve been refactoring the tests for and I needed to test that it sets the right cookies at the right time. But the cookies in use in the gem are signed cookies and that caused a slight hiccup for me. I’d never tested the value in a signed cookie before and it wasn’t immediately obvious what to do. a gem I maintain So I thought I would share what I found out in case it helps. Cookies on Rails In Rails applications there are three flavours of cookies available: simple session cookies, signed cookies and encrypted cookies. You can set any of these by using the object in a controller, like this: cookies cookies[ ] = cookies.signed[ ] = cookies.encrypted[ ] = < ApplicationController class CookiesController def index "simple" "Hello, I am easy to read." "protected" "Hello, I can be read, but I can't be tampered with." "private" "Hello, I can't be read or tampered with." end end Simple cookies Simple cookies are made up of plain text. If you inspected the cookie above called “simple” in the browser you would see the text “Hello, I am easy to read.” Simple cookies are ok for storing data that doesn’t really matter. The end user can read and change it and your application shouldn’t be affected. Signed cookies Signed cookies are not sent to the browser as plain text. Instead they comprise of a payload and signature separated by two dashes . Before the dashes, the payload is . To read the data you can base 64 decode it. This data isn’t secret, but it can’t be tampered with because the second part of the cookie is a signature. -- base 64 encoded data The signature is created by taking an digest of the application’s and the data in the cookie. If the contents of the cookie are changed when you try to read the cookie, the signature will no longer match the contents and Rails will return . Under the hood this is all handled by the . As you can see above, you don’t need to worry about that, you can treat the object as if it were a hash. HMAC SHA1 secret_key_base nil ActiveSupport::MessageVerifier cookies.signed Signed cookies are useful for data that can be read by the user, but you need to trust is the same when you get it back to the server again. Encrypted cookies Encrypted cookies take this one step further and encrypt the data in the cookie, then sign it. This is handled by the and means that without the you cannot read or write to this cookie. Thankfully there’s no need to worry about the encryption yourself, using the object you can set encrypted cookies as though they were a regular hash. ActiveSupport::MessageEncryptor secret_key_base cookies.encrypted Encrypted cookies are useful for private data that you want to store with the user, but you don’t want them, or anyone, to read. Testing cookies Suppose we now want to test the controller we saw above. We want to ensure that all of our cookies are set correctly. The test might look something like this: test get root_url assert_response assert_equal , cookies[ ] assert_equal , cookies[ ] assert_equal , cookies[ ] < ActionDispatch::IntegrationTest class CookiesControllerTest "should set cookies when getting the index" do :success "Hello, I am easy to read." "simple" "Hello, I can be read, but I can't be tampered with." "protected" "Hello, I can't be read or tampered with." "private" end end Or with RSpec Rails: RSpec.describe CookiesController, it get root_url expect(response).to have_http_status( ) expect(cookies[ ]).to eq( ) expect(cookies[ ]).to eq( ) expect(cookies[ ]).to eq( ) type: :request do "should set cookies when getting the index" do :success "simple" "Hello, I am easy to read." "protected" "Hello, I can be read, but I can't be tampered with." "private" "Hello, I can't be read or tampered with." end end But this would fail at the test for the signed cookie and wouldn’t pass for the encrypted cookie either. You can’t just call on those cookies straight out of the jar if they have been signed or encrypted. You might think you should test against the and version of the cookies, like this: signed encrypted assert_equal , cookies.signed[ ] assert_equal , cookies.encrypted[ ] "Hello, I can be read, but I can't be tampered with." "protected" "Hello, I can't be read or tampered with." "private" That doesn’t work either. At least it doesn’t work if you are using the currently recommended way of testing controllers, with in Minitest or in RSpec. ActionDispatch::IntegrationTest type: :request If you have the older style or tests, then and will work. If you have an application with the older style tests, do carry on reading just in case you decide to refactor them to come in line with the current Rails way. ActionController::TestCase type: :controller cookies.signed cookies.encrypted With the tests above, the object is actually an instance of , which does not have knowledge of your Rails application secrets. cookies Rack::Test::CookieJar So how do we test these cookies? This is where I got to with the gem I was working on. I needed to test the result of a signed cookie, but I had a object. The good news is we can bring the Rails application’s own back into play to decode your signed cookies and decrypt your encrypted cookies. Rack::Test::CookieJar ActionDispatch::Cookies::CookieJar To do so, you instantiate an instance of using the object from the test and a hash of your cookie data. You can then call or on that cookie jar. ActionDispatch::Cookies::CookieJar request signed encrypted So now the test looks like: test get root_url assert_response assert_equal , cookies[ ] jar = ActionDispatch::Cookies::CookieJar.build(request, cookies.to_hash) assert_equal , jar.signed[ ] assert_equal , jar.encrypted[ ] < ActionDispatch::IntegrationTest class CookiesControllerTest "should set cookies when getting the index" do :success "Hello, I am easy to read." "simple" "Hello, I can be read, but I can't be tampered with." "protected" "Hello, I can't be read or tampered with." "private" end end Or the spec would look like: RSpec.describe CookiesController, it get root_url expect(response).to have_http_status( ) expect(cookies[ ]).to eq( ) jar = ActionDispatch::Cookies::CookieJar.build(request, cookies.to_hash) expect(jar.signed[ ]).to eq( ) expect(jar.encrypted[ ]).to eq( ) type: :request do "gets cookies from the response" do :success "simple" "Hello, I am easy to read." "protected" "Hello, I can be read, but I can't be tampered with." "private" "Hello, I can't be read or tampered with." end end Red, Green, Re-snack-tor In this post we’ve seen how to test signed or encrypted cookies in Rails. Hopefully your test suite is running green and your cookies are covered now. I’m going to get back to the refactor I was working on. There are plenty more tests to cover now that these cookies have been polished off.