Naki-404/naki-frontend-testing

Tests unitaires et de composants frontend avec Vitest et React Testing Library : tests orientés comportement, requêtes accessibles, user-event, simulation réseau avec MSW, hooks, UI asynchrone et couverture de code. À utiliser lors de l'écriture ou de la correction de tests pour des composants React, des hooks ou des pages, ou lorsque les tests sont instables, lents ou couplés aux détails d'implémentation.

Qu'est-ce que naki-frontend-testing ?

Ce skill guide l'écriture de tests frontend orientés comportement avec Vitest et React Testing Library, en se concentrant sur ce que l'utilisateur voit et fait plutôt que sur l'implémentation interne des composants. Il promeut l'utilisation de requêtes accessibles (getByRole, getByLabelText, etc.), l'interaction via userEvent au lieu de fireEvent, et la simulation réseau via MSW (Mock Service Worker) pour éviter de moquer les modules directement. Le skill fournit des règles concrètes (une par test, état indépendant, fournisseurs réels via renderWithProviders), un aide-mémoire de requêtes, un workflow étape par étape, et des exemples de tests avec gestion des cas de succès et d'erreur. Il est conçu pour les développeurs React utilisant Vitest et RTL, et aide à résoudre les problèmes de tests instables, lents ou couplés à l'implémentation, tout en renforçant l'accessibilité et la fiabilité des tests.

Compatible avec~Claude Code~Codex CLI~Cursor
Part ofReact
npx skills add https://github.com/Naki-404/naki-claude-kit/tree/HEAD/kit/skills/naki-frontend-testing

Installed? Explore more Développement et programmation skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

Tests frontend

Testez ce que l'utilisateur voit et fait, pas comment le composant est construit. Associez avec naki-tdd pour la boucle, naki-e2e-playwright pour les flux navigateur complets et naki-accessibility pour la sémantique. Suivez la règle skill du projet si elle existe (par exemple naki-myapp).

Quand l'utiliser

  • Un nouveau composant, hook ou page nécessite des tests.
  • Un test échoue après un refactor qui n'a pas changé le comportement (signe de couplage à l'implémentation).
  • Les tests sont instables, utilisent waitFor partout, ou moquent la moitié de l'application.

Règles essentielles

  1. Interrogez comme un utilisateur. Priorité : getByRole (avec name), getByLabelText, getByPlaceholderText, getByText, getByDisplayValue. Utilisez getByTestId uniquement quand rien d'accessible n'existe.
  2. Interagissez avec userEvent, pas fireEvent. Créez-le avec const user = userEvent.setup() et attendez chaque appel.
  3. Affirmez sur la sortie : texte visible, rôles, valeurs de formulaire, appels à un endpoint réseau. N'affirmez jamais sur les variables d'état, les internes des hooks, les noms de classes CSS ou les méthodes d'instance des composants.
  4. Simulez le réseau, pas vos modules. Utilisez les gestionnaires MSW au niveau HTTP. Ne mockez un module que pour des limites extérieures réelles (temps, aléatoire, API du navigateur non présentes dans jsdom).
  5. Utilisez findBy* pour les choses qui apparaissent plus tard. Réservez waitFor pour les assertions qui ne sont pas une requête, et ne mettez jamais d'effets de bord dans waitFor.
  6. Un comportement par test, nommé comme une phrase : affiche une erreur quand le serveur renvoie 500.
  7. Chaque test configure son propre état. Pas de dépendance d'ordre ; réinitialisez les handlers, les timers et le stockage dans afterEach.
  8. Fournissez de vrais fournisseurs via un helper renderWithProviders (routeur, client de requête avec réessai désactivé, thème) au lieu de les moquer.
  9. L'accessibilité est testable. Un échec de getByRole("button", { name: "Enregistrer" }) signale souvent un vrai bug d'accessibilité. Ajoutez optionnellement des vérifications vitest-axe pour les écrans clés.
  10. La couverture est un signal, pas un objectif. Couvrez les branches qui comptent : états d'erreur, états vides, permissions.

Aide-mémoire des requêtes

