|
| 1 | +--- |
| 2 | +title: Setting up Vitest with Next.js |
| 3 | +nav: Vitest |
| 4 | +description: Learn how to set up Vitest with Next.js for Unit Testing. |
| 5 | +--- |
| 6 | + |
| 7 | +Vite and React Testing Library are frequently used together for **Unit Testing**. This guide will show you how to setup Vitest with Next.js and write your first tests. |
| 8 | + |
| 9 | +> **Good to know:** Since `async` Server Components are new to the React ecosystem, Vitest currently does not support them. While you can still run **unit tests** for synchronous Server and Client Components, we recommend using an **E2E tests** for `async` components. |
| 10 | +
|
| 11 | +## Quickstart |
| 12 | + |
| 13 | +You can use `create-next-app` with the Next.js [with-vitest](https://github.com/vercel/next.js/tree/canary/examples/with-jest) example to quickly get started: |
| 14 | + |
| 15 | +```bash filename="Terminal" |
| 16 | +npx create-next-app@latest --example with-vitest with-jest-vitest |
| 17 | +``` |
| 18 | + |
| 19 | +## Manual Setup |
| 20 | + |
| 21 | +To manually set up Vitest, install `vitest` and the following packages as dev dependencies: |
| 22 | + |
| 23 | +```bash filename="Terminal" |
| 24 | +npm install -D vitest @vitejs/plugin-react jsdom @testing-library/react |
| 25 | +# or |
| 26 | +yarn add -D vitest @vitejs/plugin-react jsdom @testing-library/react @vitejs/plugin-react |
| 27 | +# or |
| 28 | +pnpm install -D vitest @vitejs/plugin-react jsdom @testing-library/react |
| 29 | +``` |
| 30 | + |
| 31 | +Create a `vitest.config.ts|js` file in the root of your project, and add the following options: |
| 32 | + |
| 33 | +```ts filename="vitest.config.ts" switcher |
| 34 | +import { defineConfig } from 'vitest/config' |
| 35 | +import react from '@vitejs/plugin-react' |
| 36 | + |
| 37 | +export default defineConfig({ |
| 38 | + plugins: [react()], |
| 39 | + test: { |
| 40 | + environment: 'jsdom', |
| 41 | + }, |
| 42 | +}) |
| 43 | +``` |
| 44 | + |
| 45 | +```js filename="vitest.config.js" switcher |
| 46 | +import { defineConfig } from 'vitest/config' |
| 47 | +import react from '@vitejs/plugin-react' |
| 48 | + |
| 49 | +export default defineConfig({ |
| 50 | + plugins: [react()], |
| 51 | + test: { |
| 52 | + environment: 'jsdom', |
| 53 | + }, |
| 54 | +}) |
| 55 | +``` |
| 56 | + |
| 57 | +For more information on configuring Vitest, please refer to the [Vitest Cofiguration](https://vitest.dev/config/#configuration) docs. |
| 58 | + |
| 59 | +Then, add a `test` script to your `package.json`: |
| 60 | + |
| 61 | +```json filename="package.json" |
| 62 | +{ |
| 63 | + "scripts": { |
| 64 | + "dev": "next dev", |
| 65 | + "build": "next build", |
| 66 | + "start": "next start", |
| 67 | + "test": "vitest" |
| 68 | + } |
| 69 | +} |
| 70 | +``` |
| 71 | + |
| 72 | +When you run `npm run test`, Vitest will **watch** for changes in your project by default. |
| 73 | + |
| 74 | +## Creating your first Vitest Unit Test |
| 75 | + |
| 76 | +Check that everything is working by creating a test to check if the `<Page />` component successfully renders a heading: |
| 77 | + |
| 78 | +<AppOnly> |
| 79 | + |
| 80 | +```tsx filename="app/page.tsx" switcher |
| 81 | +import Link from 'next/link' |
| 82 | + |
| 83 | +export default function Page() { |
| 84 | + return ( |
| 85 | + <div> |
| 86 | + <h1>Home</h1> |
| 87 | + <Link href="/about">About</Link> |
| 88 | + </div> |
| 89 | + ) |
| 90 | +} |
| 91 | +``` |
| 92 | + |
| 93 | +```jsx filename="app/page.js" switcher |
| 94 | +import Link from 'next/link' |
| 95 | + |
| 96 | +export default function Page() { |
| 97 | + return ( |
| 98 | + <div> |
| 99 | + <h1>Home</h1> |
| 100 | + <Link href="/about">About</Link> |
| 101 | + </div> |
| 102 | + ) |
| 103 | +} |
| 104 | +``` |
| 105 | + |
| 106 | +```tsx filename="__tests__/page.test.tsx" switcher |
| 107 | +import { expect, test } from 'vitest' |
| 108 | +import { render, screen } from '@testing-library/react' |
| 109 | +import Page from '../app/page' |
| 110 | + |
| 111 | +test('Page', () => { |
| 112 | + render(<Page />) |
| 113 | + expect(screen.getByRole('heading', { level: 1, name: 'Home' })).toBeDefined() |
| 114 | +}) |
| 115 | +``` |
| 116 | + |
| 117 | +```jsx filename="__tests__/page.test.jsx" switcher |
| 118 | +import { expect, test } from 'vitest' |
| 119 | +import { render, screen } from '@testing-library/react' |
| 120 | +import Page from '../app/page' |
| 121 | + |
| 122 | +test('Page', () => { |
| 123 | + render(<Page />) |
| 124 | + expect(screen.getByRole('heading', { level: 1, name: 'Home' })).toBeDefined() |
| 125 | +}) |
| 126 | +``` |
| 127 | + |
| 128 | +> **Good to know**: The example above uses the common `__tests__` convention, but test files can also be colocated inside the `app` router. |
| 129 | +
|
| 130 | +</AppOnly> |
| 131 | + |
| 132 | +<PagesOnly> |
| 133 | + |
| 134 | +```tsx filename="pages/index.tsx" switcher |
| 135 | +import Link from 'next/link' |
| 136 | + |
| 137 | +export default function Page() { |
| 138 | + return ( |
| 139 | + <div> |
| 140 | + <h1>Home</h1> |
| 141 | + <Link href="/about">About</Link> |
| 142 | + </div> |
| 143 | + ) |
| 144 | +} |
| 145 | +``` |
| 146 | + |
| 147 | +```jsx filename="pages/index.jsx" switcher |
| 148 | +import Link from 'next/link' |
| 149 | + |
| 150 | +export default function Page() { |
| 151 | + return ( |
| 152 | + <div> |
| 153 | + <h1>Home</h1> |
| 154 | + <Link href="/about">About</Link> |
| 155 | + </div> |
| 156 | + ) |
| 157 | +} |
| 158 | +``` |
| 159 | + |
| 160 | +```tsx filename="__tests__/index.test.tsx" switcher |
| 161 | +import { expect, test } from 'vitest' |
| 162 | +import { render, screen } from '@testing-library/react' |
| 163 | +import Page from '../pages/index' |
| 164 | + |
| 165 | +test('Page', () => { |
| 166 | + render(<Page />) |
| 167 | + expect(screen.getByRole('heading', { level: 1, name: 'Home' })).toBeDefined() |
| 168 | +}) |
| 169 | +``` |
| 170 | + |
| 171 | +```jsx filename="__tests__/index.test.jsx" switcher |
| 172 | +import { expect, test } from 'vitest' |
| 173 | +import { render, screen } from '@testing-library/react' |
| 174 | +import Page from '../pages/index' |
| 175 | + |
| 176 | +test('Page', () => { |
| 177 | + render(<Page />) |
| 178 | + expect(screen.getByRole('heading', { level: 1, name: 'Home' })).toBeDefined() |
| 179 | +}) |
| 180 | +``` |
| 181 | + |
| 182 | +</PagesOnly> |
| 183 | + |
| 184 | +## Running your tests |
| 185 | + |
| 186 | +Then, run the following command to run your tests: |
| 187 | + |
| 188 | +```bash filename="Terminal" |
| 189 | +npm run test |
| 190 | +# or |
| 191 | +yarn test |
| 192 | +# or |
| 193 | +pnpm test |
| 194 | +``` |
| 195 | + |
| 196 | +## Additional Resources |
| 197 | + |
| 198 | +You may find these resources helpful: |
| 199 | + |
| 200 | +- [Next.js with Vitest example](https://github.com/vercel/next.js/tree/canary/examples/with-vitest) |
| 201 | +- [Vitest Docs](https://vitest.dev/guide/) |
| 202 | +- [React Testing Library Docs](https://testing-library.com/docs/react-testing-library/intro/) |
0 commit comments