Testing & E2E

Cypress vs. Playwright mit Claude Code: E2E Testing 2026

E2E-Tests sind 2026 kein Nice-to-have mehr — sie sind Produktions-Gate. Wer mit Claude Code arbeitet, hat täglich die Wahl: Cypress oder Playwright? Beide Tools sind ausgezeichnet. Beide haben Claude-Code-Integration. Aber sie unterscheiden sich fundamental in Architektur, API und Einsatzgebiet.

Dieser Artikel ist kein Marketing. Wir zeigen echten TypeScript-Code, echte CI/CD-Konfigurationen und eine ehrliche Entscheidungsmatrix — damit du für dein Team und dein Projekt das richtige Tool wählst.

Claude Code Relevanz: Beide Frameworks werden von Claude Code direkt unterstützt. Claude generiert Tests, analysiert Fehler, schlägt Fixture-Strukturen vor und refaktoriert Selektoren — aber nur wenn du verstehst, was Claude da eigentlich schreibt. Genau dafür ist dieser Vergleich da.

1. Direkt-Vergleich: Architektur & Setup

Der fundamentale Unterschied zwischen Cypress und Playwright liegt nicht in der API — er liegt in der Architektur. Cypress führt Tests im Browser aus (In-Process), Playwright kommuniziert mit dem Browser über das Chrome DevTools Protocol (CDP) von außen.

Cypress In-Browser-Execution

  • JavaScript läuft direkt im Browser-Kontext
  • Echtzeit-Reloading beim Schreiben von Tests (Test Runner GUI)
  • Native Zugriff auf window, localStorage, DOM ohne Umwege
  • Time-travel Debugging mit Screenshot-Snapshots pro Command
  • Einschränkung: Primär Chromium, Firefox als Beta; kein WebKit

Playwright CDP/Out-of-Process

  • Kommuniziert mit Browser via WebSocket/CDP-Protocol
  • Echter Multi-Browser-Support: Chromium, Firefox, WebKit (Safari)
  • Headless-first Architektur — ideal für CI/CD ohne GUI
  • Multiple Contexts und Pages in einem Test nativ unterstützt
  • Kein eingebauter Real-time-Reloader, dafür --ui Mode seit v1.32

Setup-Vergleich mit Claude Code

Claude Code kann das initiale Setup beider Tools generieren. Hier der direkte Vergleich der Installation und Basiskonfiguration:

# Cypress Installation npm install --save-dev cypress npx cypress open # GUI startet, erstellt cypress.config.ts # Playwright Installation npm install --save-dev @playwright/test npx playwright install # lädt Browser-Binaries (~280MB) npx playwright test --ui # Playwright UI Mode
// cypress.config.ts import { defineConfig } from 'cypress'; export default defineConfig({ e2e: { baseUrl: 'http://localhost:3000', specPattern: 'cypress/e2e/**/*.cy.ts', viewportWidth: 1280, viewportHeight: 720, video: true, screenshotOnRunFailure: true, experimentalStudio: true, // AI-gestützter Test-Recorder }, });
// playwright.config.ts import { defineConfig, devices } from '@playwright/test'; export default defineConfig({ testDir: './tests/e2e', fullyParallel: true, retries: process.env.CI ? 2 : 0, workers: process.env.CI ? 4 : undefined, reporter: [ ['html'], ['json', { outputFile: 'test-results/results.json' }], ], use: { baseURL: 'http://localhost:3000', trace: 'on-first-retry', screenshot: 'only-on-failure', video: 'retain-on-failure', }, projects: [ { name: 'chromium', use: { ...devices['Desktop Chrome'] } }, { name: 'firefox', use: { ...devices['Desktop Firefox'] } }, { name: 'webkit', use: { ...devices['Desktop Safari'] } }, ], });
Merkmal Cypress Playwright
Architektur In-Browser (JS im Browser) Out-of-Process (CDP/WebSocket)
Browser-Support Chromium, Firefox (Beta) Chromium, Firefox, WebKit
Real-time Debug Time-travel, Screenshot pro Step Trace Viewer, --ui Mode
Headless-Performance Gut, aber mehr Overhead Sehr schnell, headless-first
Multiple Tabs/Windows Eingeschränkt Native Unterstützung
Mobile Emulation Viewport-basiert Echter Device-Fingerprint
Setup-Komplexität Einfacher Einstieg Browser-Download nötig
Claude Code Integration Sehr gut Sehr gut
Claude Code Tipp: Wenn du Claude Code bittest, Tests zu generieren, spezifiziere immer das Framework explizit: "Schreib einen Playwright-Test für Login-Flow mit page.locator()" statt nur "schreib einen E2E-Test". Claude kennt beide APIs gut, aber Kontext verhindert Halluzinationen bei Framework-spezifischen Features.