ÉlémentRequête
boutongetByRole("button", { name: /enregistrer/i })
liengetByRole("link", { name: "Docs" })
champ texte avec labelgetByRole("textbox", { name: "Email" }) ou getByLabelText("Email")
case à cochergetByRole("checkbox", { name: "Se souvenir de moi" })
titregetByRole("heading", { level: 2, name: "Alertes" })
ligne de tableaugetAllByRole("row") puis within(row)
dialoguegetByRole("dialog", { name: "Supprimer l'alerte" })
absenceexpect(queryByText("Erreur")).not.toBeInTheDocument()

Workflow

  1. Listez les comportements : états de rendu (chargement, vide, données, erreur) et interactions.
  2. Ajoutez des gestionnaires MSW pour les endpoints que le composant appelle ; par défaut en succès.
  3. Écrivez un test par comportement, en écrasant les handlers avec server.use(...) pour les cas d'erreur.
  4. Lancez npx vitest run path/to/file.test.tsx, puis toute la suite.
  5. Cassez intentionnellement l'implémentation une fois (commentez une ligne) pour confirmer que le test peut échouer.

Configuration

// vitest.setup.ts
import "@testing-library/jest-dom/vitest";
import { afterAll, afterEach, beforeAll } from "vitest";
import { cleanup } from "@testing-library/react";
import { server } from "./src/test/server";

beforeAll(() => server.listen({ onUnhandledRequest: "error" }));
afterEach(() => { server.resetHandlers(); cleanup(); });
afterAll(() => server.close());

onUnhandledRequest: "error" fait échouer un handler manquant de manière visible au lieu de bloquer.

Exemple

import { http, HttpResponse } from "msw";
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { server } from "../test/server";
import { AlertList } from "./AlertList";

test("liste les alertes et filtre par sévérité", async () => {
  server.use(http.get("/api/alerts", () => HttpResponse.json([
    { id: "a1", title: "Brute force sur le VPN", severity: "high" },
    { id: "a2", title: "Nouvelle connexion admin", severity: "low" },
  ])));
  const user = userEvent.setup();
  render(<AlertList />);

  expect(await screen.findByText("Brute force sur le VPN")).toBeInTheDocument();
  await user.selectOptions(screen.getByRole("combobox", { name: "Sévérité" }), "high");
  expect(screen.queryByText("Nouvelle connexion admin")).not.toBeInTheDocument();
});

test("affiche un bouton de réessai en cas d'échec du chargement", async () => {
  server.use(http.get("/api/alerts", () => new HttpResponse(null, { status: 500 })));
  render(<AlertList />);
  expect(await screen.findByRole("button", { name: /réessayer/i })).toBeInTheDocument();
});

Hooks et temps

  • Testez un hook via un petit composant qui l'utilise, ou avec renderHook quand il n'a pas d'UI.
  • Temporisateurs fictifs : vi.useFakeTimers() et userEvent.setup({ advanceTimers: vi.advanceTimersByTime }) ; restaurez avec vi.useRealTimers() dans afterEach.
  • Figez les dates avec vi.setSystemTime(new Date("2026-01-01T00:00:00Z")) pour que les snapshots et les labels soient stables.

Liste de vérification

  • Les requêtes sont basées sur les rôles ou les labels.
  • Tous les appels userEvent sont attendus.
  • Réseau mocké avec MSW ; les requêtes non traitées échouent.
  • États de chargement, d'erreur et vide couverts.
  • Pas d'assertion sur les internes ou les noms de classes.
  • Les tests passent seuls et dans n'importe quel ordre.
  • Pas d'avertissement act(...) dans la sortie.

Erreurs courantes

ErreurCorrection
getByTestId partoutrequêtes par rôle/label ; ajoutez des labels au composant si manquants
await waitFor(() => getByText("x"))await findByText("x")
fireEvent.change pour la saisieawait user.type(input, "texte")
Moquer directement le hook useAlertsmockez l'endpoint HTTP
Grands snapshots de pages entièresassertions explicites sur ce qui compte
Client de requête avec réessais activés, tests d'erreur lentsretry: false dans le fournisseur de test
Avertissements act ignorésattendez la mise à jour asynchrone de l'UI avec findBy*

Individual skills in this repo

This repo contains 1 individual skill — each has its own dedicated page.

Skills associés