Advanced (Aktualisiert: 3.6.2026)

E2E-Tests mit Claude Code und Playwright produktionsreif einführen

Plane Playwright-E2E mit Claude Code: Mobile Screenshots, Auth State, Trace Viewer, Selektoren und CI-Retries.

E2E-Tests mit Claude Code und Playwright produktionsreif einführen

Claude Code nur mit “füge Playwright-Tests hinzu” zu beauftragen, reicht für Produktion nicht aus. Häufig entstehen Tests, die einmal laufen, aber an CSS-Klassen hängen, jedes Mal den Login durchklicken, keine Mobile-Screenshots speichern und bei CI-Fehlern keine verwertbare Trace hinterlassen.

Praktischer ist es, Claude Code als Partner für Testdesign zu nutzen. Du definierst Geschäftsrisiken, Routen, Selektorregeln und den Verifikationsbefehl; Claude Code liest das Projekt und ergänzt Playwright-Konfiguration und Specs. Dieser Leitfaden deckt E2E für Monetarisierungspfade, Mobile-Layout, Codeblöcke, Auth State, Trace Viewer, CI-Retries und weniger flaky Tests ab.

Als Basis dienen die offiziellen Quellen: Claude Code overview, Claude Code common workflows sowie Playwright zu Locators, Authentication, Screenshots, Trace Viewer, Retries und CI. In ClaudeCodeLab passen dazu Teststrategie, CI/CD Setup und Responsive Design.

Schütze die richtigen Flows

E2E startet echte Browser und ist langsamer als Unit Tests. Es sollte daher Verhalten schützen, das nur im Browser wirklich belegbar ist.

Use CaseWas geschützt wirdPlaywright-Beleg
Artikel zu ProduktenLeser erreichen /products/CTA, URL, Mobile-Tap
Eingeloggt zum DashboardAuthentifizierte Nutzer erreichen geschützte SeitenstorageState, Redirects, Rollen
Layout technischer ArtikelCodeblöcke und Tabellen sprengen Mobile nichtMobile Screenshot, kein Overflow, Trace
flowchart LR
  A["Umsatz- oder Signup-Pfad"] --> B["Playwright E2E"]
  C["Mobile Layout Risiko"] --> B
  D["Reine Validierung"] --> E["Unit Tests"]
  F["API- oder Komponenten-Grenze"] --> G["Integration Tests"]

Für monetarisierte Inhalte sind versteckte CTAs, zu breite Codezeilen oder ungetestete Käuferseiten keine kosmetischen Probleme. Sie kosten Vertrauen und Conversion.

Claude Code präzise briefen

Der Prompt sollte Zielrouten, erlaubte Selektoren, ausführbare Befehle und erlaubte Dateien enthalten.

Lies die bestehende Astro-Site und ergänze Playwright-E2E-Tests.

Ziele:
- Prüfe, dass `/de/blog/claude-code-playwright-testing/` zu `/products/` und `/training/` führt
- Prüfe bei 390px Mobile-Breite, dass Artikel, Tabellen und Codeblöcke nicht horizontal überlaufen
- Nutze `storageState` für authentifizierte Tests, statt jedes Mal über die UI einzuloggen
- In CI 2 Retries und `trace: "on-first-retry"` verwenden

Einschränkungen:
- Kein `page.waitForTimeout()`
- Role, Label, Text oder Test-ID vor CSS-Klassenketten
- Nur `playwright.config.ts` und `tests/e2e/**` ändern
- `npx playwright test` ausführen und Fehler mit Trace Viewer erklären

Beim Review zählt nicht die Anzahl erzeugter Dateien, sondern ob ein Fehler erklärbar ist und ob der Test ein echtes Nutzerproblem abbildet.

Kopierbare Grundkonfiguration

cd site
npm i -D @playwright/test
npx playwright install
mkdir tests/e2e
// playwright.config.ts
import { defineConfig, devices } from '@playwright/test';

const baseURL = process.env.BASE_URL ?? 'http://127.0.0.1:4321';
const hasAuth = Boolean(process.env.TEST_EMAIL && process.env.TEST_PASSWORD);
const authFile = 'playwright/.auth/user.json';

export default defineConfig({
  testDir: './tests/e2e',
  timeout: 30_000,
  expect: { timeout: 5_000 },
  fullyParallel: true,
  forbidOnly: Boolean(process.env.CI),
  retries: process.env.CI ? 2 : 0,
  workers: process.env.CI ? 2 : undefined,
  reporter: process.env.CI ? [['html'], ['github']] : 'html',
  use: {
    baseURL,
    trace: 'on-first-retry',
    screenshot: 'only-on-failure',
    video: 'retain-on-failure',
  },
  ...(process.env.PLAYWRIGHT_WEB_SERVER === '1'
    ? {
        webServer: {
          command: 'npm run preview -- --host 127.0.0.1 --port 4321',
          url: baseURL,
          reuseExistingServer: !process.env.CI,
          timeout: 120_000,
        },
      }
    : {}),
  projects: [
    ...(hasAuth
      ? [
          {
            name: 'setup',
            testMatch: /.*\.setup\.ts/,
          },
        ]
      : []),
    {
      name: 'desktop-chrome',
      use: {
        ...devices['Desktop Chrome'],
        storageState: hasAuth ? authFile : undefined,
      },
      dependencies: hasAuth ? ['setup'] : [],
    },
    {
      name: 'mobile-safari',
      use: {
        ...devices['iPhone 13'],
        storageState: hasAuth ? authFile : undefined,
      },
      dependencies: hasAuth ? ['setup'] : [],
    },
  ],
});

Lokal bleiben Retries aus, damit Fehler sichtbar bleiben. In CI sind Retries sinnvoll, wenn gleichzeitig Trace, Screenshot und Report gesichert werden.

Auth State speichern

Jeder Test sollte nicht erneut über die Login-UI laufen. Das ist langsam und fragil. storageState speichert Cookies und Local Storage eines Testnutzers. playwright/.auth gehört in .gitignore.

// tests/e2e/auth.setup.ts
import { test as setup, expect } from '@playwright/test';
import fs from 'node:fs';
import path from 'node:path';

const authFile = path.resolve('playwright/.auth/user.json');
const email = process.env.TEST_EMAIL;
const password = process.env.TEST_PASSWORD;

setup('save signed-in browser state', async ({ page }) => {
  setup.skip(!email || !password, 'Set TEST_EMAIL and TEST_PASSWORD to record auth state.');

  await page.goto('/login');
  await page.getByLabel(/email|メール|e-mail/i).fill(email!);
  await page.getByLabel(/password|パスワード/i).fill(password!);
  await page.getByRole('button', { name: /log in|sign in|ログイン/i }).click();

  await expect(page).toHaveURL(/dashboard|account|admin/);
  await expect(page.locator('body')).toBeVisible();

  fs.mkdirSync(path.dirname(authFile), { recursive: true });
  await page.context().storageState({ path: authFile });
});

Bitte Claude Code, Login-Tests und bereits authentifizierte Feature-Tests zu trennen. Dann bricht nicht die ganze Suite, nur weil ein Login-Label geändert wurde.

Mobile Screenshots und Codeblöcke testen

Technische Artikel brechen oft durch lange Codezeilen, Tabellen oder eingebettete Medien. Dieser Spec prüft CTAs, speichert einen Mobile-Screenshot und schlägt bei horizontalem Overflow fehl.

// tests/e2e/article-quality.spec.ts
import { test, expect } from '@playwright/test';

const articlePath = process.env.ARTICLE_PATH ?? '/de/blog/claude-code-playwright-testing/';

test.describe('article quality checks', () => {
  test('article has monetization CTAs', async ({ page }) => {
    await page.goto(articlePath);

    await expect(page.getByRole('heading', { level: 1 })).toContainText(/Playwright|E2E|Claude Code/i);
    await expect(page.locator('a[href="/products/"], a[href="/products"]').first()).toBeVisible();
    await expect(page.locator('a[href="/training/"], a[href="/training"]').first()).toBeVisible();
  });

  test('mobile layout has no horizontal overflow', async ({ page }, testInfo) => {
    await page.setViewportSize({ width: 390, height: 844 });
    await page.goto(articlePath);
    await expect(page.locator('main, article').first()).toBeVisible();

    const overflow = await page.evaluate(() => ({
      viewport: window.innerWidth,
      documentWidth: document.documentElement.scrollWidth,
      offenders: Array.from(document.querySelectorAll('pre, table, img, iframe, .prose'))
        .filter((node) => {
          const rect = node.getBoundingClientRect();
          return rect.left < -1 || rect.right > window.innerWidth + 1;
        })
        .map((node) => {
          const rect = node.getBoundingClientRect();
          return `${node.tagName.toLowerCase()} ${Math.round(rect.left)}-${Math.round(rect.right)}`;
        }),
    }));

    expect(overflow.documentWidth, JSON.stringify(overflow)).toBeLessThanOrEqual(overflow.viewport + 2);
    expect(overflow.offenders).toEqual([]);
    await page.screenshot({ path: testInfo.outputPath('article-mobile.png'), fullPage: true });
  });

  test('code examples are present and copyable', async ({ page }) => {
    await page.goto(articlePath);

    const blocks = page.locator('pre code');
    await expect(blocks.first()).toBeVisible();
    expect(await blocks.count()).toBeGreaterThanOrEqual(3);
    await expect(blocks.nth(0)).toContainText(/playwright|defineConfig|test/i);
  });
});

Der Screenshot hilft im Review, die numerische Overflow-Prüfung im CI-Gate.

Umsatz- und Lern-CTAs schützen

// tests/e2e/revenue-flows.spec.ts
import { test, expect } from '@playwright/test';