2. Test-Syntax & API-Vergleich

Die Syntax beider Tools ist auf den ersten Blick ähnlich, im Detail aber grundlegend verschieden. Cypress nutzt ein Command-Queue-Modell mit impliziten Assertions. Playwright arbeitet mit echten async/await Promises und expliziten Locatoren.

Cypress: Command Queue & Chaining

// cypress/e2e/auth/login.cy.ts import { LoginPage } from '../../support/pages/LoginPage'; describe('Authentication Flow', () => { const loginPage = new LoginPage(); beforeEach(() => { cy.clearCookies(); cy.clearLocalStorage(); cy.visit('/login'); }); it('sollte erfolgreich einloggen', () => { // Cypress: Command-Queue, kein await nötig cy.get('[data-testid="email-input"]') .should('be.visible') .type('user@example.com'); cy.get('[data-testid="password-input"]') .type('sicheres-passwort-2026'); cy.get('[data-testid="login-button"]') .should('not.be.disabled') .click(); // URL-Assertion nach Redirect cy.url().should('include', '/dashboard'); cy.get('[data-testid="user-greeting"]') .should('contain.text', 'Willkommen'); }); it('sollte Fehler bei falschem Passwort zeigen', () => { cy.get('[data-testid="email-input"]').type('user@example.com'); cy.get('[data-testid="password-input"]').type('falsches-passwort'); cy.get('[data-testid="login-button"]').click(); cy.get('[data-testid="error-message"]') .should('be.visible') .and('contain.text', 'Ungültige Anmeldedaten'); }); it('sollte API-Response abwarten', () => { // cy.intercept für Request-Tracking cy.intercept('POST', '/api/auth/login').as('loginRequest'); cy.get('[data-testid="email-input"]').type('user@example.com'); cy.get('[data-testid="password-input"]').type('sicheres-passwort-2026'); cy.get('[data-testid="login-button"]').click(); cy.wait('@loginRequest').then((interception) => { expect(interception.response?.statusCode).to.equal(200); expect(interception.response?.body).to.have.property('token'); }); }); });

Playwright: Async/Await & Locators

