Tests

Exemples

Apprenez à configurer Next.js avec des outils de test couramment utilisés : Cypress, Playwright et Jest avec React Testing Library.

Cypress

Cypress est un exécuteur de tests utilisé pour les tests End-to-End (E2E) et les tests de composants.

Démarrage rapide

Vous pouvez utiliser create-next-app avec l'exemple with-cypress pour commencer rapidement.

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

Configuration manuelle

Pour commencer avec Cypress, installez le package cypress :

Terminal
npm install --save-dev cypress

Ajoutez Cypress au champ scripts du package.json :

package.json
{
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "cypress:open": "cypress open"
  }
}

Exécutez Cypress pour la première fois pour générer des exemples utilisant leur structure de dossiers recommandée :

Terminal
npm run cypress:open

Vous pouvez parcourir les exemples générés et la section Writing Your First Test de la documentation Cypress pour vous familiariser avec Cypress.

Dois-je utiliser des tests E2E ou des tests de composants ?

La documentation Cypress contient un guide sur la différence entre ces deux types de tests et quand il est approprié d'utiliser chacun.

Création de votre premier test E2E Cypress

Supposons les deux pages Next.js suivantes :

pages/index.js
import Link from 'next/link'

export default function Home() {
  return (
    <nav>
      <h1>Page d'accueil</h1>
      <Link href="/about">À propos</Link>
    </nav>
  )
}
pages/about.js
export default function About() {
  return (
    <div>
      <h1>Page À propos</h1>
      <Link href="/">Page d'accueil</Link>
    </div>
  )
}

Ajoutez un test pour vérifier que votre navigation fonctionne correctement :

cypress/e2e/app.cy.js
describe('Navigation', () => {
  it('should navigate to the about page', () => {
    // Commencez depuis la page d'index
    cy.visit('http://localhost:3000/')

    // Trouvez un lien avec un attribut href contenant "about" et cliquez dessus
    cy.get('a[href*="about"]').click()

    // La nouvelle URL devrait inclure "/about"
    cy.url().should('include', '/about')

    // La nouvelle page devrait contenir un h1 avec "About page"
    cy.get('h1').contains('About Page')
  })
})

Vous pouvez utiliser cy.visit("/") au lieu de cy.visit("http://localhost:3000/") si vous ajoutez baseUrl: 'http://localhost:3000' au fichier de configuration cypress.config.js.

Création de votre premier test de composant Cypress

Les tests de composants construisent et montent un composant spécifique sans avoir à bundler toute votre application ou à lancer un serveur. Cela permet des tests plus performants qui fournissent toujours un retour visuel et la même API utilisée pour les tests E2E Cypress.

Bon à savoir : Comme les tests de composants ne lancent pas un serveur Next.js, les fonctionnalités comme <Image /> et getServerSideProps qui dépendent d'un serveur disponible ne fonctionneront pas par défaut. Consultez la documentation Cypress Next.js pour des exemples de mise en œuvre de ces fonctionnalités dans les tests de composants.

Supposant les mêmes composants que dans la section précédente, ajoutez un test pour valider qu'un composant rend le résultat attendu :

pages/about.cy.js
import AboutPage from './about.js'

describe('<AboutPage />', () => {
  it('should render and display expected content', () => {
    // Montez le composant React pour la page À propos
    cy.mount(<AboutPage />)

    // La nouvelle page devrait contenir un h1 avec "About page"
    cy.get('h1').contains('About Page')

    // Validez qu'un lien avec l'URL attendue est présent
    // *Suivre* le lien est mieux adapté à un test E2E
    cy.get('a[href="/"]').should('be.visible')
  })
})

Exécution de vos tests Cypress

Tests E2E

Comme les tests E2E Cypress testent une véritable application Next.js, ils nécessitent que le serveur Next.js soit en cours d'exécution avant de démarrer Cypress. Nous recommandons d'exécuter vos tests contre votre code de production pour mieux ressembler au comportement de votre application.

Exécutez npm run build et npm run start, puis exécutez npm run cypress -- --e2e dans une autre fenêtre de terminal pour démarrer Cypress et exécuter votre suite de tests E2E.

Bon à savoir : Alternativement, vous pouvez installer le package start-server-and-test et l'ajouter au champ scripts du package.json : "test": "start-server-and-test start http://localhost:3000 cypress" pour démarrer le serveur de production Next.js conjointement avec Cypress. N'oubliez pas de reconstruire votre application après de nouveaux changements.

