# Test Middleware in React Router

Used: react-router@7.3.0 and bun@1.2.4

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](https://sergiodxa.com/tutorials/use-middleware-in-react-router).

## Setting Up the Test

First, create a test file and import the middleware function:

```ts
import { test, expect, mock } from "bun:test";
import { sessionMiddleware, getSession } from "./session";
```

Since middleware functions require a `request` object, a `params` object, a `unstable_RouterContextProvider` instance, and a `next` function, we need to mock them.

```ts
let response = await sessionMiddleware({ request, params, context }, next);
```

Now, let's define the necessary mocks:

```ts
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.

```ts
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:

```ts
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.

```ts
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:

```sh
bun test
```

For the full implementation of the middleware and test cases, check the [GitHub repository of Remix Utils](https://github.com/sergiodxa/remix-utils/blob/c01eca4f9dffb54d300d9037b676517e89a55358/src/server/middlewares/session.test.ts).