// tests/e2e/auth/login.spec.ts import { test, expect, Page } from '@playwright/test'; // Page Object Model mit Playwright class LoginPage { constructor(private page: Page) {} async navigate() { await this.page.goto('/login'); } async login(email: string, password: string) { await this.page.getByTestId('email-input').fill(email); await this.page.getByTestId('password-input').fill(password); await this.page.getByTestId('login-button').click(); } } test.describe('Authentication Flow', () => { test.beforeEach(async ({ page }) => { await page.context().clearCookies(); }); test('sollte erfolgreich einloggen', async ({ page }) => { const loginPage = new LoginPage(page); await loginPage.navigate(); await loginPage.login('user@example.com', 'sicheres-passwort-2026'); // Playwright wartet automatisch auf URL-Change await expect(page).toHaveURL(/.*dashboard/); await expect(page.getByTestId('user-greeting')) .toContainText('Willkommen'); }); test('sollte Fehler bei falschem Passwort zeigen', async ({ page }) => { const loginPage = new LoginPage(page); await loginPage.navigate(); await loginPage.login('user@example.com', 'falsch'); await expect(page.getByTestId('error-message')) .toBeVisible(); await expect(page.getByTestId('error-message')) .toContainText('Ungültige Anmeldedaten'); }); test('sollte API-Response tracken', async ({ page }) => { // Playwright: Promise-basiertes Request-Tracking const responsePromise = page.waitForResponse( resp => resp.url().includes('/api/auth/login') && resp.status() === 200 ); const loginPage = new LoginPage(page); await loginPage.navigate(); await loginPage.login('user@example.com', 'sicheres-passwort-2026'); const response = await responsePromise; const body = await response.json(); expect(body).toHaveProperty('token'); }); });
Wichtiger Unterschied: Cypress nutzt ein Command-Queue-System — dein Code sieht synchron aus, ist aber async. Das verwirrt viele Entwickler, besonders bei if/else Logik. Playwright's echtes async/await ist TypeScript-nativ und vermeidet diese Falle komplett.

Selector-Strategien im Vergleich

// Cypress Selectors cy.get('[data-testid="submit"]') // Attribut cy.get('.btn-primary') // Klasse cy.contains('Jetzt kaufen') // Text-Suche cy.get('form').find('input[type=email]') // Nested cy.get('table tr').eq(2) // Index-basiert // Playwright Locators (bevorzugte Reihenfolge laut Docs) page.getByRole('button', { name: 'Jetzt kaufen' }) // ARIA Role (Best Practice) page.getByLabel('E-Mail-Adresse') // Label-Assoziation page.getByPlaceholder('name@example.com') // Placeholder page.getByText('Willkommen zurück') // Text-Suche page.getByTestId('submit-button') // data-testid page.locator('table >> tr').nth(2) // CSS + Index

Claude Code generiert Playwright-Locatoren systematisch: Claude bevorzugt getByRole() und getByLabel(), weil diese Tests mit Barrierefreiheits-Semantik koppeln — resilientes gegen UI-Änderungen als CSS-Klassen oder XPath.

3. Component Testing

Component Testing ist 2026 einer der wichtigsten Battlegrounds zwischen Cypress und Playwright. Cypress Component Testing ist production-ready und weit verbreitet. Playwright Component Testing befindet sich noch in der experimentellen Phase.

Cypress Component Testing (CT)

// cypress/component/Button.cy.tsx import React from 'react'; import { mount } from 'cypress/react18'; import { Button } from '../../src/components/Button'; describe('Button Component', () => { it('rendert primären Button korrekt', () => { // mount() rendert Komponente im Cypress-Browser mount( <Button variant="primary" onClick={cy.stub().as('handleClick')} > Klick mich </Button> ); cy.get('button') .should('have.class', 'btn-primary') .and('contain.text', 'Klick mich') .and('not.be.disabled'); }); it('ruft onClick-Handler auf', () => { mount( <Button variant="primary" onClick={cy.stub().as('handleClick')} > Klick </Button> ); cy.get('button').click(); cy.get('@handleClick').should('have.been.calledOnce'); }); it('zeigt Ladezustand', () => { mount(<Button variant="primary" isLoading={true}>Laden</Button>); cy.get('button').should('be.disabled'); cy.get('[data-testid="spinner"]').should('be.visible'); }); });
// cypress.config.ts — Component Testing Konfiguration import { defineConfig } from 'cypress'; import { devServer } from '@cypress/vite-dev-server'; export default defineConfig({ component: { devServer: { framework: 'react', bundler: 'vite', }, specPattern: '**/*.cy.{ts,tsx}', // Automatisches Hot-Module-Replacement während Component Tests supportFile: 'cypress/support/component.ts', }, });

Playwright Component Testing (Experimental)

