Skip to content

Commit

Permalink
Docs: Add App Router Testing Guides and update /examples (#59268)
Browse files Browse the repository at this point in the history
This PR updates the testing guides to use App Router and TypeScript,
also updates `/examples` to show `app` and `pages` examples.

## Overview

- [x] Create a new "Testing" section that is shared between `app` and
`pages`.
- [x] Explain the differences between E2E, unit testing, component
testing, etc.
- [x] Recommend E2E for `async` components as currently none of the
tools support it.
- [x] Update setup guides for **Cypress**, **Playwright**, and **Jest**
with latest config options, and examples for `app` and `pages`.
- [x] Add new guide for **Vitest**
- [x] Clean up `/examples`: use TS, show `app` and `pages` examples,
match docs config

## Cypress

- [x] E2E Tests
- [x] Component Testing
  - [x] Client Components
  - [x] Server Components
  - [ ] `async` components

**Blockers:** 
- TS: `Option 'bundler' can only be used when 'module' is set to
'es2015' or later`. In **tsconfig.json** compilerOptions, Next.js uses
"moduleResolution": "bundler", changing it to "node" fixes the issue but
it can have repercussions.
  - cypress-io/cypress#27731 
- Version 14 is currently not supported for component testing
  - cypress-io/cypress#28185

## Playwright

- [x] E2E Tests

## Jest

- [x] Unit Testing
   - [x] Client Components
   - [x] Server Components
- [ ] `async` components:
testing-library/react-testing-library#1209
   - [x]  'server-only': #54891
- [x] Snapshot Testing

**Blockers:**
- TS: testing-library/jest-dom#546
- None of the solutions in the issue work with Next.js v14.0.4 and TS v5

## Vitest 

- [x] Unit Testing
  - [x] Client Components
  - [x] Server Components
  - [ ] `async` components
  - [x] 'server-only'
 - [x] Update vitest example
- [x] Handles CSS, and CSS modules imports
- [x] Handles next/image

## Other

- #47448
- #47299
  • Loading branch information
delbaoliveira committed Dec 13, 2023
1 parent 32759b4 commit 0ddc7e8
Show file tree
Hide file tree
Showing 81 changed files with 1,279 additions and 639 deletions.
202 changes: 202 additions & 0 deletions docs/02-app/01-building-your-application/08-testing/01-vitest.mdx
@@ -0,0 +1,202 @@
---
title: Setting up Vitest with Next.js
nav: Vitest
description: Learn how to set up Vitest with Next.js for Unit Testing.
---

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.

> **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.
## Quickstart

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:

```bash filename="Terminal"
npx create-next-app@latest --example with-vitest with-jest-vitest
```

## Manual Setup

To manually set up Vitest, install `vitest` and the following packages as dev dependencies:

```bash filename="Terminal"
npm install -D vitest @vitejs/plugin-react jsdom @testing-library/react
# or
yarn add -D vitest @vitejs/plugin-react jsdom @testing-library/react @vitejs/plugin-react
# or
pnpm install -D vitest @vitejs/plugin-react jsdom @testing-library/react
```

Create a `vitest.config.ts|js` file in the root of your project, and add the following options:

```ts filename="vitest.config.ts" switcher
import { defineConfig } from 'vitest/config'
import react from '@vitejs/plugin-react'

export default defineConfig({
plugins: [react()],
test: {
environment: 'jsdom',
},
})
```

```js filename="vitest.config.js" switcher
import { defineConfig } from 'vitest/config'
import react from '@vitejs/plugin-react'

export default defineConfig({
plugins: [react()],
test: {
environment: 'jsdom',
},
})
```

For more information on configuring Vitest, please refer to the [Vitest Cofiguration](https://vitest.dev/config/#configuration) docs.

Then, add a `test` script to your `package.json`:

```json filename="package.json"
{
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"test": "vitest"
}
}
```

When you run `npm run test`, Vitest will **watch** for changes in your project by default.

## Creating your first Vitest Unit Test

Check that everything is working by creating a test to check if the `<Page />` component successfully renders a heading:

<AppOnly>

```tsx filename="app/page.tsx" switcher
import Link from 'next/link'

export default function Page() {
return (
<div>
<h1>Home</h1>
<Link href="/about">About</Link>
</div>
)
}
```

```jsx filename="app/page.js" switcher
import Link from 'next/link'

export default function Page() {
return (
<div>
<h1>Home</h1>
<Link href="/about">About</Link>
</div>
)
}
```

```tsx filename="__tests__/page.test.tsx" switcher
import { expect, test } from 'vitest'
import { render, screen } from '@testing-library/react'
import Page from '../app/page'

test('Page', () => {
render(<Page />)
expect(screen.getByRole('heading', { level: 1, name: 'Home' })).toBeDefined()
})
```

```jsx filename="__tests__/page.test.jsx" switcher
import { expect, test } from 'vitest'
import { render, screen } from '@testing-library/react'
import Page from '../app/page'

test('Page', () => {
render(<Page />)
expect(screen.getByRole('heading', { level: 1, name: 'Home' })).toBeDefined()
})
```

> **Good to know**: The example above uses the common `__tests__` convention, but test files can also be colocated inside the `app` router.
</AppOnly>

<PagesOnly>

```tsx filename="pages/index.tsx" switcher
import Link from 'next/link'

export default function Page() {
return (
<div>
<h1>Home</h1>
<Link href="/about">About</Link>
</div>
)
}
```

```jsx filename="pages/index.jsx" switcher
import Link from 'next/link'

export default function Page() {
return (
<div>
<h1>Home</h1>
<Link href="/about">About</Link>
</div>
)
}
```

```tsx filename="__tests__/index.test.tsx" switcher
import { expect, test } from 'vitest'
import { render, screen } from '@testing-library/react'
import Page from '../pages/index'

test('Page', () => {
render(<Page />)
expect(screen.getByRole('heading', { level: 1, name: 'Home' })).toBeDefined()
})
```

```jsx filename="__tests__/index.test.jsx" switcher
import { expect, test } from 'vitest'
import { render, screen } from '@testing-library/react'
import Page from '../pages/index'

test('Page', () => {
render(<Page />)
expect(screen.getByRole('heading', { level: 1, name: 'Home' })).toBeDefined()
})
```

</PagesOnly>

## Running your tests

Then, run the following command to run your tests:

```bash filename="Terminal"
npm run test
# or
yarn test
# or
pnpm test
```

## Additional Resources

You may find these resources helpful:

- [Next.js with Vitest example](https://github.com/vercel/next.js/tree/canary/examples/with-vitest)
- [Vitest Docs](https://vitest.dev/guide/)
- [React Testing Library Docs](https://testing-library.com/docs/react-testing-library/intro/)

0 comments on commit 0ddc7e8

Please sign in to comment.