Tests de composants

Exécutez npm run cypress -- --component pour démarrer Cypress et exécuter votre suite de tests de composants.

Préparation pour l'intégration continue (CI)

Vous aurez remarqué que l'exécution de Cypress jusqu'à présent a ouvert un navigateur interactif, ce qui n'est pas idéal pour les environnements CI. Vous pouvez également exécuter Cypress en mode headless en utilisant la commande cypress run :

package.json
{
  "scripts": {
    //...
    "e2e": "start-server-and-test dev http://localhost:3000 \"cypress open --e2e\"",
    "e2e:headless": "start-server-and-test dev http://localhost:3000 \"cypress run --e2e\"",
    "component": "cypress open --component",
    "component:headless": "cypress run --component"
  }
}

Vous pouvez en apprendre plus sur Cypress et l'intégration continue à partir de ces ressources :

Playwright

Playwright est un framework de test qui vous permet d'automatiser Chromium, Firefox et WebKit avec une seule API. Vous pouvez l'utiliser pour écrire des tests End-to-End (E2E) et des tests d'intégration sur toutes les plateformes.

Démarrage rapide

Le moyen le plus rapide de commencer est d'utiliser create-next-app avec l'exemple with-playwright. Cela créera un projet Next.js complet avec Playwright déjà configuré.

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

Configuration manuelle

Vous pouvez également utiliser npm init playwright pour ajouter Playwright à un projet NPM existant.

Pour commencer manuellement avec Playwright, installez le package @playwright/test :

Terminal
npm install --save-dev @playwright/test

Ajoutez Playwright au champ scripts du package.json :

package.json
{
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "test:e2e": "playwright test"
  }
}

Création de votre premier test End-to-End Playwright

Supposant les deux pages Next.js suivantes :

pages/index.js
import Link from 'next/link'

export default function Home() {
  return (
    <nav>
      <Link href="/about">À propos</Link>
    </nav>
  )
}
pages/about.js
export default function About() {
  return (
    <div>
      <h1>Page À propos</h1>
    </div>
  )
}

Ajoutez un test pour vérifier que votre navigation fonctionne correctement :

import { test, expect } from '@playwright/test'

test('should navigate to the about page', async ({ page }) => {
  // Commencez depuis la page d'index (baseURL est défini via webServer dans playwright.config.ts)
  await page.goto('http://localhost:3000/')
  // Trouvez un élément avec le texte 'About Page' et cliquez dessus
  await page.click('text=About')
  // La nouvelle URL devrait être "/about" (baseURL est utilisé ici)
  await expect(page).toHaveURL('http://localhost:3000/about')
  // La nouvelle page devrait contenir un h1 avec "About Page"
  await expect(page.locator('h1')).toContainText('About Page')
})
import { test, expect } from '@playwright/test'

test('should navigate to the about page', async ({ page }) => {
  // Commencez depuis la page d'index (baseURL est défini via webServer dans playwright.config.ts)
  await page.goto('http://localhost:3000/')
  // Trouvez un élément avec le texte 'About Page' et cliquez dessus
  await page.click('text=About')
  // La nouvelle URL devrait être "/about" (baseURL est utilisé ici)
  await expect(page).toHaveURL('http://localhost:3000/about')
  // La nouvelle page devrait contenir un h1 avec "About Page"
  await expect(page.locator('h1')).toContainText('About Page')
})

Vous pouvez utiliser page.goto("/") au lieu de page.goto("http://localhost:3000/"), si vous ajoutez "baseURL": "http://localhost:3000" au fichier de configuration playwright.config.ts.

Exécution de vos tests Playwright

Comme Playwright teste une véritable application Next.js, il nécessite que le serveur Next.js soit en cours d'exécution avant de démarrer Playwright. Il est recommandé d'exécuter vos tests contre votre code de production pour mieux ressembler au comportement de votre application.

Exécutez npm run build et npm run start, puis exécutez npm run test:e2e dans une autre fenêtre de terminal pour exécuter les tests Playwright.

Bon à savoir : Alternativement, vous pouvez utiliser la fonctionnalité webServer pour laisser Playwright démarrer le serveur de développement et attendre qu'il soit complètement disponible.

Exécution de Playwright en intégration continue (CI)

Playwright exécutera par défaut vos tests en mode headless. Pour installer toutes les dépendances Playwright, exécutez npx playwright install-deps.