// playwright-ct.config.ts import { defineConfig } from '@playwright/experimental-ct-react'; export default defineConfig({ testDir: './src', snapshotPathTemplate: '{testDir}/{testFileDir}/__screenshots__/{testFileName}/{arg}{ext}', use: { ctPort: 3100, ctViteConfig: { resolve: { alias: { '@': '/src' }, }, }, }, });
// src/components/Button.spec.tsx (Playwright CT) import { test, expect } from '@playwright/experimental-ct-react'; import { Button } from './Button'; test('rendert primären Button', async ({ mount }) => { const component = await mount( <Button variant="primary">Klick mich</Button> ); await expect(component).toBeVisible(); await expect(component).toHaveClass(/btn-primary/); }); test('Screenshot-Regression für Button-States', async ({ mount, page }) => { await mount(<Button variant="primary">Default</Button>); // Playwright CT kann direkt Screenshots für Visual Regression machen await expect(page).toHaveScreenshot('button-primary.png'); });

Storybook-Integration

// Cypress + Storybook: @storybook/addon-interactions // .storybook/main.ts export default { addons: [ '@storybook/addon-interactions', // Interaktions-Tests in Stories '@storybook/addon-coverage', // Coverage in Storybook ], }; // Button.stories.tsx mit Play-Function (kompatibel mit Cypress CT) export const PrimaryButton: Story = { args: { variant: 'primary', children: 'Test-Button' }, play: async ({ canvasElement }) => { const canvas = within(canvasElement); const button = canvas.getByRole('button'); await userEvent.click(button); await expect(button).toHaveBeenCalled(); }, };
Aspekt Cypress CT Playwright CT
Status Stable, Production-ready Experimental (v1.x)
Frameworks React, Vue, Angular, Svelte React, Vue, Svelte (CT)
Hot Reload Nativ, sehr schnell Über Vite
Visual Regression Via Plugin (percy, applitools) Native Screenshot-Diffs
Storybook-Integration Sehr gut Möglich, weniger native
Empfehlung für Component Testing: Wenn Component Testing ein zentraler Bestandteil deines Workflows ist, ist Cypress 2026 die stabilere Wahl. Claude Code kann Cypress CT-Tests aus vorhandenen React-Komponenten generieren — Claude versteht die mount()-API gut und generiert sinnvolle Stub-Patterns.

4. Network Interception & Mocking

Network Mocking ist für moderne Web-Apps unverzichtbar. Tests, die auf echte APIs angewiesen sind, sind langsam, flaky und nicht deterministisch. Beide Tools bieten mächtiges Network-Mocking — mit unterschiedlichen APIs.

Cypress: cy.intercept

// cypress/e2e/dashboard/products.cy.ts describe('Produkt-Dashboard', () => { // Fixture-basiertes Mocking it('lädt Produkte aus Fixture', () => { cy.intercept('GET', '/api/products', { fixture: 'products.json', }).as('getProducts'); cy.visit('/dashboard/products'); cy.wait('@getProducts'); cy.get('[data-testid="product-card"]').should('have.length', 5); }); // Request-Modifikation: Header hinzufügen it('modifiziert Request-Header', () => { cy.intercept('POST', '/api/products', (req) => { req.headers['x-custom-header'] = 'test-value'; req.continue((res) => { res.body.id = 'mocked-id'; // Response modifizieren }); }).as('createProduct'); cy.get('[data-testid="create-btn"]').click(); cy.wait('@createProduct').its('response.body.id').should('eq', 'mocked-id'); }); // Error-Simulation it('behandelt 500er Server-Fehler', () => { cy.intercept('GET', '/api/products', { statusCode: 500, body: { error: 'Internal Server Error' }, }); cy.visit('/dashboard/products'); cy.get('[data-testid="error-state"]').should('be.visible'); cy.get('[data-testid="retry-button"]').should('exist'); }); // GraphQL Mocking mit cy.intercept it('mockt GraphQL Query', () => { cy.intercept('POST', '/graphql', (req) => { if (req.body.operationName === 'GetProducts') { req.reply({ data: { products: [ { id: '1', name: 'Test-Produkt', price: 29.99 }, ], }, }); } }).as('graphqlProducts'); cy.visit('/products'); cy.wait('@graphqlProducts'); cy.contains('Test-Produkt').should('be.visible'); }); });