const articlePath = process.env.ARTICLE_PATH ?? '/de/blog/claude-code-playwright-testing/';

test.describe('revenue and learning flows', () => {
  test('reader can move from article to products', async ({ page }) => {
    await page.goto(articlePath);

    await page.locator('a[href="/products/"], a[href="/products"]').first().click();
    await expect(page).toHaveURL(/\/products\/?$/);
    await expect(page.locator('main').first()).toBeVisible();
  });

  test('training CTA is reachable on mobile', async ({ page }) => {
    await page.setViewportSize({ width: 390, height: 844 });
    await page.goto(articlePath);

    await page.locator('a[href="/training/"], a[href="/training"]').first().click();
    await expect(page).toHaveURL(/\/training\/?$/);
    await expect(page.locator('main').first()).toBeVisible();
  });

  test('main navigation can open the blog index', async ({ page }) => {
    await page.goto('/');

    await expect(page.getByRole('navigation').first()).toBeVisible();
    await page.getByRole('link', { name: /blog|記事|articles/i }).first().click();
    await expect(page).toHaveURL(/blog/);
  });
});

Auf mehrsprachigen Sites ändern sich CTA-Texte. Für kritische Aktionen sind stabile hrefs oder fachliche data-testids sinnvoll.

Stabilere Selektoren

PrioritätSelektorBeispielWarum
HochRole und Namepage.getByRole('button', { name: /save/i })Nah an Nutzer- und Accessibility-Sicht
HochLabelpage.getByLabel(/email/i)Prüft Formularsemantik
MittelTextpage.getByText(/Start trial/)Verständlich, aber copy-abhängig
MittelTest-IDpage.getByTestId('checkout-submit')Stabil für Business-Aktionen
NiedrigCSS-Struktur.card:nth-child(3)Layoutänderungen brechen den Test

Vermeide page.waitForTimeout(). Nutze toBeVisible(), toHaveURL() und toContainText(), damit Playwright echte Bedingungen abwartet.

Fehler mit Trace Viewer verstehen

npx playwright test --trace on
npx playwright show-report
npx playwright show-trace test-results/path-to-trace/trace.zip

Gib Claude Code bei Fehlern den Testnamen, den sichtbaren Trace-Zustand und das erwartete Nutzerverhalten. Das führt eher zu besseren Selektoren oder Daten-Setup als zu blind erhöhten Timeouts.

CI mit Retries und Artefakten

# .github/workflows/playwright.yml
name: Playwright E2E

on:
  pull_request:
  push:
    branches: [main]

jobs:
  e2e:
    runs-on: ubuntu-latest
    timeout-minutes: 15
    defaults:
      run:
        working-directory: site
    env:
      BASE_URL: http://127.0.0.1:4321
      PLAYWRIGHT_WEB_SERVER: "1"
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: npm
          cache-dependency-path: site/package-lock.json
      - run: npm ci
      - run: npx playwright install --with-deps
      - run: npm run build
      - run: npx playwright test
      - uses: actions/upload-artifact@v4
        if: always()
        with:
          name: playwright-report
          path: site/playwright-report
          retention-days: 7

Retries reparieren keine flaky Tests. Sie klassifizieren sie und erzeugen Belege, die geprüft werden müssen.

Häufige Fallen

Erstens: alles als E2E testen. Berechnungen, Validierungen und kleine Rechteprüfungen gehören meist in Unit- oder Integrationstests.

Zweitens: Auth State committen. Nutze begrenzte Testnutzer und schließe playwright/.auth aus.

Drittens: Instabilität mit Retries verstecken. Ein Test, der nur im Retry passt, bleibt ein Risiko.

Viertens: Claude Code ohne Änderungsgrenze arbeiten lassen. Besser ist: fehlschlagenden Test ergänzen, Trace ansehen, kleinste Produktkorrektur umsetzen.

Für Self-Service nutze die ClaudeCodeLab products Vorlagen. Für Teams helfen training und gemeinsame Regeln für Review, CI und Onboarding.

Ich habe diesen Ablauf an einer lokalen ClaudeCodeLab-artigen Artikelseite geprüft: 390px Screenshot, Codeblock-Overflow, Navigation zu /products/ und /training/, sowie CI-Retry-Konfiguration. Die ersten nützlichen Fehler lagen nicht in Playwright, sondern in zu langen Codezeilen und unklaren Linknamen. Nach der Korrektur wurde Trace Viewer zu einem brauchbaren Nachweis für den nächsten Claude-Code-Prompt.

#Claude Code #Playwright #E2E-Tests #Testautomatisierung #Qualitätssicherung
Kostenlos

Kostenloses PDF: Claude-Code-Cheatsheet

E-Mail eintragen und eine Seite mit Befehlen, Review-Gewohnheiten und sicheren Workflows herunterladen.

Wir schützen Ihre Daten und senden keinen Spam.

Masa

Über den Autor

Masa

Engineer für praktische Claude-Code-Workflows und Team-Einführung.