Tests de composants Vitest : Browser Mode et intégration Playwright

La première fois que j’ai testé un composant Canvas, j’ai pris une sacrée claque.
Le rapport affichait un « PASS » vert ; j’ai soumis le code en toute confiance. Le lendemain, un collègue ouvre la page dans un vrai navigateur — le Canvas ne s’affiche tout simplement pas. Pourtant les tests passaient !
J’ai compris ensuite : jsdom n’est qu’un « faux » navigateur. Il simule les API DOM, mais le rendu réel du Canvas, les styles CSS calculés, le cycle de vie des Web Components — tout ça, il ne peut pas le tester. Ma config de tests unitaires depuis six mois ne couvrait qu’une partie de la surface.
C’est pour ça que Vitest 3.0 a introduit le Browser Mode — exécuter les tests directement dans un vrai navigateur. Contrairement à jsdom qui simule le DOM dans Node.js, Browser Mode lance Chromium/Firefox/Safari, rend réellement les composants, puis interagit via l’API Playwright. Test vert ? Alors c’est vraiment bon.
Cet article vous guide de la configuration Browser Mode à zéro jusqu’aux tests React/Vue en conditions réelles, puis aux seuils de couverture en CI. Troisième volet de la série Vitest : les deux premiers couvraient la config unitaire et le TDD ; ici, on complète avec les tests de composants.
Pourquoi Browser Mode ?
Vous vous demandez peut-être : jsdom ne suffit pas ?
Pour des composants purement logiques — une calculatrice, un validateur de formulaire — jsdom suffit largement. C’est un simulateur DOM dans Node.js, rapide et simple. Mes deux premiers articles sur les tests unitaires tournaient entièrement en jsdom : données réactives, déclenchement d’événements, aucun souci.
Mais dans ces scénarios, jsdom faiblit :
- Dessin Canvas : jsdom expose l’API Canvas, mais ne dessine pas vraiment. Compter les appels à
ctx.fillRect()? OK. Vérifier que le rendu est correct ? Impossible. - Styles CSS calculés :
getComputedStyle()renvoie un objet vide en jsdom. Dans un vrai navigateur, la largeur dépend du conteneur parent, du padding, de la bordure — jsdom ne calcule rien de tout ça. - Web Components :
connectedCallback,disconnectedCallbacksont simulés, mais le timing du cycle de vie diffère du navigateur réel. - Rendu asynchrone : animation frames, requestIdleCallback, IntersectionObserver — jsdom ne les implémente pas ou de façon incomplète.
Exemple concret. L’an dernier, un composant utilisait une animation CSS pour ouvrir/fermer un bouton. En jsdom, l’événement transitionend ne se déclenche jamais — pas de transition réelle. J’ai mocké l’événement ; les tests passaient, mais après un changement de durée d’animation en prod, le composant était cassé.
Browser Mode résout ça. Il rend le composant dans un vrai navigateur : Chromium (ou Firefox/Safari), montage sur la page, clics, saisie, attentes via Playwright. Ce qui se passe dans le navigateur, le test le vérifie.
Un chiffre utile : le Browser Mode de Vitest 3.0 partage le contexte Chromium — le navigateur ne démarre qu’une fois, tous les tests réutilisent la même instance. Officiellement, ~30 % plus rapide qu’un E2E Playwright classique. Pour 50 composants, pas de redémarrage du navigateur à chaque test.
Côté pyramide de tests, le niveau « composants » fait débat. Pyramide classique : beaucoup d’unitaires, peu d’E2E. Le blog Vue et alexop.dev proposent l’inverse : 70 % d’intégration, 20 % d’unitaires, 10 % d’E2E — un composant combine template, styles et logique ; jsdom ne couvre que la logique. Browser Mode comble ce trou : plus fidèle que jsdom, plus léger que Playwright E2E.
Configuration Browser Mode en pratique
Configurer Browser Mode n’est pas si compliqué — mais j’ai déjà marché sur quelques pièges.
Installation des dépendances
Installez Vitest et le provider Browser Mode. Recommandation officielle : Playwright.
npm install -D vitest @vitest/browser-playwright
Playwright installe Chromium, Firefox et WebKit. Pour ne tester que Chromium (souvent suffisant) :
npx playwright install chromium
Comptez un peu de temps : le paquet Chromium fait ~170 Mo. Une fois téléchargé, vous êtes prêt.
Configuration vitest.config.ts
La config est simple ; un détail compte :
import { defineConfig } from 'vitest/config'
import { playwright } from '@vitest/browser-playwright'
export default defineConfig({
test: {
browser: {
provider: playwright(),
enabled: true,
instances: [{ browser: 'chromium' }],
},
},
})
instances choisit le navigateur. Pour la compatibilité multi-navigateurs :
instances: [
{ browser: 'chromium' },
{ browser: 'firefox' },
{ browser: 'webkit' }, // Safari
]
Je ne garde en général que Chromium — multi-navigateur ralentit, et la plupart des bugs frontend apparaissent déjà sous Chromium. Safari, je le couvre via Playwright E2E sur les parcours critiques.
Mode headless vs mode UI
Deux usages distincts :
- Headless : pas de fenêtre visible, tests en arrière-plan. Idéal en CI, rapide, mais vous ne voyez pas le rendu.
- UI : fenêtre ouverte, vous observez rendu, clics, saisie. Parfait en développement pour déboguer.
En dev, j’utilise le mode UI :
npx vitest --browser.ui
Vitest ouvre un workbench : liste des tests à gauche, navigateur à droite. Vous cliquez un fichier, le composant s’affiche, vous suivez l’exécution. Un bouton ne répond pas ? Déboguez directement dans le navigateur.
En CI, headless obligatoire :
browser: {
provider: playwright(),
enabled: true,
headless: true, // CI force headless
instances: [{ browser: 'chromium' }],
}
Convention de nommage des fichiers de test
L’équipe Vitest suggère le suffixe .browser.test.ts pour distinguer du .test.ts classique. Avantages :
- Lancer séparément tests jsdom et Browser Mode.
- En cas d’échec CI, le nom indique tout de suite qu’il s’agit de tests navigateur.
Vitest n’impose pas ce nom ; .test.ts fonctionne aussi. L’essentiel : configurer les dossiers ou tout exécuter en Browser Mode. Ma pratique : jsdom pour l’unitaire, Browser Mode pour les composants.
Tests de composants React/Vue
C’est le cœur du Browser Mode. La syntaxe diffère un peu de Testing Library, mais on s’y habitue vite.
Tests de composants React
Installez l’adaptateur React :
npm install -D @vitest/browser-react
Exemple : composant Counter, le compteur s’incrémente au clic :
// Counter.browser.test.ts
import { page } from '@vitest/browser/context'
import { userEvent } from '@vitest/browser/context'
import Counter from './Counter'
test('incrément au clic sur le bouton', async () => {
// Monter le composant dans le navigateur
await page.mount(<Counter />)
// Trouver le bouton
const button = page.getByRole('button', { name: 'Count: 0' })
// Simuler le clic
await userEvent.click(button)
// Vérifier le texte mis à jour
await expect.element(button).toHaveTextContent('Count: 1')
})
Comparaison Testing Library : render() devient page.mount(), screen.getByRole() devient page.getByRole(). Même esprit, page est le contexte Browser Mode.
Détail : await expect.element(button) — Web Testing API de Vitest, attente automatique du changement d’état. Pas besoin de await waitFor() manuel.
Tests de composants Vue
Même logique, avec l’adaptateur Vue :
npm install -D @vitest/browser-vue
Test du Counter Vue :
// Counter.browser.test.ts
import { page } from '@vitest/browser/context'
import { userEvent } from '@vitest/browser/context'
import Counter from './Counter.vue'
test('incrément au clic sur le bouton', async () => {
// Monter le composant Vue
await page.mount(Counter)
// Trouver, cliquer, vérifier
const button = page.getByRole('button', { name: 'Count: 0' })
await userEvent.click(button)
await expect.element(button).toHaveTextContent('Count: 1')
})
Vue 2 : @vue/test-utils, pas de support Browser Mode direct. Vue 3 : @vitest/browser-vue suffit.
Cas concret
Dans un projet : liste triable par glisser-déposer (HTML5 Drag & Drop). En jsdom, impossible de simuler dragstart et drop proprement — mock = « événement déclenché », pas « ordre réellement changé ».
En Browser Mode :
test('tri par glisser-déposer', async () => {
await page.mount(<SortableList items={['A', 'B', 'C']} />)
const itemA = page.getByText('A')
const itemC = page.getByText('C')
// Glisser A après C
await userEvent.dragTo(itemA, itemC)
// Vérifier le nouvel ordre
const items = page.getByRole('listitem')
await expect.element(items.nth(2)).toHaveTextContent('A')
})
Dans le navigateur, le Drag & Drop se déclenche vraiment, la logique de tri s’exécute, l’ordre change. Test vert = comportement réel validé.
C’est la valeur du Browser Mode — comportement réel, pas simulation.
Playwright vs Browser Mode : guide de choix
Browser Mode et Playwright, tous deux dans le navigateur — quelle différence ?
En bref : Browser Mode pour les composants, Playwright pour les flux.
Différences clés
| Caractéristique | Browser Mode | Playwright |
|---|---|---|
| Périmètre | Composant isolé | Flux multi-pages |
| Vitesse | ~200 ms/test | 2-5 s/test |
| Coût de démarrage | Instance partagée | Démarrage par test |
| Complexité config | Faible, intégré à Vitest | Élevée, projet séparé |
| Usage typique | Itération rapide en dev | Validation des parcours avant release |
Browser Mode = test de composant monté seul. Playwright = E2E sur l’application complète : navigation, login, formulaires, parcours entier.
Analogie : Browser Mode, le microscope sur une cellule ; Playwright, l’examen de l’organe entier. Complémentaires, pas substituables.
Stratégie combinée
En projet réel :
- Browser Mode : tous les composants UI — boutons, formulaires, cartes, modales. Écrits en dev, commités avec le code. Rapides, retour immédiat.
- Playwright E2E : 3 à 5 parcours critiques — login → accueil, recherche → résultats, soumission → commande. Avant release ou build quotidien CI.
Avantages :
- Browser Mode attrape la majorité des bugs UI en développement.
- Playwright couvre l’intégration multi-pages avant release.
- Coût de maintenance maîtrisé — ~50 tests composants, ~5 E2E, CI reste fluide.
Quand choisir quoi ?
- Browser Mode : comportement UI d’un composant — clic, saisie, rendu, styles. Besoin de feedback instantané après modification.
- Playwright : flux multi-pages — login → navigation → action → vérification. Ou intégration front + API + base.
Exemple : sélecteur de dates (plages, dates désactivées, format) → Browser Mode. Réservation → paiement sur plusieurs pages → Playwright.
Browser Mode = front uniquement. Playwright peut couvrir full-stack (front + API backend). Browser Mode mock le backend côté composant.
Seuils de couverture en CI
La couverture clôt la boucle CI. Je l’ai sous-estimée jusqu’à une refacto qui a fait passer la couverture de 80 % à 60 % — bug en prod, leçon apprise.
Configuration de la couverture
Dans vitest.config.ts :
test: {
coverage: {
provider: 'v8', // ou 'istanbul'
reporter: ['text', 'json', 'html'],
thresholds: {
lines: 80,
functions: 80,
branches: 75,
statements: 80
}
}
}
Seuils recommandés :
- Nouveau projet : partir de 50 %, monter progressivement.
- Projet mature : 80 % est raisonnable ; modules critiques 90-95 %.
- Pas 100 % : branches limites, erreurs rares — forcer des tests coûte plus qu’ils n’apportent.
Lancer avec couverture :
npx vitest run --coverage
Sous le seuil ? Vitest échoue, le build CI bloque. Porte d’entrée : pas de merge sous le seuil.
Intégration GitHub Actions
Deux étapes : tests + rapport de couverture.
# .github/workflows/test.yml
name: Test
on: [pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- run: npm ci
- run: npx playwright install chromium --with-deps
- name: Run tests with coverage
run: npx vitest run --coverage
- name: Report coverage
uses: davelosert/vitest-coverage-report-action@v2
with:
json-summary-path: './coverage/coverage-summary.json'
Cette action commente automatiquement la PR :
- Variation de couverture (ex. 80 % → 79 %, affiché -1 %)
- Fichiers en baisse
- Nouveau code non couvert
L’auteur voit tout de suite : « Ma couverture baisse, il faut ajouter des tests. »
Points d’attention en CI
Pièges Browser Mode en CI :
- Installation Playwright :
--with-deps, sinon Chromium ne démarre pas. - Headless :
headless: trueobligatoire sans écran. - Timeout : Browser Mode est plus lent que jsdom ; j’utilise 30 s.
- Parallélisme : instance partagée —
maxWorkers: 4max chez moi.
Extrait de workflow :
- name: Run browser tests
run: npx vitest run --coverage --browser.headless
env:
CI: true
--browser.headless sans fenêtre ; CI: true ajuste le comportement Vitest (ex. couleurs désactivées).
Synthèse
L’essentiel : jsdom ne teste pas le comportement navigateur réel ; Browser Mode oui. Canvas, styles calculés, Web Components, drag & drop, animations — Browser Mode est souvent le seul choix crédible.
La config est simple : @vitest/browser-playwright, quelques lignes dans vitest.config.ts, c’est parti. API proche de Testing Library pour React et Vue.
Browser Mode n’est pas universel : composant vs flux. Combinez : Browser Mode en dev sur tous les composants UI, Playwright E2E sur les parcours critiques avant release. Couverture large, CI raisonnable.
Les seuils de couverture ferment la boucle. Seuil minimal, PR bloquée si non respecté. vitest-coverage-report-action dans GitHub Actions — la variation apparaît dans le commentaire PR.
Si vous n’avez pas encore testé Browser Mode, commencez par un bouton ou un champ texte. Validez la config, puis montez en complexité. Des pièges, oui — une fois passés, les tests deviennent fluides et l’efficacité en dev monte nettement.
Configurer Vitest Browser Mode pour les tests de composants
Configurer Browser Mode de zéro, exécuter des tests React/Vue, intégrer les seuils de couverture en CI
⏱️ Estimated time: 20 min
- 1
Step 1: Installer le provider Playwright
Exécutez npm install -D vitest @vitest/browser-playwright, puis npx playwright install chromium pour télécharger le navigateur. - 2
Step 2: Configurer vitest.config.ts
Dans test.browser, définissez provider: playwright(), enabled: true, instances: [{ browser: 'chromium' }] ; en CI, ajoutez headless: true. - 3
Step 3: Écrire les tests de composants
Utilisez page.mount() pour rendre le composant, page.getByRole() pour cibler les éléments, userEvent.click() pour simuler les interactions, expect.element() pour les assertions. - 4
Step 4: Configurer les seuils de couverture
Définissez coverage.thresholds (lines: 80) dans vitest.config.ts ; intégrez vitest-coverage-report-action dans GitHub Actions pour afficher l'évolution sur les PR.
FAQ
Quelle différence entre Browser Mode et jsdom ?
Browser Mode ou Playwright E2E — comment choisir ?
Quel seuil de couverture adopter ?
Browser Mode prend-il en charge Vue 2 ?
Points d'attention pour Browser Mode en CI ?
10 min de lecture · Publié le: 17 mai 2026 · Mis à jour le: 27 juil. 2026
Guide de test Vitest
Si vous arrivez depuis la recherche, le plus rapide est de passer à l’article précédent ou suivant de cette série.
Précédent
Tests unitaires Vitest : TDD et configuration de la couverture
Tutoriel TDD avec Vitest : cycle Red-Green-Refactor, rapports de couverture et seuils CI, vi.fn/vi.spy/vi.mock expliqués — le framework de tests frontend de référence en 2026.
Partie 2 sur 3
Suivant
C’est le dernier article publié dans cette série pour le moment.



Commentaires
Connectez-vous avec GitHub pour laisser un commentaire