Problem
We want to write tests for our GraphQL server. Our app uses cookie-based authentication to protect certain resolvers. For example, the user must be logged in to create a new Post.
This is easy in production, because the browser handles the cookie stuff automatically: it stores the cookie when the server tells it to, and then it sends that cookie with every request to prove that the user is logged in.
Ok that's great in the browser, but we're writing tests in our Node app. So how do we store the cookie? How do we send it along with subsequent requests (using Axios in our tests) so we can test those auth-protected resolvers, like createPost?
Solution
Well, the important thing to remember is that a cookie is just a string. It's not special.
That string lives in the http header of:
The response from the server after a successful login
The subsequent requests from the client after receiving the cookie in step 1.
So to "use cookies" in our tests, all we need to do is pass this string around.
This means a few things concretely:
Grab the cookie string out of the http header of a successful login response.
Send that cookie string through to our requests to protected resolvers (again, in the http header of the request)
Implementation
The test
The cookie string we want lives in an array at the "set-cookie" property of the response header object.
We're only setting one cookie, so we can grab the cookie we want at the 0th index of that array.
Then, we pass that cookie along to our API wrapper function userApi.createPost
. This function is just a wrapper around an Axios call. Let's inspect that function to see how we use that cookie string.
The Axios call
We place that cookie string at headers.Cookie.
Doing this satisfies our GraphQL server, who looks at the incoming request, sees the appropriate cookie, and grants access to auth-protected resolvers.
The moral of the story
Cookies are not very special, and that's great. They're just strings in the http header. If we know where to look, we can grab those strings and pass them around as we please.
One more thing
Ok great, cookies are just strings, but they kind of act like objects with a property name and a value
"cookie1=value1; cookie2=value2"
What if we want to use this as an object? We could manually parse this string with regex, but we can also just use the handy cookie npm package like this:
import Cookie from "cookie"; const cookieStr = "cookie1=value1; cookie2=value2" const cookieObj = Cookie.parse(cookieStr);
This will give us a nice Javascript object we can more easily inspect an manipulate:
{ cookie1: "value1", cookie2: "value2", }
Well that's nifty.
We can take this even further since our cookie actually stores a JSON Web Token as a string. When decoded, this string has an object with details about our user.
Here's the full test that tests to see if that user object really does live inside that string.
Note that the object inside the token contains an "iat" (Issued At) value. We can't rely on this in our test, so we strip it out of the result before the comparison.
🍪Thanks for reading.