Настройка Jest с Next.js

Jest и React Testing Library часто используются вместе для модульного тестирования (Unit Testing) и тестирования снимков (Snapshot Testing). Это руководство покажет, как настроить Jest с Next.js и написать первые тесты.

Полезно знать: Поскольку async Server Components являются новинкой в экосистеме React, Jest пока их не поддерживает. Хотя вы можете запускать модульные тесты для синхронных Server и Client Components, мы рекомендуем использовать E2E-тесты для async компонентов.

Быстрый старт

Вы можете использовать create-next-app с примером Next.js with-jest, чтобы быстро начать:

Terminal
npx create-next-app@latest --example with-jest with-jest-app

Ручная настройка

Начиная с версии Next.js 12, Next.js включает встроенную конфигурацию для Jest.

Чтобы настроить Jest, установите jest и следующие пакеты как dev-зависимости:

Terminal
npm install -D jest jest-environment-jsdom @testing-library/react @testing-library/jest-dom
# или
yarn add -D jest jest-environment-jsdom @testing-library/react @testing-library/jest-dom
# или
pnpm install -D jest jest-environment-jsdom @testing-library/react @testing-library/jest-dom

Создайте базовый файл конфигурации Jest, выполнив следующую команду:

Terminal
npm init jest@latest
# или
yarn create jest@latest
# или
pnpm create jest@latest

Это запустит серию подсказок для настройки Jest в вашем проекте, включая автоматическое создание файла jest.config.ts|js.

Обновите конфигурационный файл, чтобы использовать next/jest. Этот трансформер содержит все необходимые настройки для работы Jest с Next.js:

import type { Config } from 'jest'
import nextJest from 'next/jest.js'

const createJestConfig = nextJest({
  // Укажите путь к вашему приложению Next.js для загрузки next.config.js и .env файлов в тестовой среде
  dir: './',
})

// Добавьте любые пользовательские настройки для Jest
const config: Config = {
  coverageProvider: 'v8',
  testEnvironment: 'jsdom',
  // Добавьте дополнительные настройки перед запуском каждого теста
  // setupFilesAfterEnv: ['<rootDir>/jest.setup.ts'],
}

// createJestConfig экспортируется таким образом, чтобы next/jest мог загрузить асинхронную конфигурацию Next.js
export default createJestConfig(config)
const nextJest = require('next/jest')

/** @type {import('jest').Config} */
const createJestConfig = nextJest({
  // Укажите путь к вашему приложению Next.js для загрузки next.config.js и .env файлов в тестовой среде
  dir: './',
})

// Добавьте любые пользовательские настройки для Jest
const config = {
  coverageProvider: 'v8',
  testEnvironment: 'jsdom',
  // Добавьте дополнительные настройки перед запуском каждого теста
  // setupFilesAfterEnv: ['<rootDir>/jest.setup.ts'],
}

// createJestConfig экспортируется таким образом, чтобы next/jest мог загрузить асинхронную конфигурацию Next.js
module.exports = createJestConfig(config)

Под капотом next/jest автоматически настраивает Jest для вас, включая:

  • Настройку transform с использованием Next.js Compiler
  • Автоматическое мокирование таблиц стилей (.css, .module.css и их scss-вариантов), импортов изображений и next/font
  • Загрузку .env (и всех вариантов) в process.env
  • Игнорирование node_modules при разрешении зависимостей и трансформациях
  • Игнорирование .next при разрешении зависимостей
  • Загрузку next.config.js для флагов, включающих SWC-трансформации

Полезно знать: Для тестирования переменных окружения напрямую загружайте их вручную в отдельном скрипте настройки или в файле jest.config.ts. Подробнее см. Test Environment Variables.

Опционально: Обработка абсолютных импортов и алиасов модулей

Если ваш проект использует алиасы модулей, вам нужно настроить Jest для разрешения импортов, сопоставив параметр paths в файле jsconfig.json с параметром moduleNameMapper в файле jest.config.js. Например:

tsconfig.json или jsconfig.json
{
  "compilerOptions": {
    "module": "esnext",
    "moduleResolution": "bundler",
    "baseUrl": "./",
    "paths": {
      "@/components/*": ["components/*"]
    }
  }
}
jest.config.js
moduleNameMapper: {
  // ...
  '^@/components/(.*)$': '<rootDir>/components/$1',
}

Опционально: Расширение Jest пользовательскими матчерами

@testing-library/jest-dom включает набор удобных пользовательских матчеров, таких как .toBeInTheDocument(), что упрощает написание тестов. Вы можете импортировать пользовательские матчеры для каждого теста, добавив следующую настройку в конфигурационный файл Jest:

setupFilesAfterEnv: ['<rootDir>/jest.setup.ts']
setupFilesAfterEnv: ['<rootDir>/jest.setup.js']

Затем внутри jest.setup.ts добавьте следующий импорт:

import '@testing-library/jest-dom'
import '@testing-library/jest-dom'

Полезно знать:extend-expect был удален в v6.0, поэтому если вы используете @testing-library/jest-dom версии ниже 6, вам нужно импортировать @testing-library/jest-dom/extend-expect вместо этого.

Если вам нужно добавить дополнительные настройки перед каждым тестом, вы можете добавить их в файл jest.setup.js выше.

Добавление тестового скрипта в package.json:

Наконец, добавьте Jest-скрипт test в ваш файл package.json:

package.json
{
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "test": "jest",
    "test:watch": "jest --watch"
  }
}

jest --watch будет перезапускать тесты при изменении файла. Дополнительные опции CLI Jest см. в документации Jest.

Создание первого теста:

Теперь ваш проект готов к запуску тестов. Создайте папку __tests__ в корневой директории проекта.

Например, мы можем добавить тест для проверки, успешно ли рендерится заголовок в компоненте <Page />:

import Link from 'next/link'

export default function Home() {
  return (
    <div>
      <h1>Home</h1>
      <Link href="/about">About</Link>
    </div>
  )
}
__tests__/page.test.jsx
import '@testing-library/jest-dom'
import { render, screen } from '@testing-library/react'
import Page from '../app/page'

describe('Page', () => {
  it('renders a heading', () => {
    render(<Page />)

    const heading = screen.getByRole('heading', { level: 1 })

    expect(heading).toBeInTheDocument()
  })
})

Опционально добавьте тест снимков (snapshot test) для отслеживания неожиданных изменений в вашем компоненте:

__tests__/snapshot.js
import { render } from '@testing-library/react'
import Page from '../app/page'

it('renders homepage unchanged', () => {
  const { container } = render(<Page />)
  expect(container).toMatchSnapshot()
})

Запуск тестов

Затем выполните следующую команду для запуска тестов:

Terminal
npm run test
# или
yarn test
# или
pnpm test

Дополнительные ресурсы

Для дальнейшего изучения могут быть полезны следующие ресурсы: