CommunityCodierung & Entwicklunggithub.com

Naki-404/naki-frontend-testing

Frontend-Komponententests mit Vitest und React Testing Library: verhaltensorientierte Tests, zugängliche Selektoren, user-event, Netzwerk-Mocking mit MSW, Hooks, asynchrone UI und Coverage. Verwende dies beim Schreiben oder Korrigieren von Tests für React-Komponenten, Hooks oder Seiten oder wenn Tests flaky, langsam oder an Implementierungsdetails gekoppelt sind.

Was ist naki-frontend-testing?

Dieses Skill bietet eine umfassende Anleitung für das Schreiben von Frontend-Komponententests mit Vitest und React Testing Library (RTL) in React-Anwendungen. Es fördert einen verhaltensorientierten Ansatz, bei dem getestet wird, was der Benutzer sieht und tut, nicht die interne Implementierung der Komponente. Die wichtigsten Prinzipien umfassen die Verwendung von zugänglichen Selektoren wie `getByRole` und `getByLabelText`, die Interaktion mit `userEvent` anstelle von `fireEvent`, und das Mocken des Netzwerks mit MSW (Mock Service Worker) auf HTTP-Ebene, anstatt Module direkt zu mocken. Das Skill beschreibt einen klaren Workflow: Verhalten auflisten, MSW-Handler hinzufügen, einen Test pro Verhalten schreiben und die Tests lokal ausführen. Es enthält eine Query-Referenztabelle, Setup-Code für Vitest (inklusive aktivierter unhandled Request-Erkennung), Beispiele für asynchrone UI-Tests und Fehlerzustände sowie eine Checkliste für gängige Fehler. Die Integration erfolgt nahtlos in bestehende Vitest- und RTL-Umgebungen. Nützlich für Entwickler, die flaky, langsame oder an Implementierungsdetails gekoppelte Tests vermeiden möchten.

Funktioniert mit~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 Codierung & Entwicklung skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

In Ihrer bevorzugten KI fragen

Öffnet einen neuen Chat, in dem dieser Agent-Skill bereits geladen ist.

Dokumentation

Frontend-Tests

Teste, was der Benutzer sieht und tut, nicht wie die Komponente aufgebaut ist. Kombiniere mit naki-tdd für den Entwicklungszyklus, naki-e2e-playwright für vollständige Browserabläufe und naki-accessibility für Semantik. Befolge das Projektregeln-Skill, falls vorhanden (z. B. naki-myapp).

Wann verwenden

  • Eine neue Komponente, ein neuer Hook oder eine neue Seite benötigt Tests.
  • Ein Test bricht nach einem Refactoring, das das Verhalten nicht geändert hat (Anzeichen für Kopplung an die Implementierung).
  • Tests sind flaky, verwenden überall waitFor oder mocken die halbe App.

Kernregeln

  1. Selektiere wie ein Benutzer. Priorität: getByRole (mit name), getByLabelText, getByPlaceholderText, getByText, getByDisplayValue. Verwende getByTestId nur, wenn nichts zugängliches existiert.
  2. Interagiere mit userEvent, nicht mit fireEvent. Erstelle es mit const user = userEvent.setup() und warte auf jeden Aufruf mit await.
  3. Prüfe die Ausgabe: sichtbaren Text, Rollen, Formularwerte, Aufrufe eines Netzwerkendpunkts. Prüfe niemals Zustandsvariablen, Hook-Interna, CSS-Klassennamen oder Instanzmethoden von Komponenten.
  4. Mocke das Netzwerk, nicht deine Module. Verwende MSW-Handler auf HTTP-Ebene. Mocke ein Modul nur für echte externe Grenzen (Zeit, Zufall, Browser-APIs, die nicht in jsdom sind).
  5. Verwende findBy* für Dinge, die später erscheinen. Reserviere waitFor für Assertions, die keine Selektoren sind, und setze niemals Seiteneffekte in waitFor.
  6. Ein Verhalten pro Test, benannt als Satz: zeigt einen Fehler an, wenn der Server 500 zurückgibt.
  7. Jeder Test richtet seinen eigenen Zustand ein. Keine Reihenfolgenabhängigkeit; setze Handler, Timer und Speicher in afterEach zurück.
  8. Stelle echte Provider durch einen renderWithProviders-Helfer bereit (Router, Query-Client mit deaktivierten Retries, Theme), anstatt sie zu mocken.
  9. Barrierefreiheit ist testbar. Ein fehlschlagender getByRole("button", { name: "Speichern" }) weist oft auf einen echten Barrierefreiheitsfehler hin. Füge optional vitest-axe-Prüfungen für wichtige Bildschirme hinzu.
  10. Coverage ist ein Signal, kein Ziel. Deckt die Zweige ab, die wichtig sind: Fehlerzustände, leere Zustände, Berechtigungen.

