Testing Async RSCs with Jest
Testing asynchronous React server components can be a bit tricky, as it's not officially supported by Jest yet. However, with a few workarounds, we can still ensure that our async components are rendering correctly and fetching the expected data.
In this lesson, we'll create an async React server component that fetches data from the Pokemon API and displays a list of Pokemon names. We'll then write a test to verify that our component is rendering correctly and returning the expected data.
Creating the Route and RSC
Let's start by creating a new route in our Next.js application. To do this, create a new directory called pokemon
and add a page.tsx
file inside it with the following RSC code:
export default async function Page() {
const pokemon = (await fetch("https://pokeapi.co/api/v2/pokemon").then(
(res) => res.json()
)) as { results: { name: string }[] };
return (
<div>
<h1>Pokemon</h1>
<ul>
{pokemon.results.map((p) => (
<li key={p.name}>{p.name}</li>
))}
</ul>
</div>
);
}
In this Page
component, we're fetching data from the Pokemon API and rendering a list of Pokemon names.
Save the file and run the server. Navigate to localhost:3000/Pokemon
, and you should see the list of Pokemon.
Writing the Test
Now, let's write a test to ensure that our component is rendering correctly. We'll use "Bulbasaur" as a key to check if we're getting the expected result.
Create a page.test.tsx
file in the same directory as page.tsx
, and add the following code:
import { render, screen } from "@testing-library/react";
import Page from "./page";
test("RSC Page", async () => {
render(await Page());
expect(await screen.findByText("bulbasaur")).toBeDefined();
});
The key difference between testing this component and other components is that it's an async component. Instead of invoking it as a component using createElement
, we simply await calling Page
which is the component we created previously. Once the Page
component is rendered, we use screen.findByText
to look for the text "bulbasaur".
Save the file and run the test. It should fail with an error saying that fetch
is not defined.
Mocking fetch
One way to solve this issue is to mock fetch
directly in our test file. To do this, we'll set window.fetch
to a mock implementation that resolves with the data we expect from the API:
window.fetch = jest.fn().mockImplementation(() =>
Promise.resolve({
ok: true,
json: () => ({
results: [
{
id: 1,
name: "bulbasaur",
}
]
})
})
);
Save the file and run the test again. It should pass quickly, without depending on the external service.
Using isomorphic-fetch
If you want to make the actual API call in your test, you can use the isomorphic-fetch
package, which shims fetch
on the server-side.
Install isomorphic-fetch
as a dev dependency:
pnpm add isomorphic-fetch -D
Then remove the fetch
mocking code from the test file and import isomorphic-fetch
at the top:
// inside src/app/pokemon/page.test.tsx
import 'isomorphic-fetch';
Save the file and run the test. It should pass, but now it relies on the Pokemon API being available.
Setting Up a Global Test Setup File
Say you have multiple tests that all require isomorphic-fetch
. By creating a global setup file, you can avoid importing it in every test file.
Create a new jest.setup.ts
file in your project's root directory, and add the following line:
// inside jest.setup.ts
import 'isomorphic-fetch';
Then we'll need to add the setup file to the jest.config.ts
file located in the project root, and add the following option:
// jest.config.js
module.exports = {
// ...
setupFiles: ["<rootDir>/jest.setup.ts"],
// ...
};
This tells Jest to run the jest.setup.ts
file before running any tests.
Remove the isomorphic-fetch
import from page.test.tsx
file, save it, and run the test again. It should still pass.
Recap
Testing async React server components with Jest requires a few workarounds, as it's not officially supported yet. By mocking fetch
requests or using the isomorphic-fetch
package, we can ensure that our tests are running correctly and returning the expected data.
Remember to keep an eye out for updates on official support for testing async server components in Jest. Once it's available, this lesson will be updated with the new approach.