Set Cookie on Rack Mock Request


Rack apps are generally straightforward to test because of their very basic public interface. But where do we put specific things, in this case, a cookie for the request, on that env argument it takes? Here's one way.

env

The env argument that is sent to #call in a Rack app is an variable that represents the environment of the request. It is a hash of CGI-like headers: request method, query params, http headers -- that sort of thing.

The HTTP_* keys on the hash will be read as request headers from the environment.

Rack MockRequest Cookies

Rack provides a great little Rack::MockRequest helper object in its library that will help us test our app. This object has a class method called env_for which allows for quick construction of an env var that is a request to a specified url.

On the returned env we will continue to make modifications before passing it to our Rack app. We'll add our cookie header with a key of HTTP_COOKIE. The value will be of the format cookieName=cookieValue. We can handle multiple cookies by separating the cookies with ; .

Let's say we're testing a token authentication middleware with rspec. Our spec may look something like this:

it "accepts an cookie token in the request" do
  middleware = # ... instantiate rack middleware
  env = Rack::MockRequest.env_for("/protected")
  env["HTTP_COOKIE"] = "AUTH_COOKIE=123"
  status, _, _ = middleware.call(env)
  expect(status).to eq(200)
end

Then in our Rack app source, we can code for the availability of a cookie on the request. It might look like:

# ...
def call(env)
  request = Rack::Request.new(env)
  token = request.cookies["AUTH_TOKEN"]
  # ...
end

Is this the easiest or best way to set cookies on requests when testing Rack apps? What do you do?