Selektoren-Referenz

ElementSelektor
ButtongetByRole("button", { name: /speichern/i })
LinkgetByRole("link", { name: "Dokumentation" })
Texteingabe mit LabelgetByRole("textbox", { name: "E-Mail" }) oder getByLabelText("E-Mail")
CheckboxgetByRole("checkbox", { name: "Angemeldet bleiben" })
ÜberschriftgetByRole("heading", { level: 2, name: "Benachrichtigungen" })
TabellenzeilegetAllByRole("row") dann within(row)
DialoggetByRole("dialog", { name: "Benachrichtigung löschen" })
Abwesenheitexpect(queryByText("Fehler")).not.toBeInTheDocument()

Arbeitsablauf

  1. Liste die Verhalten auf: Render-Zustände (Laden, Leer, Daten, Fehler) und Interaktionen.
  2. Füge MSW-Handler für die Endpunkte hinzu, die die Komponente aufruft; Standard ist Erfolg.
  3. Schreibe einen Test pro Verhalten und überschreibe Handler mit server.use(...) für Fehlerfälle.
  4. Führe npx vitest run path/to/file.test.tsx aus, dann die gesamte Suite.
  5. Zerstöre die Implementierung absichtlich einmal (kommentiere eine Zeile aus), um zu bestätigen, dass der Test fehlschlagen kann.

Setup

// 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" lässt einen fehlenden Handler lautstark fehlschlagen, anstatt zu hängen.

Beispiel

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("listet Benachrichtigungen auf und filtert nach Schweregrad", async () => {
  server.use(http.get("/api/alerts", () => HttpResponse.json([
    { id: "a1", title: "Brute-Force am VPN", severity: "high" },
    { id: "a2", title: "Neuer Admin-Login", severity: "low" },
  ])));
  const user = userEvent.setup();
  render(<AlertList />);

  expect(await screen.findByText("Brute-Force am VPN")).toBeInTheDocument();
  await user.selectOptions(screen.getByRole("combobox", { name: "Schweregrad" }), "high");
  expect(screen.queryByText("Neuer Admin-Login")).not.toBeInTheDocument();
});

test("zeigt einen Wiederholen-Button, wenn das Laden fehlschlägt", async () => {
  server.use(http.get("/api/alerts", () => new HttpResponse(null, { status: 500 })));
  render(<AlertList />);
  expect(await screen.findByRole("button", { name: /wiederholen/i })).toBeInTheDocument();
});

Hooks und Zeit

  • Teste einen Hook durch eine kleine Komponente, die ihn verwendet, oder mit renderHook, wenn er kein UI hat.
  • Gefälschte Timer: vi.useFakeTimers() und userEvent.setup({ advanceTimers: vi.advanceTimersByTime }); stelle mit vi.useRealTimers() in afterEach wieder her.
  • Friere Daten ein mit vi.setSystemTime(new Date("2026-01-01T00:00:00Z")), damit Snapshots und Labels stabil sind.

Checkliste

  • Selektoren basieren auf Rollen oder Labels.
  • Alle userEvent-Aufrufe werden mit await erwartet.
  • Netzwerk mit MSW gemockt; unbehandelte Anfragen schlagen fehl.
  • Lade-, Fehler- und leere Zustände abgedeckt.
  • Keine Assertions auf Interna oder Klassennamen.
  • Tests bestehen allein und in beliebiger Reihenfolge.
  • Keine act(...)-Warnungen in der Ausgabe.

Häufige Fehler

FehlerBehebung
getByTestId überallRollen-/Label-Selektoren; füge Labels zur Komponente hinzu, falls sie fehlen
await waitFor(() => getByText("x"))await findByText("x")
fireEvent.change zum Tippenawait user.type(input, "text")
Direktes Mocken des useAlerts-HooksMocke den HTTP-Endpunkt
Große Snapshots ganzer SeitenExplizite Assertions auf das, was wichtig ist
Query-Client mit aktivierten Retries, langsame Fehlertestsretry: false im Test-Provider
act-Warnungen ignoriertWarte auf das asynchrone UI-Update mit findBy*

Individual skills in this repo

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

Verwandte Skills