Playwright: route.fulfill & route.abort

// tests/e2e/dashboard/products.spec.ts import { test, expect } from '@playwright/test'; import productsFixture from '../../fixtures/products.json'; test.describe('Produkt-Dashboard', () => { // Fixture-basiertes Mocking test('lädt Produkte aus Fixture', async ({ page }) => { await page.route('/api/products', async (route) => { await route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(productsFixture), }); }); await page.goto('/dashboard/products'); await expect(page.getByTestId('product-card')).toHaveCount(5); }); // Request modifizieren und weiterleiten test('modifiziert API-Response', async ({ page }) => { await page.route('/api/products/**', async (route) => { const response = await route.fetch(); // echten Request senden const json = await response.json(); json.id = 'mocked-id'; // Response patchen await route.fulfill({ response, body: JSON.stringify(json) }); }); await page.getByTestId('create-btn').click(); await expect(page.getByTestId('product-id')).toHaveText('mocked-id'); }); // Network-Fehler simulieren test('simuliert Netzwerkfehler', async ({ page }) => { await page.route('/api/products', (route) => { route.abort('connectionrefused'); // Echter Netzwerkfehler }); await page.goto('/dashboard/products'); await expect(page.getByTestId('error-state')).toBeVisible(); }); // GraphQL Mocking test('mockt GraphQL Query', async ({ page }) => { await page.route('/graphql', async (route) => { const body = route.request().postDataJSON(); if (body?.operationName === 'GetProducts') { await route.fulfill({ contentType: 'application/json', body: JSON.stringify({ data: { products: [{ id: '1', name: 'Test-Produkt', price: 29.99 }], }, }), }); } else { await route.continue(); // andere Queries durchlassen } }); await page.goto('/products'); await expect(page.getByText('Test-Produkt')).toBeVisible(); }); // WebSocket Mocking (Playwright-Stärke) test('mockt WebSocket-Nachrichten', async ({ page }) => { page.on('websocket', (ws) => { ws.on('framesent', (frame) => { console.log('WS gesendet:', frame.payload); }); ws.on('framereceived', (frame) => { console.log('WS empfangen:', frame.payload); }); }); await page.goto('/live-chat'); // WebSocket-Verbindung wird jetzt geloggt }); });

Playwright Stärke WebSocket & Service Worker

Playwright kann WebSocket-Events nativ abfangen und auswerten. Cypress hat hier deutliche Einschränkungen — für Chat-Applikationen, Real-time-Dashboards oder Push-Notification-Tests ist Playwright 2026 die bessere Wahl.

5. CI/CD Performance & Parallelisierung

Schnelle CI-Pipelines entscheiden über Developer Experience. Cypress und Playwright bieten unterschiedliche Parallelisierungsstrategien — mit sehr unterschiedlichen Kostenmodellen.

GitHub Actions: Cypress mit Matrix-Parallelisierung

# .github/workflows/cypress.yml name: Cypress E2E Tests on: [push, pull_request] jobs: cypress-run: runs-on: ubuntu-latest strategy: fail-fast: false matrix: containers: [1, 2, 3, 4] # 4 parallele Container steps: - uses: actions/checkout@v4 - name: Cypress run uses: cypress-io/github-action@v6 with: build: npm run build start: npm start wait-on: 'http://localhost:3000' record: true # Cypress Cloud Dashboard parallel: true # Automatische Spec-Verteilung env: CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Upload Artifacts if: failure() uses: actions/upload-artifact@v4 with: name: cypress-screenshots-${{ matrix.containers }} path: cypress/screenshots

GitHub Actions: Playwright mit Sharding

