AgentSkillsCN

test-e2e-playwright

分析E2E Playwright测试,对照现代架构、定位器、同步与隔离的最佳实践进行评估。识别脆弱的定位器、固定的等待时间、POM违规与资源泄漏等反模式。根据严重程度给予相应扣分,计算0–10的量化得分。在审计Web应用、React、Next.js或Electron中E2E Playwright/TypeScript测试质量时使用。

SKILL.md
--- frontmatter
name: test-e2e-playwright
description: Analisa testes E2E Playwright contra best practices modernas de arquitetura, locatores, sincronização e isolamento. Detecta anti-padrões como seletores frágeis, esperas fixas, violações de POM e vazamento de recursos. Calcula score quantitativo 0-10 com penalidades por severidade. Use quando auditar qualidade de testes E2E Playwright/TypeScript em aplicações web, React, Next.js ou Electron.

Test E2E Playwright Analyzer

Skill para análise de qualidade de testes E2E com Playwright, focada em manutenibilidade, confiabilidade e resiliência de longo prazo.

Purpose

Analisar testes E2E Playwright contra best practices modernas, identificando anti-padrões que comprometem a manutenibilidade e a confiabilidade da suíte. Calcular score quantitativo e fornecer recomendações acionáveis.

When to Use

Invocar esta skill quando:

  • Auditar qualidade de testes E2E Playwright existentes
  • Revisar code review de PRs com testes Playwright
  • Diagnosticar problemas de manutenibilidade em suítes de testes
  • Validar aderência a padrões arquiteturais de automação
  • Preparar métricas de saúde de testes E2E

Sinais de Teste Playwright

Um teste é reconhecido como Playwright E2E quando apresenta:

  • Importa de @playwright/test
  • Usa page.locator(), getByRole(), getByText(), getByLabel()
  • Extende PageObject ou usa test.extend()
  • Usa expect(page).toHaveURL(), waitForLoadState(), waitForResponse()

Workflow de Análise

1. Identificação e Leitura Skim-First

Antes de ler código completo, aplicar token economy:

  • Ler apenas imports e assinaturas de teste
  • Identificar camada e tipo (web, electron, mobile)
  • Verificar presença de fixtures vs hooks tradicionais

2. Checklist por Categoria

Aplicar checklists abaixo em ordem de severidade. Documentar violações com ID acadêmico, linha e mensagem.

Arquitetura e Camadas

IDRegraSeveridadeVerificação
[PW-ARCH-01]Separação em 3 camadas: Core, Business, DataCRITICALVerificar estrutura de diretórios e organização de arquivos
[PW-ARCH-02]Page Objects via fixtures (não hooks)CRITICALBuscar test.extend() e fixtures customizadas
[PW-ARCH-03]Seletores isolados dos arquivos .spec.tsCRITICALArquivos .spec não devem conter page.locator()
[PW-ARCH-04]TypeScript com tipagem estritaHIGHVerificar imports de tipos e interfaces
[PW-ARCH-05]storageState para reuso de autenticaçãoHIGHVerificar uso de storageState em fixtures

Locadores e Seleção

IDRegraSeveridadeVerificação
[PW-LOC-01]Usar getByRole como prioridade absolutaCRITICALBuscar padrões de locadores usados
[PW-LOC-02]getByLabel para formulários e inputsHIGHVerificar formulários
[PW-LOC-03]getByText para validação de conteúdoHIGHVerificar asserções de texto
[PW-LOC-04]data-testid apenas para elementos sem semânticaMEDIUMUsar quando getByRole não é possível
[PW-LOC-05]Proibir seletores CSS frágeis (.css-xyz, nth-child)CRITICALBuscar .css-, :nth-child(), seletores compostos
[PW-LOC-06]Strict Mode: locator resolve para 1 elementoHIGHVerificar filtros e especificidade

Sincronização e Esperas

IDRegraSeveridadeVerificação
[PW-SYNC-01]Asserções Web-First expect().toBeVisible()CRITICALBuscar padrões de asserção
[PW-SYNC-02]Proibir waitForTimeout (esperas fixas)CRITICALBuscar waitForTimeout no código
[PW-SYNC-03]Aguardar hidratação React/Next.js concluídaHIGHVerificar Next.js específico
[PW-SYNC-04]Monitoramento de rede para dados dinâmicosHIGHBuscar waitForResponse, page.route()
[PW-SYNC-05]Proibir force: true em cliquesHIGHBuscar click({ force: true })
[PW-SYNC-06]Usar waitForResponse/page.route() para APIsMEDIUMVerificar mocks de APIs externas

Isolamento e Estado

IDRegraSeveridadeVerificação
[PW-ISO-01]Cada teste independente (sem dependência)CRITICALVerificar ordem de execução
[PW-ISO-02]Contextos de Browser isoladosCRITICALBuscar browser.newContext()
[PW-ISO-03]Mock APIs externas via page.route()HIGHVerificar APIs de terceiros
[PW-ISO-04]Limpeza adequada de recursos (teardown)HIGHBuscar afterEach, afterAll

Electron Específico (quando aplicável)

IDRegraSeveridadeVerificação
[PW-EL-01]electronApp.evaluate() para Main ProcessCRITICALBuscar interações com Main
[PW-EL-02]Aguardar electronApp.firstWindow()CRITICALVerificar inicialização
[PW-EL-03]Validar comunicação IPCHIGHBuscar handlers IPC
[PW-EL-04]Monitorar novas janelas via on('window')HIGHVerificar multi-janela
[PW-EL-05]Encerrar explicitamente com electronApp.close()CRITICALBuscar teardown

