Learn how to set up Next.js with three commonly used testing tools: [Cypress](https://www.cypress.io/blog/2021/04/06/cypress-component-testing-react/), [Jest](https://jestjs.io/docs/tutorial-react), and [React Testing Library](https://testing-library.com/docs/react-testing-library/intro/).
## Cypress
Cypress is a test runner used for **End-to-End (E2E)** and **Integration Testing**.
You can use `create-next-app` with the [with-cypress example](https://github.com/vercel/next.js/tree/canary/examples/with-cypress) to quickly get started.
To get started with Cypress, install the `cypress` package:
```bash
npm install --save-dev cypress
```
Add Cypress to the `package.json` scripts field:
```json
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"cypress": "cypress open",
}
```
Run Cypress for the first time to generate examples that use their recommended folder structure:
```bash
npm run cypress
```
You can look through the generated examples and the [Writing Your First Test](https://docs.cypress.io/guides/getting-started/writing-your-first-test) section of the Cypress Documentation to help you get familiar with Cypress.
### Creating your first Cypress integration test
Assuming the following two Next.js pages:
```jsx
// pages/index.js
import Link from 'next/link'
export default function Home() {
return (
<nav>
<Linkhref="/about">
<a>About</a>
</Link>
</nav>
)
}
```
```jsx
// pages/about.js
export default function About() {
return (
<div>
<h1>About Page</h1>
</div>
)
}
```
Add a test to check your navigation is working correctly:
```jsx
// cypress/integration/app.spec.js
describe('Navigation', () => {
it('should navigate to the about page', () => {
// Start from the index page
cy.visit('http://localhost:3000/')
// Find a link with an href attribute containing "about" and click it
cy.get('a[href*="about"]').click()
// The new url should include "/about"
cy.url().should('include', '/about')
// The new page should contain an h1 with "About page"
cy.get('h1').contains('About Page')
})
})
```
You can use `cy.visit("/")` instead of `cy.visit("http://localhost:3000/")` if you add `"baseUrl": "http://localhost:3000"` to the `cypress.json` configuration file.
### Running your Cypress tests
Since Cypress is testing a real Next.js application, it requires the Next.js server to be running prior to starting Cypress. We recommend running your tests against your production code to more closely resemble how your application will behave.
Run `npm run build` and `npm run start`, then run `npm run cypress` in another terminal window to start Cypress.
> **Note:** Alternatively, you can install the `start-server-and-test` package and add it to the `package.json` scripts field: `"test": "start-server-and-test start http://localhost:3000 cypress"` to start the Next.js production server in conjuction with Cypress. Remember to rebuild your application after new changes.
### Getting ready for Continuous Integration (CI)
You will have noticed that running Cypress so far has opened an interactive browser which is not ideal for CI environments. You can also run Cypress headlessly using the `cypress run` command:
Playwright is a testing framework that lets you automate Chromium, Firefox, and WebKit with a single API. You can use it to write **End-to-End (E2E)** and **Integration** tests across all platforms.
### Quickstart
The fastest way to get started, is to use `create-next-app` with the [with-playwright example](https://github.com/vercel/next.js/tree/canary/examples/with-playwright). This will create a Next.js project complete with Playwright all set up.
You can use `page.goto("/")` instead of `page.goto("http://localhost:3000/")`, if you add [`"baseURL": "http://localhost:3000"`](https://playwright.dev/docs/api/class-testoptions#test-options-base-url) to the `playwright.config.ts` configuration file.
### Running your Playwright tests
Since Playwright is testing a real Next.js application, it requires the Next.js server to be running prior to starting Playwright. It is recommend to run your tests against your production code to more closely resemble how your application will behave.
Run `npm run build` and `npm run start`, then run `npm run test:e2e` in another terminal window to run the Playwright tests.
> **Note:** Alternatively, you can use the [`webServer`](https://playwright.dev/docs/test-advanced#launching-a-development-web-server-during-the-tests) feature to let Playwright start the development server and wait until it's fully available.
### Running Playwright on Continuous Integration (CI)
Playwright will by default run your tests in the [headed mode](https://playwright.dev/docs/ci). To install all the Playwright dependencies, run `npx playwright install-deps`.
You can learn more about Playwright and Continuous Integration from these resources:
- [Getting started with Playwright](https://playwright.dev/docs/intro)
- [Use a development server](https://playwright.dev/docs/test-advanced#launching-a-development-web-server-during-the-tests)
- [Playwright on your CI provider](https://playwright.dev/docs/ci)
- [Use a development server](https://playwright.dev/docs/test-advanced#launching-a-development-web-server-during-the-tests)
You can use `create-next-app` with the [with-jest example](https://github.com/vercel/next.js/tree/canary/examples/with-jest) to quickly get started with Jest and React Testing Library:
To manually set up Jest and React Testing Library, install `jest` , `@testing-library/react`, `@testing-library/jest-dom` as well as some supporting packages:
```bash
npm install --save-dev jest babel-jest @testing-library/react @testing-library/jest-dom identity-obj-proxy react-test-renderer
```
**Configuring Jest**
Create a `jest.config.js` file in your project's root directory and add the following configuration options:
You can learn more about each option above in the [Jest docs](https://jestjs.io/docs/configuration).
**Handling stylesheets and image imports**
These files aren't useful in tests but importing them may cause errors, so we will need to mock them. Create the mock files we referenced in the configuration above - `fileMock.js` and `styleMock.js` - inside a `__mocks__` directory:
```json
// __mocks__/fileMock.js
(module.exports = "test-file-stub")
```
```json
// __mocks__/styleMock.js
module.exports = {};
```
For more information on handling static assets, please refer to the [Jest Docs](https://jestjs.io/docs/webpack#handling-static-assets).
**Extend Jest with custom matchers**
`@testing-library/jest-dom` includes a set of convenient [custom matchers](https://github.com/testing-library/jest-dom#custom-matchers) such as `.toBeInTheDocument()` making it easier to write tests. You can import the custom matchers for every test by adding the following option to the Jest configuration file:
```json
// jest.config.js
setupFilesAfterEnv: ['<rootDir>/jest.setup.js']
```
Then, inside `jest.setup.js`, add the following import:
```jsx
// jest.setup.js
import '@testing-library/jest-dom/extend-expect'
```
If you need to add more setup options before each test, it's common to add them to the `jest.setup.js` file above.
**Absolute Imports and Module Path Aliases**
If your project is using [Module Path Aliases](https://nextjs.org/docs/advanced-features/module-path-aliases), you will need to configure Jest to resolve the imports by matching the paths option in the `jsconfig.json` file with the `moduleNameMapper` option in the `jest.config.js` file. For example:
```json
// tsconfig.json or jsconfig.json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/components/*": ["components/*"]
}
}
}
```
```jsx
// jest.config.js
moduleNameMapper: {
'^@/components/(.*)$': '<rootDir>/components/$1',
}
```
**Add a test script to package.json**
Add the Jest executable in watch mode to the `package.json` scripts:
```jsx
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"test": "jest --watch"
}
```
`jest --watch` will re-run tests when a file is changed. For more Jest CLI options, please refer to the [Jest Docs](https://jestjs.io/docs/cli#reference).
**Create your first tests**
Your project is now ready to run tests. Follow Jests convention by adding tests to the `__tests__` folder in your project's root directory.
For example, we can add a test to check if the `<Index />` component successfully renders a heading:
> **Note**: The `@jest-environment jsdom` comment above configures the testing environment as `jsdom` inside the test file because React Testing Library uses DOM elements like `document.body` which will not work in Jest's default `node` testing environment. Alternatively, you can also set the `jsdom` environment globally by adding the Jest configuration option: `"testEnvironment": "jsdom"` in `jest.config.js`.
Run `npm run test` to run your test suite. After your tests pass or fail, you will notice a list of interactive Jest commands that will be helpful as you add more tests.