Ajouter des tests Vitest dans une application Next.js
28/04/2025 • Melvynx
Comment ajouter des tests Vitest
dans une application Next.js
? Vitest
va te permettre de venir créer des tests unitaires pour s'assurer que tes composants React ou même tes méthodes sont correctes.
Première étape dans ton projet c'est d'installer les dépendances nécessaires :
# Avec npm
npm install -D vitest @vitejs/plugin-react jsdom @testing-library/react @testing-library/dom vite-tsconfig-paths
# Avec pnpm
pnpm add -D vitest @vitejs/plugin-react jsdom @testing-library/react @testing-library/dom vite-tsconfig-paths
Chaque package a un rôle spécifique :
vitest
: Le framework de test principal@vitejs/plugin-react
: Pour le support de Reactjsdom
: Un environnement qui simule le navigateur pour les tests@testing-library/react
et @testing-library/dom
: Pour tester les composants Reactvite-tsconfig-paths
: Pour supporter les alias de path de ton tsconfigAprès avoir installé ces packages, crée un fichier de configuration vitest.config.mts
(ou .js
si tu n'utilises pas TypeScript) à la racine de ton projet :
import { defineConfig } from 'vitest/config'
import react from '@vitejs/plugin-react'
import tsconfigPaths from 'vite-tsconfig-paths'
export default defineConfig({
plugins: [tsconfigPaths(), react()],
test: {
environment: 'jsdom',
},
})
Cette configuration indique à Vitest d'utiliser l'environnement JSDOM pour simuler un navigateur et active les plugins React et les chemins de ton tsconfig.
Maintenant, ajoutons un script pour exécuter nos tests dans le fichier package.json
:
{
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"test": "vitest",
"test:ci": "vitest run"
}
}
Le script test
lancera Vitest en mode watch (il guettera les changements dans tes fichiers), tandis que test:ci
exécutera les tests une seule fois, idéal pour l'intégration continue.
Pour obtenir des assertions DOM plus riches comme toBeInTheDocument()
, tu peux installer le package @testing-library/jest-dom
et créer un fichier de configuration supplémentaire :
npm install -D @testing-library/jest-dom
Crée un fichier test/vitest.setup.ts
:
import '@testing-library/jest-dom/vitest'
import { cleanup } from '@testing-library/react'
import { afterEach } from 'vitest'
// Nettoie automatiquement après chaque test
afterEach(() => {
cleanup()
})
Ensuite, mets à jour la configuration Vitest pour utiliser ce fichier :
// vitest.config.mts
export default defineConfig({
plugins: [tsconfigPaths(), react()],
test: {
environment: 'jsdom',
setupFiles: './test/vitest.setup.ts',
},
})
Créons un test simple pour vérifier qu'un composant Page affiche correctement un titre. Imaginons que tu as un composant page dans ton app Next.js :
// app/page.tsx
import Link from 'next/link'
export default function Page() {
return (
<div>
<h1>Accueil</h1>
<Link href="/about">À propos</Link>
</div>
)
}
Créons un dossier __tests__
à la racine du projet et ajoutons un fichier page.test.tsx
:
// __tests__/page.test.tsx
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: 'Accueil' })).toBeDefined()
})
Ce test va rendre le composant Page
et vérifier qu'il contient un titre de niveau 1 avec le texte "Accueil".
Voyons maintenant comment tester un composant plus complexe, comme un bouton de déconnexion qui interagit avec un service d'authentification :
// components/logout.tsx
import { authClient } from "@/lib/auth-client"
export const LogoutButton = () => {
return (
<button onClick={() => authClient.signOut()}>
Logout
</button>
)
}
Pour tester ce composant, nous allons devoir mocker le client d'authentification :
// __tests__/logout.test.tsx
import { LogoutButton } from "@/components/logout"
import { authClient } from "@/lib/auth-client"
import { fireEvent, render, screen } from "@testing-library/react"
import { beforeAll, describe, expect, it, vi } from "vitest"
beforeAll(() => {
vi.mock("@/lib/auth-client", () => ({
authClient: {
signOut: vi.fn(),
},
}))
})
describe("LogoutButton", () => {
it("should renders logout button correctly", () => {
render(<LogoutButton />)
expect(screen.getByRole("button", { name: "Logout" })).toBeDefined()
})
it("should call signOut when clicked", () => {
render(<LogoutButton />)
const button = screen.getByRole("button", { name: "Logout" })
fireEvent.click(button)
expect(authClient.signOut).toHaveBeenCalled()
})
})
Ici, nous avons :
signOut
signOut
est appelée quand on clique sur le boutonPour les composants qui font des requêtes API ou ont un comportement asynchrone, nous pouvons utiliser waitFor
ou act
pour gérer les mises à jour asynchrones.
Prenons l'exemple d'un composant de zone de dépôt de fichiers :
// __tests__/upload-dropzone.test.tsx
import { UploadDropzone } from "@/components/upload-dropzone"
import { fireEvent, render, screen, waitFor } from "@testing-library/react"
import { describe, expect, it, vi } from "vitest"
describe("UploadDropzone", () => {
it("should handle file drop correctly", async () => {
const mockUploadFile = vi.fn()
const mockOnClientUploadComplete = vi.fn()
render(
<UploadDropzone
uploadFile={mockUploadFile}
onClientUploadComplete={mockOnClientUploadComplete}
/>
)
const dropzone = screen
.getByText("Drag and drop or click to upload a file")
.closest("div")
const file = new File(["file contents"], "test.pdf", {
type: "application/pdf",
})
if (dropzone) {
// Simuler des événements de drag
fireEvent.dragOver(dropzone)
expect(screen.getByText("Drop the file here")).toBeDefined()
// Créer un objet DataTransfer mock
const dataTransfer = {
files: [file],
}
fireEvent.drop(dropzone, { dataTransfer })
await waitFor(() => {
expect(mockUploadFile).toHaveBeenCalledWith(file)
expect(mockOnClientUploadComplete).toHaveBeenCalled()
})
}
})
})
Dans ce test, nous :
uploadFile
et onClientUploadComplete
UploadDropzone
Pour automatiser l'exécution des tests dans un pipeline CI/CD, tu peux ajouter un workflow comme celui-ci dans ton fichier .github/workflows/code-quality.yml
:
vitest:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [22.x]
steps:
- uses: pnpm/action-setup@v2
with:
version: 8
- uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
- name: Install
run: pnpm install
env:
CI: true
- name: Run TypeScript check
run: pnpm vitest:ci
env:
CI: true
Ce workflow exécutera tes tests Vitest dans l'environnement CI à chaque push ou pull request.
Vitest est un excellent choix pour tester tes applications Next.js. Avec sa syntaxe familière et sa rapidité d'exécution, il rend le processus de test beaucoup plus agréable. En combinaison avec React Testing Library, tu peux écrire des tests robustes qui vérifient le comportement de tes composants du point de vue de l'utilisateur.
Voici ce que nous avons appris :
Maintenant que tu as toutes les bases, tu peux commencer à tester ta propre application et garantir sa qualité et sa stabilité !