# .github/workflows/playwright.yml name: Playwright E2E Tests on: [push, pull_request] jobs: playwright-test: runs-on: ubuntu-latest strategy: fail-fast: false matrix: shardIndex: [1, 2, 3, 4] shardTotal: [4] steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: '20' cache: 'npm' - run: npm ci - run: npx playwright install --with-deps - name: Run Playwright Tests (Shard) run: > npx playwright test --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }} --reporter=blob - name: Upload blob report if: always() uses: actions/upload-artifact@v4 with: name: blob-report-${{ matrix.shardIndex }} path: blob-report/ retention-days: 1 merge-reports: if: always() needs: playwright-test runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: '20' cache: 'npm' - run: npm ci - name: Download blob reports uses: actions/download-artifact@v4 with: path: all-blob-reports pattern: blob-report-* merge-multiple: true - name: Merge reports run: npx playwright merge-reports --reporter html ./all-blob-reports - uses: actions/upload-artifact@v4 with: name: html-report path: playwright-report/

Flakiness-Handling: Cypress vs Playwright

// Cypress: Retry-Mechanismus (eingebaut) // cypress.config.ts export default defineConfig({ retries: { runMode: 2, // 2 Retries in CI openMode: 0, // Keine Retries im lokalen Dev }, }); // Playwright: Retries + Soft Assertions // playwright.config.ts export default defineConfig({ retries: process.env.CI ? 2 : 0, }); // Soft Assertions in Playwright — Test läuft weiter trotz Fehler test('prüft mehrere Elemente', async ({ page }) => { await page.goto('/dashboard'); // Soft Assert: Fehler wird gesammelt, Test bricht NICHT ab await expect.soft(page.getByTestId('header')).toBeVisible(); await expect.soft(page.getByTestId('sidebar')).toBeVisible(); await expect.soft(page.getByTestId('content')).toBeVisible(); // Am Ende: alle soft Failures werden gemeldet await expect(page.getByTestId('footer')).toBeVisible(); // Hard Assert });
CI/CD Aspekt Cypress Playwright
Parallelisierung Cypress Cloud (kostenpflichtig ab Plan) Sharding nativ, kostenlos
Browser-Download in CI Kleinere CI-Images ~280MB Download pro CI-Run
Reporting Cypress Dashboard (Cloud) HTML-Report, JSON, Allure
Video-Aufnahmen Nativ Nativ (retain-on-failure)
Trace Viewer Screenshots pro Step Vollständiger Trace-Replay
Flakiness Detection Cypress Cloud Analytics Manuell / externe Tools
Docker-Image-Größe cypress/included: ~2GB mcr.microsoft.com/playwright: ~1.8GB
Kostenhinweis: Cypress Parallelisierung mit mehr als 3 parallelen Containern erfordert Cypress Cloud — ab $0/Mo für Open Source, ab $67/Mo für private Repos. Playwright Sharding ist komplett kostenlos und benötigt nur GitHub Actions Compute-Minuten.

6. Wann welches Tool?

Die ehrliche Antwort: Beide Tools sind 2026 excellent. Die Wahl hängt von deinem Kontext ab — App-Typ, Team-Background, Browser-Anforderungen und Budget.

Cypress ist die bessere Wahl wenn...

  • Dein Team TypeScript/JS kennt, aber wenig Testing-Erfahrung hat (flachere Lernkurve)
  • Du Component Testing für React/Vue/Angular produktiv nutzen willst (CT ist stable)
  • Real-time Debugging und Test-Writing-Experience Priorität hat
  • Du bereits Cypress Cloud nutzt und das Dashboard-Reporting schätzt
  • Deine App primär Chromium-basiert getestet werden soll
  • Du Storybook intensiv nutzt und Play-Functions in Stories integrierst

Playwright ist die bessere Wahl wenn...

  • Cross-Browser-Testing (Safari/WebKit) geschäftskritisch ist
  • Multi-Tab, Multi-Window oder Multi-Origin-Szenarien vorkommen
  • WebSocket, Service Worker oder komplexe Auth-Flows (OAuth, SSO) getestet werden
  • Mobile-Emulation mit echtem Device-Fingerprint gebraucht wird
  • Cost-Control Priorität hat (kein Cloud-Abo für Parallelisierung)
  • Das Team bereits mit async/await vertraut ist und TypeScript-first entwickelt

