How toTest Middleware in React Router
If you're already using React Router middleware, you may want to ensure it works as expected. This article will show you how to test a React Router middleware using Bun Test, though the same approach works with any test runner.
We'll write a test for the middleware from the "How to Use Middleware in React Router" tutorial.
Setting Up the Test
First, create a test file and import the middleware function:
import { test, expect, mock } from "bun:test";
import { sessionMiddleware, getSession } from "./session";
Since middleware functions require a request
object, a params
object, a router context provider
instance, and a next
function, we need to mock them.
let response = await sessionMiddleware({ request, params, context }, next);
Now, let's define the necessary mocks:
import { unstable_RouterContextProvider } from "react-router";
test("returns a response", async () => {
let request = new Request("https://example.com");
let params = {};
let context = new unstable_RouterContextProvider();
let next = mock().mockImplementation(() => new Response(null));
let response = await sessionMiddleware({ request, params, context }, next);
expect(response).toBeInstanceOf(Response);
});
The unstable_RouterContextProvider
class from React Router allows middleware to store values that other middleware, loaders, or actions can use.
Ensuring the Session is Set
Now, let's update our test to check that the session is correctly stored in the context provider.
import { isSession } from "react-router";
test("sets the session instance in context", async () => {
let request = new Request("https://example.com");
let params = {};
let context = new unstable_RouterContextProvider();
let next = mock().mockImplementation(() => new Response(null));
let response = await sessionMiddleware({ request, params, context }, next);
let session = getSession(context);
expect(isSession(session)).toBeTrue();
});
Verifying the next
Function is Called
Middleware should always call the next
function. Let's test that:
test("calls the next function", async () => {
let request = new Request("https://example.com");
let params = {};
let context = new unstable_RouterContextProvider();
let next = mock().mockImplementation(() => new Response(null));
let response = await sessionMiddleware({ request, params, context }, next);
expect(next).toHaveBeenCalledTimes(1);
});
Checking if the Session is Committed
Since the middleware commits the session, we need to verify that the response includes the Set-Cookie
header.
test("commits the session in the response headers", async () => {
let request = new Request("https://example.com");
let params = {};
let context = new unstable_RouterContextProvider();
let next = mock().mockImplementation(() => new Response(null));
let response = await sessionMiddleware({ request, params, context }, next);
expect(response.headers.get("Set-Cookie")).toBeString();
});
Here, we're only confirming that Set-Cookie
is set, not whether the session data is correct. However, it's a solid starting point.
Running the Tests
You can run the tests using:
bun test
For the full implementation of the middleware and test cases, check the GitHub repository of Remix Utils.