3. Taxonomia de Test Smells

CRITICAL (-2 pontos cada)

IDNomeDescriçãoPadrão de Detecção
[PW-CRIT-01]Fragile SelectorUsa CSS/XPath ao invés de getByRole/getByTextpage.locator('.css-'), page.locator('div > span')
[PW-CRIT-02]Hardcoded WaitUsa waitForTimeout com tempo fixoawait page.waitForTimeout(5000)
[PW-CRIT-03]Architecture ViolationSeletores/lógica de página no .spec.ts.spec.ts com page.locator()
[PW-CRIT-04]Force ClickUsa click({ force: true }) mascarando problemasclick({ force: true })
[PW-CRIT-05]Electron Teardown LeakNão executa electronApp.close()Falta afterAll com close

HIGH (-1 ponto cada)

IDNomeDescriçãoPadrão de Detecção
[PW-HIGH-01]Missing Web-First AssertionsNão usa expect().toBeVisible() com auto-retryexpect(element).toBe(x) sem await
[PW-HIGH-02]Framework CSS SelectorSeletores .css-xyz que mudam a cada build.css-[0-9a-z]+
[PW-HIGH-03]Hydration RaceInterage antes de React/Next.js hidratarInteração imediada após navegação
[PW-HIGH-04]Shared StateTeste depende de estado de teste anteriorTestes B dependem de A
[PW-HIGH-05]No StorageStateRepete login em cada testeLogin repetido sem storageState
[PW-HIGH-06]Missing Strict ModeLocator ambíguo sem filtro específicoLocator retorna múltiplos

MEDIUM (-0.5 ponto cada)

IDNomeDescriçãoPadrão de Detecção
[PW-MED-01]Static FixtureDados hard-coded ao invés de factoriesObjetos literais em variáveis
[PW-MED-02]Weak LocatorgetByTestId quando getByRole seria possívelgetByTestId com role disponível
[PW-MED-03]Missing Network MockChama API externa real ao invés de mockfetch() para APIs externas
[PW-MED-04]Generic Error Handlertry-catch que silencia falhastry {} catch {} vazio

4. Cálculo de Score

Fórmula por Arquivo

code
Score do arquivo = max(0, 10 - soma_penalidades)

Ponderação por Categoria (score agregado)

code
Score Final = 0.4*Locatores + 0.3*Sincronização + 0.2*Arquitetura + 0.1*Isolamento

Onde cada categoria é calculada individualmente usando a mesma fórmula de penalidades.

Classificação de Saúde

  • 8.0 - 10.0: Excelente - Suíte saudável, follow best practices
  • 6.0 - 7.9: Bom - Algumas melhorias necessárias
  • 4.0 - 5.9: Regular - Vários anti-padrões, refatoração recomendada
  • 2.0 - 3.9: Ruim - Críticos violados, atenção urgente
  • 0.0 - 1.9: Crítico - Suíte em risco alto de manutenibilidade

5. Output Format

Retornar relatório estruturado em JSON:

json
{
  "summary": {
    "total_files": 10,
    "overall_score": 7.2,
    "health_level": "Bom",
    "critical_issues": 5,
    "high_issues": 12,
    "medium_issues": 8
  },
  "files": [
    {
      "path": "tests/e2e/login.spec.ts",
      "layer": "E2E",
      "score": 8.5,
      "category_scores": {
        "locators": 9.0,
        "synchronization": 8.0,
        "architecture": 9.0,
        "isolation": 8.0
      },
      "issues": [
        {
          "id": "PW-LOC-04",
          "severity": "MEDIUM",
          "line": 15,
          "msg": "getByTestId usado quando getByRole seria possível",
          "code": "page.getByTestId('submit-btn')"
        }
      ],
      "smells": ["PW-MED-02"],
      "recommendation": "Substituir getByTestId por getByRole('button', { name: 'Entrar' })"
    }
  ],
  "aggregate_issues": {
    "PW-LOC-05": { "count": 5, "severity": "CRITICAL", "description": "Seletores CSS frágeis" },
    "PW-SYNC-02": { "count": 3, "severity": "CRITICAL", "description": "Esperas fixas" }
  }
}

Anti-padrões: Certo vs. Errado

Referência rápida para análise:

CategoriaAnti-padrão ❌Prática de Excelência ✅
Locadorespage.locator('.container > div:nth-child(2)')page.getByRole('button', { name: 'Enviar' })
Sincronismoawait page.waitForTimeout(5000)await expect(page.getByText('Carregado')).toBeVisible()
ArquiteturaSeletores dentro do .spec.tsPOM injetado via fixtures
AutenticaçãoRepete login a cada testestorageState com cookies reutilizados
IsolamentoTeste B depende do teste ACada teste com seu próprio context
External APIsawait fetch('https://api-pagamento.com')page.route('**/api/**', mockHandler)
ElectronInteração sem aguardar windowawait electronApp.firstWindow()
Tratamento de Errostry { ... } catch (e) {}expect.soft() com traces detalhados

Referências Adicionais

Para análise profunda de arquitetura ou casos específicos, consultar:

  • references/playwright-best-practices.md - Guia completo de práticas recomendadas
  • references/electron-automation.md - Específico para aplicações Electron