Advanced (Atualizado: 03/06/2026)

Testes E2E com Claude Code e Playwright em produção

Use Claude Code e Playwright para E2E, mobile screenshots, auth state, Trace Viewer, seletores e retries no CI.

Testes E2E com Claude Code e Playwright em produção

Pedir ao Claude Code “adicione testes Playwright” não basta para proteger um site em produção. O resultado pode passar uma vez, mas depender de classes CSS frágeis, refazer login em cada teste, ignorar screenshots mobile e não deixar uma trace útil quando o CI falhar.

Use o Claude Code como parceiro de desenho de testes. Você define riscos de negócio, rotas, regras de seletores e comando de validação; ele lê o projeto e propõe configuração Playwright e specs. Este guia cobre fluxos de monetização, mobile screenshots, QA de blocos de código, estado autenticado, Trace Viewer, retries no CI e como evitar testes flaky.

Use as fontes oficiais como base: Claude Code overview, Claude Code common workflows, e no Playwright Locators, Authentication, Screenshots, Trace Viewer, Retries e CI. No ClaudeCodeLab, complemente com estratégia de testes, CI/CD setup e design responsivo.

Escolha os fluxos certos

E2E abre um navegador real, então deve proteger o que unit tests não provam.

Caso de usoO que protegeProva no Playwright
Artigo para produtosO leitor chega a /products/CTA, URL, toque no mobile
Dashboard autenticadoUsuário logado acessa páginas protegidasstorageState, redirects, permissões
Layout de artigo técnicoCódigo e tabelas não quebram no mobileScreenshot mobile, sem overflow, trace
flowchart LR
  A["Fluxo de receita ou cadastro"] --> B["Playwright E2E"]
  C["Risco de layout mobile"] --> B
  D["Validação pura"] --> E["Unit tests"]
  F["Fronteira API ou componente"] --> G["Integration tests"]

Em um site monetizado, CTA escondido no mobile, código que alarga a página ou área paga fora do CI são problemas pequenos que afetam conversão e confiança.

Dê limites claros ao Claude Code

O prompt deve trazer rotas, seletores aceitos, arquivos permitidos e comando de prova.

Leia o site Astro existente e adicione testes E2E com Playwright.

Objetivos:
- Verificar que `/pt/blog/claude-code-playwright-testing/` leva a `/products/` e `/training/`
- Checar em 390px mobile que artigo, tabelas e blocos de código não têm overflow horizontal
- Usar `storageState` para testes autenticados, sem login por UI em cada teste
- No CI usar 2 retries e `trace: "on-first-retry"`

Restrições:
- Não usar `page.waitForTimeout()`
- Preferir role, label, text ou test id a cadeias de classes CSS
- Alterar apenas `playwright.config.ts` e `tests/e2e/**`
- Executar `npx playwright test` e explicar falhas com Trace Viewer

Na revisão, pergunte se o teste falha por um problema real de usuário e se o diagnóstico será possível.

Configuração copiável

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'] : [],
    },
  ],
});

Localmente, retry desligado deixa o erro visível. No CI, retry só é útil junto com trace, screenshots e HTML report.

Salve o estado autenticado

Não faça login pela UI em todo teste. storageState salva cookies e localStorage de um usuário de teste para reutilizar. Mantenha playwright/.auth fora do git.

// 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 });
});

Peça ao Claude Code para separar testes do login de testes que apenas precisam estar autenticados. Isso reduz falhas em cascata.

QA mobile e blocos de código

Artigos técnicos quebram por linhas longas, tabelas e imagens. Este spec valida CTAs, captura mobile e falha se houver overflow horizontal.

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

const articlePath = process.env.ARTICLE_PATH ?? '/pt/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);
  });
});

Screenshot ajuda na revisão humana; a asserção numérica decide no CI.

Proteja CTAs de receita e treinamento

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

const articlePath = process.env.ARTICLE_PATH ?? '/pt/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/);
  });
});

Em sites multilíngues, o texto muda. Para ações críticas, use href estável ou data-testid com significado de negócio.

Seletores menos flaky

PrioridadeSeletorExemploMotivo
AltaRole e nomepage.getByRole('button', { name: /save/i })Próximo da experiência acessível
AltaLabelpage.getByLabel(/email/i)Valida semântica do formulário
MédiaTextopage.getByText(/Start trial/)Claro, mas depende do copy
MédiaTest idpage.getByTestId('checkout-submit')Bom para ação de negócio estável
BaixaEstrutura CSS.card:nth-child(3)Quebra com layout

Evite page.waitForTimeout(). Use toBeVisible(), toHaveURL() e toContainText() para aguardar condições reais.

Depure com Trace Viewer

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

Ao devolver uma falha ao Claude Code, inclua nome do teste, estado visual na trace e comportamento esperado. Isso evita soluções baseadas apenas em aumentar timeout.

CI com retries e artefatos

# .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

Retry não cura teste flaky; ele classifica e deixa evidência.

Armadilhas comuns

A primeira é testar tudo com E2E. Cálculos, validações e permissões pequenas cabem melhor em unit ou integration tests.

A segunda é commitar estado autenticado. Use usuários de teste limitados e exclua playwright/.auth.

A terceira é esconder instabilidade com retry. Se só passa no retry, ainda é risco.

A quarta é pedir correções amplas ao Claude Code. Adicione o teste que falha, leia a trace e faça a menor correção de produto.

Para começar sozinho, use os templates em products. Para equipes, training ajuda a alinhar review, CI e onboarding.

Testei esse fluxo em uma página local no estilo ClaudeCodeLab: screenshot em 390px, overflow de blocos de código, navegação para /products/ e /training/, e retries no CI. As primeiras falhas úteis não eram do Playwright, mas linhas de código longas e nomes de links ambíguos. Depois da correção, Trace Viewer virou uma evidência concreta para o próximo prompt no Claude Code.

#Claude Code #Playwright #testes E2E #automação de testes #qualidade
Grátis

PDF grátis: cheatsheet do Claude Code

Informe seu e-mail e baixe uma página com comandos, hábitos de revisão e workflows seguros.

Cuidamos dos seus dados e não enviamos spam.

Masa

Sobre o autor

Masa

Engenheiro focado em workflows práticos com Claude Code.