Home

Fri Aug 23 2024

Easy mocking of API requests with Next.js and Playwright

Pease see the example project for the full code. Please also visit the page on cat-fact.melkstam.com to see the example in action.

We are underway with developing a new Next.js application at work where we wanted to setup some end-to-end tests. However, our backend is a go application built and hosted with Encore, and in the name of simplicity, we wanted to be able to mock the API requests made to the backend.

Playwright has become a very popular tool for testing web applications, and became the tool of choice for us here. Howerver, we had to figure out how to mock the API requests made by the Next.js application, both client- and server-side. This is where the Next.js experimental test mode for playwright came in handy.

The Next.js project

In this example, we have a simple Next.js project that fetches a random cat fact using the meowfatcs API.

page.tsx

export default async function CatFactPage() {
const fact = await fetch('https://meowfacts.herokuapp.com/')
.then(response => response.json())
.then(body => body.data[0]);
return (
<>
<h1>Cat fact</h1>
<p>{fact}</p>
</>
)
}

Had this call been made on the client-side, we could have used Playwright's page.route (docs) method to intercept the request and return a predefined cat fact. However, since this is a server-component, we need to set up a proxy to intercept the request.

Setting up the proxy

To make it easier to mock the API requests, both client- and server-side, we can use the Next.js experimental proxy feature.

First we need to enable the the test mode in the next.config.js|mjs file by setting the experimental.testProxy flag to true.

next.config.js

module.exports = {
experimental: {
testProxy: true,
},
}

If Playwright is not already installed, please go ahead and install Playwright.

Lastly, we need to update the playwright.config.ts file to use the proxy server.

playwright.config.ts

import { defineConfig } from 'next/experimental/testmode/playwright'
export default defineConfig({
// Other config
// Let Playwright start the Next.js project before running the tests
// See https://playwright.dev/docs/test-webserver
webServer: {
command: 'pnpm dev',
url: 'http://localhost:3000',
},
})

Please note that we have updated the import to be from next/experimental/testmode/playwright instead of @playwright/test. This allows Next.js to add any required configuration for the proxy server to work as expected.

Writing the test

Now that the proxy server is set up, we can write the test to mock the API request.

cat-fact.spec.ts

import { test, expect } from "next/experimental/testmode/playwright";
test('displays a cat fact', async ({ page, next }) => {
// Listen for any fetch requests
next.onFetch((request) => {
if (request.url.includes('meowfacts.herokuapp.com')) {
return new Response(JSON.stringify({
data: ['A group of cats is called a clowder.']
}));
}
// If the request is not to the meowfacts API, abort it
return "abort";
});
// Navigate to the page
await page.goto('http://localhost:3000/');
// Check that the cat fact is displayed
await expect(page.getByText('A group of cats is called a clowder.')).toBeVisible();
});

This is all you need to do to mock the API requests made by the Next.js application, both client- and server-side.

To run the test, you can use the following command:


pnpm exec playwright test # Run test in terminal
pnpm exec playwright test --ui # Run test in UI mode

Using msw

The Nextjs test proxy has support for using msw instead of the next.onFetch syntax.

However, there's a bug that means that it sadly will not work at the moment :(