Vitest Komponententests in der Praxis: Browser Mode und Playwright-Integration

Ehrlich gesagt bin ich beim ersten Test einer Canvas-Komponente in eine ziemliche Falle getappt.
Ich starrte auf das grüne „PASS“ im Testreport und reichte den Code voller Zuversicht ein. Am nächsten Tag öffnete ein Kollege die Seite im echten Browser – und das Canvas wurde überhaupt nicht gerendert. Der Test war doch durchgelaufen?!
Später wurde mir klar: jsdom ist nur ein „Schein“-Browser. Es simuliert DOM-APIs, aber echtes Canvas-Rendering, berechnete CSS-Stile, der Lebenszyklus von Web Components – all das lässt sich damit nicht testen. Meine halbjährige Unit-Test-Konfiguration hatte nur an der Oberfläche gekratzt.
Deshalb führt Vitest ab Version 3.0 den Browser Mode ein – Tests laufen direkt in echten Browsern. Anders als jsdom, das das DOM in Node.js simuliert, startet Browser Mode Chromium/Firefox/Safari, rendert Komponenten wirklich und interagiert über die Playwright-API. Test bestanden? Dann wirklich bestanden.
Dieser Artikel führt Sie von der Browser-Mode-Konfiguration über React/Vue-Praxis bis zu CI-Coverage-Gates. Es ist Teil drei der Vitest-Testreihe; die ersten beiden Teile behandelten Unit-Test-Setup und TDD – hier fehlt das Puzzlestück Komponententests.
Warum Browser Mode?
Die Frage liegt nahe: Reicht jsdom nicht?
Für reine Logik-Komponenten – einen Taschenrechner, einen Formularvalidator – reicht jsdom völlig. Es ist ein DOM-Simulator in Node.js, schnell und einfach konfiguriert. In meinen ersten beiden Artikeln liefen alle Unit-Tests in jsdom; reaktive Daten und Event-Trigger – kein Problem.
Bei diesen Szenarien scheitert jsdom jedoch:
- Canvas-Zeichnung: jsdom kennt die Canvas-API, zeichnet aber nicht wirklich. Wie oft
ctx.fillRect()aufgerufen wird, lässt sich prüfen; ob das Bild stimmt? Nein. - Berechnete CSS-Stile:
getComputedStyle()liefert in jsdom ein leeres Objekt. Im echten Browser hängen Breite, Padding und Border vom Elterncontainer ab – jsdom rechnet das nicht. - Web Components:
connectedCallbackunddisconnectedCallbacksind simuliert, aber der Lebenszyklus triggert anders als im echten Browser. - Asynchrones Rendering: Animationsframes,
requestIdleCallback,IntersectionObserver– jsdom implementiert das gar nicht oder nur unvollständig.
Ein Beispiel aus eigener Erfahrung: Ein Projekt nutzte CSS-Animationen für aufklappbare Buttons. In jsdom feuert transitionend nie – es gibt keine echte Transition. Der Test mockte das Event; im echten Browser änderte sich die Animationsdauer, der Test blieb „grün“, die Komponente war kaputt.
Browser Mode löst genau das. Komponenten werden in echten Browsern gerendert; Sie schreiben Tests, Vitest startet Chromium (oder Firefox/Safari), mountet die Komponente und nutzt Playwright zum Klicken, Tippen und Warten. Was im Browser passiert, testen Sie auch.
Eine Zahl lohnt sich: Vitest 3.0 teilt sich in Browser Mode einen Chromium-Kontext – der Browser startet einmal, alle Tests nutzen dieselbe Instanz. Offiziell soll das etwa 30 % schneller sein als klassisches Playwright-E2E. Bei 50 Komponententests kein ständiges Starten und Schließen.
Zum Test-Pyramiden-Thema gibt es bei Komponententests Kontroversen. Klassisch: viele Unit-Tests, wenig E2E. Das Vue-Official-Blog und alexop.dev argumentieren für eine invertierte Pyramide – 70 % Integration, 20 % Unit, 10 % E2E. Begründung: Eine Komponente ist bereits eine Integration aus Template, Stil und Logik; jsdom-Unit-Tests prüfen vor allem Logik, Integrationstests das Gesamtverhalten. Browser Mode füllt die Lücke – realer als jsdom, leichter als Playwright-E2E.
Browser Mode konfigurieren – Praxis
Die Konfiguration ist nicht kompliziert, aber ein paar Fallstricke kenne ich aus eigener Erfahrung.
Abhängigkeiten installieren
Installieren Sie Vitest und den Browser-Mode-Provider. Offiziell wird Playwright empfohlen:
npm install -D vitest @vitest/browser-playwright
Playwright bringt Chromium, Firefox und WebKit mit. Für die meisten Fälle reicht Chromium:
npx playwright install chromium
Das dauert – das Chromium-Paket hat etwa 170 MB. Danach sind Sie fast fertig.
vitest.config.ts
Die Konfiguration ist schlank, ein Detail ist wichtig:
import { defineConfig } from 'vitest/config'
import { playwright } from '@vitest/browser-playwright'
export default defineConfig({
test: {
browser: {
provider: playwright(),
enabled: true,
instances: [{ browser: 'chromium' }],
},
},
})
instances legt fest, in welchem Browser getestet wird. Für Multi-Browser-Kompatibilität können Sie Firefox und WebKit ergänzen:
instances: [
{ browser: 'chromium' },
{ browser: 'firefox' },
{ browser: 'webkit' }, // Safari
]
Ich nutze meist nur Chromium – Multi-Browser ist langsam, die meisten Frontend-Bugs zeigen sich in Chromium. Safari-Probleme decke ich mit Playwright-E2E auf kritischen Pfaden ab.
Headless vs. UI-Modus
Die Wahl ist nicht trivial.
- Headless: Kein sichtbares Fenster, Tests laufen im Hintergrund. Ideal für CI, schnell, aber ohne visuelles Rendering.
- UI-Modus: Browserfenster offen – Sie sehen Mount, Klick und Eingabe. Praktisch beim Debuggen in der Entwicklung.
In der Entwicklung nutze ich den UI-Modus:
npx vitest --browser.ui
Vitest öffnet ein Test-Dashboard: links die Testliste, rechts der Browser. Klicken Sie eine Testdatei, die Komponente erscheint – Sie sehen die Ausführung. Button reagiert nicht? Direkt im Browser debuggen.
In CI Headless, eine Zeile in der Config:
browser: {
provider: playwright(),
enabled: true,
headless: true, // CI erzwingt headless
instances: [{ browser: 'chromium' }],
}
Dateinamen-Konvention
Offiziell empfiehlt sich .browser.test.ts, getrennt von normalem .test.ts. Vorteile:
- jsdom-Unit-Tests und Browser-Mode-Komponententests laufen getrennt.
- Bei mysteriösen CI-Fehlern erkennen Sie am Dateinamen sofort Browser-Tests.
Vitest erzwingt das nicht – .test.ts geht auch. Wichtig ist, Browser-Mode-Verzeichnisse in der Config einzubinden oder alles im Browser Mode laufen zu lassen. Ich trenne: jsdom für Units, Browser Mode für Komponenten.
React/Vue-Komponententests in der Praxis
Das ist der Kern von Browser Mode. Die Syntax weicht etwas von Testing Library ab, gewöhnt man sich aber schnell.
React-Komponententests
React-Adapter installieren:
npm install -D @vitest/browser-react
Beispiel: Counter-Komponente, Klick erhöht den Zähler:
// Counter.browser.test.ts
import { page } from '@vitest/browser/context'
import { userEvent } from '@vitest/browser/context'
import Counter from './Counter'
test('Klick auf Button erhöht Zähler', async () => {
await page.mount(<Counter />)
const button = page.getByRole('button', { name: 'Count: 0' })
await userEvent.click(button)
await expect.element(button).toHaveTextContent('Count: 1')
})
Vergleich mit Testing Library: dort render(), hier page.mount(). Dort screen.getByRole(), hier page.getByRole(). Die APIs ähneln sich; page ist der Browser-Mode-Kontext.
Ein Detail: await expect.element(button). Das ist Vitests Web Testing API – sie wartet automatisch auf Zustandsänderungen. Kein manuelles await waitFor() nötig; kompakter als Testing Library.
Vue-Komponententests
Ähnlich, mit Vue-Adapter:
npm install -D @vitest/browser-vue
Vue-Counter-Test:
// Counter.browser.test.ts
import { page } from '@vitest/browser/context'
import { userEvent } from '@vitest/browser/context'
import Counter from './Counter.vue'
test('Klick auf Button erhöht Zähler', async () => {
await page.mount(Counter)
const button = page.getByRole('button', { name: 'Count: 0' })
await userEvent.click(button)
await expect.element(button).toHaveTextContent('Count: 1')
})
Vue 2 mit @vue/test-utils – Browser Mode unterstützt das nicht direkt. Für Vue 3 reicht @vitest/browser-vue.
Praxisbeispiel
In einem Projekt: Drag-and-Sort-Liste mit HTML5 Drag & Drop. In jsdom lassen sich dragstart und drop nicht realistisch simulieren – nur Mocks, die prüfen, ob Events feuern, nicht ob die Sortierung stimmt.
Mit Browser Mode:
test('Drag-and-Drop-Sortierung', async () => {
await page.mount(<SortableList items={['A', 'B', 'C']} />)
const itemA = page.getByText('A')
const itemC = page.getByText('C')
await userEvent.dragTo(itemA, itemC)
const items = page.getByRole('listitem')
await expect.element(items.nth(2)).toHaveTextContent('A')
})
Im echten Browser feuert Drag & Drop wirklich, die Sortierlogik läuft, die Reihenfolge ändert sich. Test grün? Dann passt es wirklich.
Das ist der Wert von Browser Mode – echtes Verhalten, keine Simulation.
Playwright vs. Browser Mode – Entscheidungshilfe
Verwirrend: Beides sind Browser-Tests. Der Unterschied?
Kurz: Browser Mode testet Komponenten, Playwright testet Abläufe.
Kernunterschiede
| Eigenschaft | Browser Mode | Playwright |
|---|---|---|
| Testumfang | Isolierte Einzelkomponente | Multi-Page-Flows |
| Ausführungszeit | ca. 200 ms/Test | 2–5 s/Test |
| Startkosten | Geteilte Browser-Instanz | Oft pro Test neu starten |
| Konfiguration | Niedrig, in Vitest integriert | Höher, eigenes Projekt |
| Einsatz | Schnelle Iteration in der Entwicklung | Kritische Pfade vor Release |
Browser Mode mountet eine Komponente isoliert im Browser. Playwright öffnet die ganze App – Navigation, Login, Formular – der gesamte Flow.
Metapher: Browser Mode ist der Chirurg am Mikroskop für eine Zelle; Playwright der Hausarzt für das Organsystem. Beides hat seinen Platz.
Kombinationsstrategie
So setze ich es ein:
- Browser Mode: Alle UI-Komponenten – Buttons, Formulare, Karten, Modals. Mit dem Code committen, schnelles Feedback.
- Playwright E2E: 3–5 kritische Pfade – Login und Startseite, Suche und Ergebnisse, Submit und Bestellung. Vor Release oder im täglichen CI-Build.
Vorteile:
- Browser Mode fängt die meisten UI-Bugs früh ab.
- Playwright fängt Cross-Page-Integration ab.
- Wartbar: 50 Komponententests, 5 E2E – CI bleibt tragbar.
Wann was?
- Browser Mode: Einzelkomponente – Klick, Eingabe, Rendering, Stil. Code ändert sich, Feedback sofort.
- Playwright: Multi-Page – Login → Navigation → Aktion → Assertion. Oder Full-Stack – Frontend, API, Datenbank.
Beispiel: Datumsauswahl – Bereichsgrenzen, gesperrte Tage, Format → Browser Mode. Buchungsseite, Datum wählen, Bestellung absenden, zur Zahlung → Playwright.
Browser Mode testet nur Frontend; Playwright kann Full-Stack abdecken. Mit Backend-API mocken Sie in Browser Mode das Backend; Playwright-E2E kann Frontend und Backend gemeinsam prüfen.
CI-Coverage-Gates
Coverage ist der letzte Baustein in CI. Lange ignorierte ich das – bis nach einem Refactoring die Coverage von 80 % auf 60 % fiel und ein Bug live ging.
Coverage konfigurieren
In vitest.config.ts Schwellenwerte setzen:
test: {
coverage: {
provider: 'v8', // oder 'istanbul'
reporter: ['text', 'json', 'html'],
thresholds: {
lines: 80,
functions: 80,
branches: 75,
statements: 80
}
}
}
Schwellenwerte nach Erfahrung:
- Neues Projekt: Mit 50 % starten, schrittweise erhöhen. Zu hoch am Anfang erzeugt Druck.
- Reifes Projekt: 80 % ist sinnvoll. Kernmodule 90 % oder 95 %.
- Nicht 100 % jagen: Randfälle und Exception-Pfade sind oft nicht testbar – erzwungene Tests kosten Zeit ohne Nutzen.
Coverage ausführen:
npx vitest run --coverage
Unter dem Schwellenwert? Vitest bricht ab, CI schlägt fehl – das Gate verhindert Merge mit zu niedriger Coverage.
GitHub Actions
Zwei Schritte: Tests laufen lassen, Coverage melden.
# .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'
Die Action kommentiert PRs automatisch:
- Coverage-Delta (z. B. 80 % → 79 %, −1 %)
- Dateien mit gesunkener Coverage
- Neuer Code ohne Tests
Autoren sehen sofort: „Neuer Code braucht noch Tests.“
CI-Hinweise für Browser Mode
- Playwright installieren:
--with-deps, sonst startet Chromium nicht. - Headless:
headless: true– in CI gibt es keinen Monitor. - Timeout: Browser Mode ist langsamer als jsdom – ich setze 30 Sekunden.
- Parallelität: Geteilte Instanz –
maxWorkers: 4reicht mir.
Mein CI-Schritt:
- name: Run browser tests
run: npx vitest run --coverage --browser.headless
env:
CI: true
--browser.headless hält Fenster zu; CI: true passt Vitest-Verhalten an (z. B. keine Farbausgabe).
Fazit
Kernbotschaft: jsdom testet kein echtes Browserverhalten – Browser Mode schon. Canvas, berechnete CSS-Stile, Web Components, Drag & Drop, Animationen – dafür ist Browser Mode die richtige Wahl.
Setup ist überschaubar: @vitest/browser-playwright installieren, wenige Zeilen in vitest.config.ts, loslegen. React- und Vue-APIs ähneln Testing Library – niedrige Einstiegshürde.
Browser Mode ersetzt Playwright nicht. Komponenten hier, Flows dort: Browser Mode für UI in der Entwicklung, Playwright-E2E für kritische Pfade vor Release. Breite Abdeckung, schnelles CI.
Coverage-Gates sind der Abschluss: Schwellenwert setzen, PRs unter der Grenze blockieren. vitest-coverage-report-action in GitHub Actions – Coverage-Änderungen im PR-Kommentar, Probleme auf einen Blick.
Wenn Sie Browser Mode noch nicht probiert haben: Starten Sie mit einer einfachen Komponente – Button oder Input. Config verifizieren, dann komplexere Fälle. Fallstricke gibt es, aber danach laufen Tests flüssig – und die Entwicklung wird spürbar effizienter.
Vitest Browser Mode für Komponententests konfigurieren
Browser Mode von Grund auf einrichten, React/Vue-Komponententests ausführen und CI-Coverage-Gates integrieren
⏱️ Estimated time: 20 min
- 1
Step 1: Playwright-Provider installieren
Führen Sie npm install -D vitest @vitest/browser-playwright aus, um Abhängigkeiten zu installieren, und npx playwright install chromium, um den Browser herunterzuladen. - 2
Step 2: vitest.config.ts konfigurieren
Setzen Sie in test.browser provider: playwright(), enabled: true und instances: [{ browser: 'chromium' }]. In CI-Umgebungen headless: true hinzufügen. - 3
Step 3: Komponententests schreiben
Nutzen Sie page.mount() zum Rendern, page.getByRole() zum Abfragen von Elementen, userEvent.click() für Interaktionen und expect.element() für Assertions. - 4
Step 4: Coverage-Gates konfigurieren
Setzen Sie Schwellenwerte in vitest.config.ts coverage.thresholds (z. B. lines: 80) und integrieren Sie vitest-coverage-report-action in GitHub Actions, um PR-Coverage-Änderungen anzuzeigen.
FAQ
Was ist der Unterschied zwischen Browser Mode und jsdom?
Wie wähle ich zwischen Browser Mode und Playwright E2E?
Welchen Coverage-Schwellenwert soll ich setzen?
Unterstützt Browser Mode Vue 2?
Was ist bei Browser Mode in CI zu beachten?
9 Min. Lesezeit · Veröffentlicht am: 17. Mai 2026 · Aktualisiert am: 14. Juli 2026
Vitest Testing Guide
Wenn du über die Suche hier gelandet bist, kommst du am schnellsten weiter, indem du zum vorherigen oder nächsten Beitrag dieser Serie springst.
Vorheriger
Vitest Unit-Tests in der Praxis: TDD-Workflow und Coverage-Konfiguration
Vitest-TDD-Praxisleitfaden: vollständiger Red-Green-Refactor-Zyklus, Coverage-Reports und CI-Schwellenwerte, vi.fn/vi.spy/vi.mock im Vergleich – das bevorzugte Frontend-Testframework 2026
Teil 2 von 3
Nächster
Dies ist bisher der neueste Beitrag dieser Serie.
Ähnliche Beiträge
Vitest Unit-Tests in der Praxis: Von der Konfiguration zum TDD-Workflow

Vitest Unit-Tests in der Praxis: Von der Konfiguration zum TDD-Workflow
Self-Hosted Dev Sandboxes mit Docker und Go: Preview-URLs ohne Kubernetes


Kommentare
Melde dich mit GitHub an, um einen Kommentar zu hinterlassen