Configuration de Jest avec Next.js

Jest et React Testing Library sont souvent utilisés ensemble pour les tests unitaires et les tests par instantané (snapshot). Ce guide vous montrera comment configurer Jest avec Next.js et écrire vos premiers tests.

Bon à savoir : Les composants serveur async étant nouveaux dans l'écosystème React, Jest ne les prend pas encore en charge. Bien que vous puissiez exécuter des tests unitaires pour les composants serveur et client synchrones, nous recommandons d'utiliser des tests E2E pour les composants async.

Démarrage rapide

Vous pouvez utiliser create-next-app avec l'exemple Next.js with-jest pour commencer rapidement :

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

Configuration manuelle

Depuis la sortie de Next.js 12, Next.js inclut désormais une configuration intégrée pour Jest.

Pour configurer Jest, installez jest et les packages suivants comme dépendances de développement :

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

Générez un fichier de configuration Jest de base en exécutant la commande suivante :

Terminal
npm init jest@latest
# ou
yarn create jest@latest
# ou
pnpm create jest@latest

Cela vous guidera à travers une série de questions pour configurer Jest pour votre projet, y compris la création automatique d'un fichier jest.config.ts|js.

Mettez à jour votre fichier de configuration pour utiliser next/jest. Ce transformateur inclut toutes les options de configuration nécessaires pour que Jest fonctionne avec Next.js :

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

const createJestConfig = nextJest({
  // Fournissez le chemin vers votre application Next.js pour charger next.config.js et les fichiers .env dans votre environnement de test
  dir: './',
})

// Ajoutez toute configuration personnalisée à passer à Jest
const config: Config = {
  coverageProvider: 'v8',
  testEnvironment: 'jsdom',
  // Ajoutez plus d'options de configuration avant chaque exécution de test
  // setupFilesAfterEnv: ['<rootDir>/jest.setup.ts'],
}

// createJestConfig est exporté de cette manière pour garantir que next/jest peut charger la configuration Next.js qui est asynchrone
export default createJestConfig(config)
const nextJest = require('next/jest')

/** @type {import('jest').Config} */
const createJestConfig = nextJest({
  // Fournissez le chemin vers votre application Next.js pour charger next.config.js et les fichiers .env dans votre environnement de test
  dir: './',
})

// Ajoutez toute configuration personnalisée à passer à Jest
const config = {
  coverageProvider: 'v8',
  testEnvironment: 'jsdom',
  // Ajoutez plus d'options de configuration avant chaque exécution de test
  // setupFilesAfterEnv: ['<rootDir>/jest.setup.ts'],
}

// createJestConfig est exporté de cette manière pour garantir que next/jest peut charger la configuration Next.js qui est asynchrone
module.exports = createJestConfig(config)

Sous le capot, next/jest configure automatiquement Jest pour vous, notamment :

  • Configuration de transform en utilisant le Next.js Compiler
  • Simulation automatique des feuilles de style (.css, .module.css, et leurs variantes scss), des imports d'images et de next/font
  • Chargement de .env (et toutes ses variantes) dans process.env
  • Exclusion de node_modules de la résolution et des transformations de test
  • Exclusion de .next de la résolution de test
  • Chargement de next.config.js pour les drapeaux activant les transformations SWC

Bon à savoir : Pour tester directement les variables d'environnement, chargez-les manuellement dans un script de configuration séparé ou dans votre fichier jest.config.ts. Pour plus d'informations, consultez Variables d'environnement de test.

Configuration de Jest (avec Babel)

Si vous optez pour ne pas utiliser le Next.js Compiler et préférez utiliser Babel, vous devrez configurer Jest manuellement et installer babel-jest et identity-obj-proxy en plus des packages mentionnés ci-dessus.

Voici les options recommandées pour configurer Jest avec Next.js :

