Настройка 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, чтобы быстро начать:
npx create-next-app@latest --example with-jest with-jest-app
Ручная настройка
Начиная с версии Next.js 12, Next.js включает встроенную конфигурацию для Jest.
Чтобы настроить Jest, установите jest
и следующие пакеты как dev-зависимости:
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, выполнив следующую команду:
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 (с Babel)
Если вы отказываетесь от Next.js Compiler и используете Babel, вам потребуется вручную настроить Jest и установить babel-jest
и identity-obj-proxy
в дополнение к указанным выше пакетам.
Рекомендуемые настройки для конфигурации Jest с Next.js:
module.exports = {
collectCoverage: true,
// на node 14.x coverage provider v8 обеспечивает хорошую скорость и более-менее качественный отчет
coverageProvider: 'v8',
collectCoverageFrom: [
'**/*.{js,jsx,ts,tsx}',
'!**/*.d.ts',
'!**/node_modules/**',
'!<rootDir>/out/**',
'!<rootDir>/.next/**',
'!<rootDir>/*.config.js',
'!<rootDir>/coverage/**',
],
moduleNameMapper: {
// Обработка импортов CSS (с CSS modules)
// https://jestjs.io/docs/webpack#mocking-css-modules
'^.+\\.module\\.(css|sass|scss)$': 'identity-obj-proxy',
// Обработка импортов CSS (без CSS modules)
'^.+\\.(css|sass|scss)$': '<rootDir>/__mocks__/styleMock.js',
// Обработка импортов изображений
// https://jestjs.io/docs/webpack#handling-static-assets
'^.+\\.(png|jpg|jpeg|gif|webp|avif|ico|bmp|svg)$/i': `<rootDir>/__mocks__/fileMock.js`,
// Обработка алиасов модулей
'^@/components/(.*)$': '<rootDir>/components/$1',
// Обработка @next/font
'@next/font/(.*)': `<rootDir>/__mocks__/nextFontMock.js`,
// Обработка next/font
'next/font/(.*)': `<rootDir>/__mocks__/nextFontMock.js`,
// Отключение server-only
'server-only': `<rootDir>/__mocks__/empty.js`,
},
// Добавьте дополнительные настройки перед запуском каждого теста
// setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
testPathIgnorePatterns: ['<rootDir>/node_modules/', '<rootDir>/.next/'],
testEnvironment: 'jsdom',
transform: {
// Используйте babel-jest для транспиляции тестов с пресетом next/babel
// https://jestjs.io/docs/configuration#transform-objectstring-pathtotransformer--pathtotransformer-object
'^.+\\.(js|jsx|ts|tsx)$': ['babel-jest', { presets: ['next/babel'] }],
},
transformIgnorePatterns: [
'/node_modules/',
'^.+\\.module\\.(css|sass|scss)$',
],
}
Вы можете узнать больше о каждой настройке в документации Jest. Также рекомендуем изучить конфигурацию next/jest
, чтобы понять, как Next.js настраивает Jest.
Обработка таблиц стилей и импортов изображений
Таблицы стилей и изображения не используются в тестах, но их импорт может вызвать ошибки, поэтому их нужно замокировать.
Создайте файлы-моки, указанные в конфигурации выше - fileMock.js
и styleMock.js
- внутри директории __mocks__
:
module.exports = 'test-file-stub'
module.exports = {}
Подробнее об обработке статических ресурсов см. в документации Jest.
Обработка шрифтов
Для обработки шрифтов создайте файл nextFontMock.js
внутри директории __mocks__
и добавьте следующую конфигурацию:
module.exports = new Proxy(
{},
{
get: function getter() {
return () => ({
className: 'className',
variable: 'variable',
style: { fontFamily: 'fontFamily' },
})
},
}
)
Опционально: Обработка абсолютных импортов и алиасов модулей
Если ваш проект использует алиасы модулей, вам нужно настроить Jest для разрешения импортов, сопоставив параметр paths в файле jsconfig.json
с параметром moduleNameMapper
в файле jest.config.js
. Например:
{
"compilerOptions": {
"module": "esnext",
"moduleResolution": "bundler",
"baseUrl": "./",
"paths": {
"@/components/*": ["components/*"]
}
}
}
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
:
{
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"test": "jest",
"test:watch": "jest --watch"
}
}
jest --watch
будет перезапускать тесты при изменении файла. Дополнительные опции CLI Jest см. в документации Jest.
Создание первого теста:
Теперь ваш проект готов к запуску тестов. Создайте папку __tests__
в корневой директории проекта.
Например, мы можем добавить тест для проверки, успешно ли рендерится заголовок в компоненте <Home />
:
export default function Home() {
return <h1>Home</h1>
}
import '@testing-library/jest-dom'
import { render, screen } from '@testing-library/react'
import Home from '../pages/index'
describe('Home', () => {
it('renders a heading', () => {
render(<Home />)
const heading = screen.getByRole('heading', { level: 1 })
expect(heading).toBeInTheDocument()
})
})
Опционально добавьте тест снимков (snapshot test) для отслеживания неожиданных изменений в вашем компоненте:
import { render } from '@testing-library/react'
import Home from '../pages/index'
it('renders homepage unchanged', () => {
const { container } = render(<Home />)
expect(container).toMatchSnapshot()
})
Полезно знать: Тестовые файлы не должны находиться внутри Pages Router, так как любые файлы внутри Pages Router считаются маршрутами.
Запуск тестов
Затем выполните следующую команду для запуска тестов:
npm run test
# или
yarn test
# или
pnpm test
Дополнительные ресурсы
Для дальнейшего изучения могут быть полезны следующие ресурсы:
- Пример Next.js с Jest
- Документация Jest
- Документация React Testing Library
- Testing Playground - используйте лучшие практики тестирования для сопоставления элементов.