Entscheidungsmatrix

Kriterium Cypress Playwright Empfehlung
App-Typ: SPA (React/Vue) Sehr gut Sehr gut Beide gleichwertig
App-Typ: Multi-Tab App Eingeschränkt Nativ Playwright WINNER
App-Typ: Mobile Web Viewport-only Device-Emulation Playwright WINNER
Browser: Safari/WebKit Nicht verfügbar Full Support Playwright WINNER
Component Testing Stable, Production-ready Experimental Cypress WINNER
Team-Skill: Testing-Neuling Flachere Lernkurve Mehr Konzepte nötig Cypress WINNER
Team-Skill: TS-Experte Gut, Command Queue OK async/await nativ Playwright WINNER
Budget: Cloud-Kosten Kostenpflichtig ab Parallelisierung Sharding kostenlos Playwright WINNER
Reporting & Dashboard Cypress Cloud HTML-Report (lokal) Cypress WINNER
Network/WebSocket Mocking cy.intercept (gut) route.fulfill (mächtiger) Playwright WINNER
Claude Code Integration Sehr gut Sehr gut Beide gleichwertig

Claude Code + Playwright: Praktisches Beispiel

Claude Code generiert auf Basis von Page-Source und bestehenden Komponenten automatisch typsichere Playwright-Tests. So sieht ein typischer Claude-Code-generierter Test aus:

// Von Claude Code generiert — typisches Pattern // Eingabe an Claude: "Erstelle einen E2E-Test für den Checkout-Flow" import { test, expect } from '@playwright/test'; test.describe('Checkout-Flow', () => { test.beforeEach(async ({ page }) => { // Auth-State wiederverwenden (Playwright storageState) await page.goto('/shop'); }); test('vollständiger Checkout-Prozess', async ({ page }) => { // Produkt in Warenkorb legen await page.getByTestId('product-1').getByRole('button', { name: 'In den Warenkorb', }).click(); await expect(page.getByTestId('cart-count')).toHaveText('1'); // Checkout starten await page.getByRole('link', { name: 'Zur Kasse' }).click(); await expect(page).toHaveURL(/.*checkout/); // Lieferadresse ausfüllen await page.getByLabel('Vorname').fill('Max'); await page.getByLabel('Nachname').fill('Mustermann'); await page.getByLabel('Straße').fill('Musterstraße 1'); await page.getByLabel('PLZ').fill('10115'); await page.getByLabel('Stadt').fill('Berlin'); // Zahlungsmethode wählen (API gemockt) await page.route('/api/payment/process', (route) => { route.fulfill({ status: 200, body: JSON.stringify({ orderId: 'ORDER-2026-001', status: 'success' }), }); }); await page.getByRole('radio', { name: 'Kreditkarte' }).check(); await page.getByRole('button', { name: 'Jetzt kaufen' }).click(); // Bestellbestätigung prüfen await expect(page).toHaveURL(/.*order-confirmation/); await expect(page.getByTestId('order-id')) .toContainText('ORDER-2026-001'); }); });

Fazit für Claude Code Nutzer: Wähle Playwright als Standard-E2E-Framework für neue Projekte — es ist open-source, kostenlos parallelisierbar, cross-browser und async/await-nativ. Setze Cypress ein, wenn Component Testing ein zentrales Requirement ist oder dein Team visuelles Real-time-Debugging schätzt. Claude Code unterstützt beide hervorragend — der Unterschied liegt in deinem Projekt, nicht in Claude.

E2E-Testing-Modul im Kurs

Im Claude Code Mastery Kurs: vollständiges E2E-Testing-Modul mit Cypress und Playwright — inkl. Component Testing, CI/CD und Mocking-Strategien.

14 Tage kostenlos testen →