jest.config.js
module.exports = {
  collectCoverage: true,
  // sur node 14.x, le fournisseur de couverture v8 offre une bonne vitesse et un rapport plus ou moins bon
  coverageProvider: 'v8',
  collectCoverageFrom: [
    '**/*.{js,jsx,ts,tsx}',
    '!**/*.d.ts',
    '!**/node_modules/**',
    '!<rootDir>/out/**',
    '!<rootDir>/.next/**',
    '!<rootDir>/*.config.js',
    '!<rootDir>/coverage/**',
  ],
  moduleNameMapper: {
    // Gérer les imports CSS (avec modules CSS)
    // https://jestjs.io/docs/webpack#mocking-css-modules
    '^.+\\.module\\.(css|sass|scss)$': 'identity-obj-proxy',

    // Gérer les imports CSS (sans modules CSS)
    '^.+\\.(css|sass|scss)$': '<rootDir>/__mocks__/styleMock.js',

    // Gérer les imports d'images
    // https://jestjs.io/docs/webpack#handling-static-assets
    '^.+\\.(png|jpg|jpeg|gif|webp|avif|ico|bmp|svg)$/i': `<rootDir>/__mocks__/fileMock.js`,

    // Gérer les alias de modules
    '^@/components/(.*)$': '<rootDir>/components/$1',

    // Gérer @next/font
    '@next/font/(.*)': `<rootDir>/__mocks__/nextFontMock.js`,
    // Gérer next/font
    'next/font/(.*)': `<rootDir>/__mocks__/nextFontMock.js`,
    // Désactiver server-only
    'server-only': `<rootDir>/__mocks__/empty.js`,
  },
  // Ajouter plus d'options de configuration avant chaque exécution de test
  // setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
  testPathIgnorePatterns: ['<rootDir>/node_modules/', '<rootDir>/.next/'],
  testEnvironment: 'jsdom',
  transform: {
    // Utiliser babel-jest pour transpiler les tests avec le preset 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)$',
  ],
}

Vous pouvez en apprendre plus sur chaque option de configuration dans la documentation Jest. Nous recommandons également de consulter la configuration de next/jest pour voir comment Next.js configure Jest.

Gestion des feuilles de style et des imports d'images

Les feuilles de style et les images ne sont pas utilisées dans les tests, mais leur importation peut causer des erreurs, donc elles doivent être simulées.

Créez les fichiers de simulation référencés dans la configuration ci-dessus - fileMock.js et styleMock.js - dans un répertoire __mocks__ :

__mocks__/fileMock.js
module.exports = 'test-file-stub'
__mocks__/styleMock.js
module.exports = {}

Pour plus d'informations sur la gestion des ressources statiques, consultez la documentation Jest.

Gestion des polices

Pour gérer les polices, créez le fichier nextFontMock.js dans le répertoire __mocks__, et ajoutez la configuration suivante :

__mocks__/nextFontMock.js
module.exports = new Proxy(
  {},
  {
    get: function getter() {
      return () => ({
        className: 'className',
        variable: 'variable',
        style: { fontFamily: 'fontFamily' },
      })
    },
  }
)

Optionnel : Gestion des imports absolus et des alias de modules

Si votre projet utilise des alias de modules, vous devrez configurer Jest pour résoudre les imports en faisant correspondre l'option paths dans le fichier jsconfig.json avec l'option moduleNameMapper dans le fichier jest.config.js. Par exemple :

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

Optionnel : Étendre Jest avec des matchers personnalisés

@testing-library/jest-dom inclut un ensemble de matchers personnalisés pratiques comme .toBeInTheDocument(), facilitant l'écriture des tests. Vous pouvez importer ces matchers pour chaque test en ajoutant l'option suivante au fichier de configuration Jest :

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

Ensuite, dans jest.setup.ts, ajoutez l'import suivante :

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

Bon à savoir : extend-expect a été supprimé dans v6.0, donc si vous utilisez @testing-library/jest-dom avant la version 6, vous devrez importer @testing-library/jest-dom/extend-expect à la place.

Si vous avez besoin d'ajouter plus d'options de configuration avant chaque test, vous pouvez les ajouter au fichier jest.setup.js ci-dessus.

Ajouter un script de test à package.json :

Enfin, ajoutez un script Jest test à votre fichier package.json :

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

jest --watch réexécutera les tests lorsqu'un fichier est modifié. Pour plus d'options CLI de Jest, consultez la documentation Jest.

Création de votre premier test :

Votre projet est maintenant prêt à exécuter des tests. Créez un répertoire appelé __tests__ à la racine de votre projet.

Par exemple, nous pouvons ajouter un test pour vérifier si le composant <Home /> affiche correctement un titre :

export default function Home() {
  return <h1>Home</h1>
}
__tests__/index.test.js
import '@testing-library/jest-dom'
import { render, screen } from '@testing-library/react'
import Home from '../pages/index'

describe('Home', () => {
  it('affiche un titre', () => {
    render(<Home />)

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

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

Optionnellement, ajoutez un test par instantané (snapshot) pour suivre les changements inattendus dans votre composant :

__tests__/snapshot.js
import { render } from '@testing-library/react'
import Home from '../pages/index'

it('affiche la page d'accueil sans changement', () => {
  const { container } = render(<Home />)
  expect(container).toMatchSnapshot()
})

Bon à savoir : Les fichiers de test ne doivent pas être inclus dans le Pages Router car tous les fichiers à l'intérieur sont considérés comme des routes.

Exécution de vos tests

Ensuite, exécutez la commande suivante pour lancer vos tests :

Terminal
npm run test
# ou
yarn test
# ou
pnpm test

Ressources supplémentaires

Pour approfondir, vous trouverez peut-être ces ressources utiles :