Vous pouvez en apprendre plus sur Playwright et l'intégration continue à partir de ces ressources :

Jest et React Testing Library

Jest et React Testing Library sont fréquemment utilisés ensemble pour les tests unitaires. Il existe trois façons de commencer à utiliser Jest dans votre application Next.js :

  1. En utilisant un de nos exemples de démarrage rapide
  2. Avec le compilateur Rust Next.js
  3. Avec Babel

Les sections suivantes expliqueront comment configurer Jest avec chacune de ces options :

Démarrage rapide

Vous pouvez utiliser create-next-app avec l'exemple with-jest pour commencer rapidement avec Jest et React Testing Library :

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

Configuration de Jest (avec le compilateur Rust)

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

Pour configurer Jest, installez jest, jest-environment-jsdom, @testing-library/react, @testing-library/jest-dom :

Terminal
npm install --save-dev jest jest-environment-jsdom @testing-library/react @testing-library/jest-dom

Créez un fichier jest.config.mjs à la racine de votre projet et ajoutez-y ce qui suit :

jest.config.mjs
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
/** @type {import('jest').Config} */
const config = {
  // Ajoutez plus d'options de configuration avant chaque exécution de test
  // setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],

  testEnvironment: 'jest-environment-jsdom',
}

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

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

  • La configuration de transform en utilisant SWC
  • Le mock automatique des feuilles de style (.css, .module.css, et leurs variantes scss), des imports d'images et de next/font
  • Le chargement de .env (et toutes ses variantes) dans process.env
  • L'ignorance de node_modules pour la résolution et les transformations des tests
  • L'ignorance de .next pour la résolution des tests
  • Le chargement de next.config.js pour les flags 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.js. Pour plus d'informations, consultez Variables d'environnement de test.

Configuration de Jest (avec Babel)

Si vous choisissez de ne pas utiliser le Compilateur Rust, vous devrez configurer Jest manuellement et installer babel-jest et identity-obj-proxy en plus des packages mentionnés précédemment.

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 correct
  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',
  },
  // 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 davantage sur chaque option de configuration dans la documentation de 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, il faut donc les simuler. 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 = {
  src: '/img.jpg',
  height: 24,
  width: 24,
  blurDataURL: 'data:image/png;base64,imagedata',
}
__mocks__/styleMock.js
module.exports = {}

Pour plus d'informations sur la gestion des ressources statiques, veuillez consulter la documentation de Jest.

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 :

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

Puis, dans jest.setup.js, ajoutez l'import suivant :

jest.setup.js
import '@testing-library/jest-dom'

extend-expect a été supprimé dans la 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, il est courant de les ajouter dans le fichier jest.setup.js ci-dessus.

Optionnel : Imports absolus et 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 ou jsconfig.json
{
  "compilerOptions": {
    "module": "esnext",
    "moduleResolution": "node",
    "baseUrl": "./",
    "paths": {
      "@/components/*": ["components/*"]
    }
  }
}
jest.config.js
moduleNameMapper: {
  '^@/components/(.*)$': '<rootDir>/components/$1',
}

Création de vos tests :

Ajouter un script de test à package.json

Ajoutez l'exécutable Jest en mode watch aux scripts du package.json :

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

jest --watch relancera les tests lorsqu'un fichier est modifié. Pour plus d'options CLI de Jest, veuillez consulter la documentation de Jest.

Créez vos premiers tests

Votre projet est maintenant prêt à exécuter des tests. Suivez la convention de Jest en ajoutant des tests dans le dossier __tests__ à la racine de votre projet.

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

__tests__/index.test.js
import { render, screen } from '@testing-library/react'
import Home from '../pages/index'
import '@testing-library/jest-dom'

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

    const heading = screen.getByRole('heading', {
      name: /welcome to next\.js!/i,
    })

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

Optionnellement, ajoutez un test de snapshot pour suivre les changements inattendus dans votre composant <Home /> :

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

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

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

Exécution de votre suite de tests

Exécutez npm run test pour lancer votre suite de tests. Après que vos tests passent ou échouent, vous verrez une liste de commandes interactives de Jest qui seront utiles lorsque vous ajouterez plus de tests.

Pour approfondir, ces ressources pourraient vous être utiles :

Packages et exemples de la communauté

La communauté Next.js a créé des packages et des articles qui pourraient vous être utiles :

Pour plus d'informations sur ce qu'il faut lire ensuite, nous recommandons :

  • pages/basic-features/environment-variables#test-environment-variables