Matware E2E Runner

Executor de testes E2E orientado por JSON com execução paralela em pool do Chrome, verificação visual e 16 ferramentas MCP.

Documentação

English · Español

@matware/e2e-runner

O executor de testes E2E nativo para IA que escreve, executa e depura testes para você.

npm version node version npm downloads Docker pulls GitHub stars license MCP compatible AI native OpenCode compatible Agent Skills


E2E Runner permite testar seu aplicativo web sem escrever código de teste. Os testes são JSON puro — e você nem precisa escrever isso: basta pedir ao Claude Code.

🎬 Escreva um teste pedindo — e veja-o rodar

Live dashboard streaming screenshots as a test suite runs
O painel ao vivo enquanto uma suíte é executada — cada etapa transmite uma captura de tela no feed, em tempo real.

Com o servidor MCP integrado, criar um teste é uma conversa — sem documentação, sem sintaxe para memorizar:

Você: Crie um teste E2E para o fluxo de login e execute-o.

Claude Code: escreve o teste, executa-o em um navegador real e reporta —login-flow passou em 2,3s · captura de tela salva · sem erros de rede.

Nos bastidores, o Claude acabou de escrever e executar isso. Um teste é apenas JSON — uma lista ordenada do que um usuário faz:

[
  { "name": "login-flow", "actions": [
    { "type": "goto", "value": "/login" },
    { "type": "type", "selector": "#email", "value": "user@test.com" },
    { "type": "type", "selector": "#password", "value": "secret" },
    { "type": "click", "text": "Sign In" },
    { "type": "assert_text", "text": "Welcome back" },
    { "type": "screenshot", "value": "logged-in.png" }
  ]}
]

Sem imports, sem describe/it, sem etapa de build. Se você consegue ler, consegue escrever — ou apenas peça.

Conecte-o ao Claude Code (2 comandos):

claude plugin marketplace add fastslack/mtw-e2e-runner
claude plugin install e2e-runner@matware

Agora diga "crie um teste para X e execute-o" — o Claude obtém 17 ferramentas MCP, comandos de barra e agentes especializados.

Usando um agente diferente (Cursor, Codex, Copilot, mais de 40)? Instale a skill: npx skills add fastslack/mtw-e2e-runner


📖 Conteúdo

SeçãoO que contém
🚀Instalação & primeiro testeconfiguração npm · execute com seu próprio Chrome (sem Docker), Obscura ou um pool Docker
O que você obtémvisão geral dos recursos de relance
✍️Escrevendo testesformato de teste · catálogo completo de ações · tentativas · serial · módulos · autenticação · hooks
🤖Integração com IAClaude Code · OpenCode · 17 ferramentas MCP · verificação visual · issue-para-teste
📊Painel & insightspainel ao vivo · sistema de aprendizado · logs de rede · captura de tela
🌐Drivers de navegadorbrowserless · cdp · lightpanda · obscura · steel
⚙️CLI, configuração & CIcomandos · flags · e2e.config.js · GitHub Actions · API programática

🚀 Instalação — é minúsculo

npm install --save-dev @matware/e2e-runner
npx e2e-runner init        # scaffolds e2e/ with a sample test + config

Depois escolha como executar o navegador. Você não precisa de Docker a menos que queira o pool paralelo:

Opção 1 · Use o Chrome que você já tem — sem Docker ⭐

Inicie qualquer navegador Chromium com uma porta de depuração e aponte o executor para ele:

google-chrome --headless=new --remote-debugging-port=9222 &   # or brave / chromium / msedge
CHROME_POOL_URL=http://localhost:9222 POOL_DRIVER=cdp npx e2e-runner run --all

Ou coloque no e2e.config.js para nunca repetir:

export default {
  baseUrl: 'http://localhost:3000',     // your app — plain localhost, no docker hostname
  poolUrls: ['http://localhost:9222'],
  poolDriver: 'cdp',
};

Nada para instalar além do npm, e baseUrl é apenas localhost (o navegador está na sua máquina).

Opção 2 · Obscura — um binário minúsculo, sem Docker

Um único binário de ~30 MB com anti-detecção integrada. Instale uma vez, execute-o, aponte o executor para ele:

obscura serve --port 9222 --stealth &
CHROME_POOL_URL=http://localhost:9222 POOL_DRIVER=obscura npx e2e-runner run --all

npx e2e-runner pool start (com poolDriver: 'obscura' na sua configuração) imprime o comando de instalação exato para o seu SO.

Opção 3 · Pool Docker — paralelo, para CI & suítes grandes

Um pool de Chrome compartilhado e gerenciado por fila que executa muitos testes de uma vez:

npx e2e-runner run --all     # the first run auto-starts the Docker pool for you

Requer Docker. Defina baseUrl: 'http://host.docker.internal:3000' para que o Chrome em contêiner alcance seu aplicativo.

Por que host.docker.internal (somente opção Docker)?

Com o pool Docker, o Chrome roda dentro de um contêiner, então localhost lá significa o contêiner — não sua máquina. host.docker.internal faz a ponte para o seu host. No Linux (Docker Engine, não Docker Desktop) adicione --add-host=host.docker.internal:host-gateway, ou use seu IP LAN. As opções 1 & 2 não têm isso — o navegador é local, então localhost simplesmente funciona.

Escreva seu primeiro teste

Abra e2e/tests/sample.json — um fluxo é uma lista ordenada de ações:

[
  { "name": "homepage loads", "actions": [
    { "type": "goto", "value": "/" },
    { "type": "assert_text", "text": "Welcome" },
    { "type": "screenshot", "value": "home.png" }
  ]}
]

Execute com npx e2e-runner run --all. Resultados — passou/falhou, tempo, capturas de tela, erros de rede — são impressos no seu terminal e no painel web se estiver aberto.

Add OpenCode (opcional)
cp node_modules/@matware/e2e-runner/opencode.json ./
mkdir -p .opencode && cp -r node_modules/@matware/e2e-runner/.opencode/* .opencode/

Veja OPENCODE.md para detalhes.

Atualização

Cada método de instalação atualiza separadamente — atualize o(s) que você usa:

# npm dependency (per project)
npm install --save-dev @matware/e2e-runner@latest

# Claude Code plugin
claude plugin update e2e-runner@matware

# MCP-only install (npx caches the package — pin @latest to force a refresh)
claude mcp add --transport stdio --scope user e2e-runner \
  -- npx -y -p @matware/e2e-runner@latest e2e-runner-mcp

[!NOTE] Duas pegadinhas: (1) npx prefere uma cópia encontrada no node_modules do projeto em vez do próprio cache — se um projeto fixar uma versão antiga, o servidor MCP e o painel executam essa versão antiga, então atualize também a dependência do projeto. (2) Processos já em execução mantêm o código antigo na memória: após atualizar, reinicie o painel e reconecte o servidor MCP (/mcpe2e-runner → Reconectar, ou reinicie sua sessão).


✨ O que você obtém

🧪 Testes sem código — arquivos JSON que qualquer pessoa da sua equipe pode ler e escrever. Sem JavaScript, sem compilação, sem dependência de framework.

🤖 Testes com IA — Claude Code cria, executa e depura testes nativamente por meio de 17 ferramentas MCP. Peça para "testar o fluxo de checkout" e ele constrói o JSON, executa e reporta.

🐛 Pipeline de issue-para-teste — Cole uma URL de issue do GitHub ou GitLab. O executor a busca, gera testes E2E, executa-os e informa: bug confirmado ou não reproduzível.

👁️ Verificação visual — Descreva como a página deve parecer em inglês simples. A IA captura uma captura de tela e julga passou/falhou com base na sua descrição. Sem configuração de diff de pixels.

🧠 Sistema de aprendizado — Rastreia a estabilidade dos testes entre execuções. Detecta testes instáveis, seletores instáveis, APIs lentas e padrões de erro — e então apresenta insights acionáveis.

Execução paralela — Execute N testes simultaneamente contra um pool de navegadores compartilhado (browserless, CDP bruto, Lightpanda, Obscura ou Steel). Modo serial disponível para testes que compartilham estado.

🎯 Drivers de navegador plugáveis — Escolha o mecanismo que se adapta a cada teste: Chrome real via browserless, Lightpanda ou Obscura para execuções rápidas e leves, Steel para sessões gerenciadas. Defina driver por teste ou substitua toda a execução com --driver.

📊 Painel em tempo real — Visualização de execução ao vivo, histórico de execuções com gráficos de taxa de aprovação, galeria de capturas de tela com busca por hash, logs de solicitações de rede expansíveis.

🔁 Tentativas inteligentes — Tentativas em nível de teste e de ação com atrasos configuráveis. Testes instáveis são detectados e sinalizados automaticamente.

📦 Módulos reutilizáveis — Extraia fluxos comuns (login, navegação, configuração) em módulos parametrizados e referencie-os com $use.

🏗️ Pronto para CI — Saída XML JUnit, código de saída 1 em falha, capturas de tela de erro capturadas automaticamente. Exemplo de GitHub Actions incluído.

🌐 Multi-projeto — Um painel agrega resultados de testes de todos os seus projetos. Um pool de Chrome atende a todos.

🐳 Portátil — Chrome roda em Docker, testes são arquivos JSON no seu repositório. Funciona em qualquer máquina com Node.js e Docker.


✍️ Escrevendo testes

Tudo sobre autoria de testes — o formato de arquivo, o vocabulário completo de ações, tentativas, isolamento de estado e reutilização. Expanda o que precisar:

Test format & file layout

Cada arquivo .json em e2e/tests/ contém um array de testes. Cada teste tem um name e actions sequenciais:

[
  {
    "name": "homepage-loads",
    "actions": [
      { "type": "goto", "value": "/" },
      { "type": "assert_visible", "selector": "body" },
      { "type": "assert_url", "value": "/" },
      { "type": "screenshot", "value": "homepage.png" }
    ]
  }
]

Arquivos de suíte podem ter prefixos numéricos para ordenação (01-auth.json, 02-dashboard.json). A flag --suite corresponde com ou sem o prefixo, então --suite auth encontra 01-auth.json.

Action catalog — navegação, entrada & interação
AçãoCamposDescrição
gotovalueNavegar para URL (relativa a baseUrl ou absoluta)
clickselector ou textClicar por seletor CSS ou texto visível. O modo texto também aceita scope: "dialog", visible: true, last: true
type / fillselector, valueLimpar campo e digitar texto
waitselector, text, gone, ou value (ms)Aguardar elemento/texto aparecer, gone desaparecer (spinner/diálogo), ou atraso fixo. Prefira condições a value fixos
screenshotvalue (nome do arquivo)Capturar uma captura de tela
selectselector, valueSelecionar uma opção de dropdown
clearselectorLimpar um campo de entrada
pressvaluePressionar uma tecla (Enter, Tab, etc.)
scrollselector ou value (px)Rolar até elemento ou por quantidade de pixels
hoverselectorPassar o mouse sobre um elemento
evaluatevalueExecutar JavaScript no contexto do navegador
navigatevalueNavegação do navegador (back, forward, reload)
clear_cookiesLimpar todos os cookies da página atual
wait_network_idleopcional value (ms ocioso, padrão 500), timeoutAguardar até a rede ficar ociosa por value ms — útil após ações que disparam solicitações em segundo plano
set_storagevalue ("key=val"), opcional selector: "session"Definir uma chave localStorage (ou sessionStorage com selector: "session")
gqlvalue (consulta), opcional text (JSON de variáveis), opcional selector (asserção)Executar consulta/mutação GraphQL via fetch na página, com o token de autenticação lido de localStorage. Falha em erros GraphQL. selector é uma expressão JS avaliada contra a resposta r (ex.: "r.data.users.length > 0"). Instala window.__e2eGql para etapas evaluate posteriores

Clicar por texto — quando click usa text em vez de selector, ele busca em elementos interativos e de conteúdo comuns:

button, a, [role="button"], [role="tab"], [role="menuitem"], [role="option"],
[role="listitem"], div[class*="cursor"], span, li, td, th, label, p, h1-h6
{ "type": "click", "text": "Sign In" }
Assertions — verificar texto, elementos, URLs, contagens & rede
| Ação | Campos | Descrição | |--------|--------|-------------| | `assert_text` | `text` | Verifica se o texto existe em qualquer lugar da página (substring) | | `assert_no_text` | `text` | Verifica se o texto NÃO aparece em nenhum lugar da página — oposto de `assert_text` | | `assert_text_in` | `selector`, `text`, opcional `value: "exact"` | Verifica texto dentro de um contêiner com escopo. `text` é uma regex sem diferenciar maiúsculas/minúsculas por padrão; `value: "exact"` alterna para substring com diferenciação de maiúsculas/minúsculas | | `assert_element_text` | `selector`, `text`, opcional `value: "exact"` | Verifica se o texto do elemento contém (ou corresponde exatamente) ao texto esperado | | `assert_url` | `value` | Verifica o caminho da URL atual ou a URL completa. Caminhos (`/dashboard`) comparam apenas o pathname | | `assert_visible` | `selector` | Verifica se o elemento existe e está visível | | `assert_not_visible` | `selector` | Verifica se o elemento está oculto ou não existe | | `assert_attribute` | `selector`, `value` | Verifica atributo: `"type=email"` para valor, `"disabled"` para existência | | `assert_class` | `selector`, `value` | Verifica se o elemento possui uma classe CSS | | `assert_input_value` | `selector`, `value` | Verifica se o `.value` de input/select/textarea contém texto | | `assert_matches` | `selector`, `value` (regex) | Verifica se o texto do elemento corresponde a um padrão de regex | | `assert_count` | `selector`, `value` | Verifica a contagem de elementos: exata (`"5"`) ou operadores (`">3"`, `">=1"`, `"<10"`) | | `assert_no_network_errors` | — | Falha se alguma requisição de rede falhar (ex.: `ERR_CONNECTION_REFUSED`) | | `assert_storage` | `value` (`"key"` ou `"key=expected"`), opcional `selector: "session"` | Verifica se uma chave de `localStorage`/`sessionStorage` existe ou possui um valor específico | | `assert_visual` | `value` (imagem dourada), opcional `selector`, `text` (diferença máxima, ex.: `"0.02"`), `fullPage`, `maskRegions`, `threshold` | Regressão visual: compara uma captura de tela com uma referência dourada. A primeira execução salva a dourada; execuções posteriores falham se mais pixels diferirem do limite (padrão 2%) e gravam uma imagem de diff | | `get_text` | `selector` | Extrai o texto do elemento (sem verificação, nunca falha). Resultado: `{ value: "..." }` |
Ações com conhecimento de framework — React/MUI sem boilerplate de evaluate

Estas ações lidam com padrões comuns em aplicativos React/MUI que normalmente exigem boilerplate verboso de evaluate:

AçãoCamposDescrição
type_reactselector, value, opcional blur, waitAfterDigita em inputs controlados do React usando o setter de valor nativo. Dispara eventos input + change para que o estado do React seja atualizado corretamente. blur: true confirma no blur; waitAfter: "<ms>" aguarda após (autocomplete com debounce).
click_regextext (regex), opcional selector, opcional value: "last"Clica no elemento cujo textContent corresponde a uma regex (sem diferenciar maiúsculas/minúsculas). Padrão: primeira correspondência. Use value: "last" para a última correspondência.
click_optiontextClica em um elemento [role="option"] por texto — comum em dropdowns de autocomplete/select.
select_comboboxtext, opcional selector, filter, openWait/filterWait/waitAfterAbre um Autocomplete/Select do MUI, opcionalmente digita filter, e então clica na opção que corresponde a text. Faz fallback entre [role="option"], .MuiAutocomplete-option, li.MuiMenuItem-root.
focus_autocompletetext (texto do label)Foca um input de autocomplete pelo texto do seu label. Suporta MUI e [role="combobox"] genérico.
click_chiptextClica em um elemento chip/tag por texto. Pesquisa em [class*="Chip"], [class*="chip"], [data-chip].
click_iconvalue (id do ícone), opcional selector (escopo)Clica em um ícone por fragmento de data-testid/data-icon/aria-label/classe ou SVG <title> — MUI, FontAwesome, Heroicons, etc. Clica no ancestral clicável mais próximo (botão, link, aba).
click_menu_itemtext, opcional selector (escopo)Clica em um item de menu por texto em [role="menuitem"], .dropdown-item, .menu-item, MUI MenuItem.
click_in_contexttext (texto do contêiner), selector (filho)Clica em um elemento filho dentro do menor contêiner que corresponde a text — ex.: o botão de excluir de um card/linha específico.
// Before: 5 lines of evaluate boilerplate
{ "type": "evaluate", "value": "const input = document.querySelector('#search'); const nativeSet = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value').set; nativeSet.call(input, 'term'); input.dispatchEvent(new Event('input', {bubbles: true})); input.dispatchEvent(new Event('change', {bubbles: true}));" }

// After: 1 action
{ "type": "type_react", "selector": "#search", "value": "term" }
Ações de múltiplas abas — popups, janelas OAuth e fluxos entre abas
AçãoCamposDescrição
open_tabvalue (URL), opcional text (label)Abre uma nova aba e navega para a URL (relativa a baseUrl ou absoluta). O label padrão é tab-<n>
switch_tabvalueAlterna a aba ativa por label, índice numérico ou correspondência de título/URL (regex ou substring). "default" retorna para a aba original
wait_for_tabopcional text (label), timeoutAguarda uma nova aba/popup aberta pelo aplicativo (window.open, target="_blank") e a torna a aba ativa
assert_tab_countvalueVerifica o número de abas abertas: exato ("2") ou operadores (">=2")
close_tabopcional value (label)Fecha a aba atual (ou nomeada) e alterna de volta para a última restante

Todas as ações subsequentes são executadas na aba ativa:

{ "type": "click", "text": "Open report" }
{ "type": "wait_for_tab", "text": "report" }
{ "type": "assert_text", "text": "Quarterly results" }
{ "type": "close_tab" }
Tentativas e detecção de flakiness

Tentativa em nível de teste — tenta novamente um teste inteiro em caso de falha. Defina globalmente via config ou por teste:

{ "name": "flaky-test", "retries": 3, "timeout": 15000, "actions": [...] }

Testes que passam após a tentativa são marcados como flaky no relatório e no sistema de aprendizado.

Tentativa em nível de ação — tenta novamente uma única ação sem reexecutar o teste inteiro. Útil para cliques e esperas sensíveis a tempo:

{ "type": "click", "selector": "#dynamic-btn", "retries": 3 }
{ "type": "wait", "selector": ".lazy-loaded", "retries": 2 }

Defina globalmente: actionRetries na config, --action-retries <n> na CLI ou variável de ambiente ACTION_RETRIES. Atraso entre tentativas: actionRetryDelay (padrão 500ms).

Testes seriais — para testes que compartilham estado

Testes que compartilham estado (ex.: dois testes modificando o mesmo registro) podem competir quando executados em paralelo. Marque-os como seriais:

{ "name": "create-patient", "serial": true, "actions": [...] }
{ "name": "verify-patient-list", "serial": true, "actions": [...] }

Testes seriais são executados um de cada vez após todos os testes paralelos terminarem — prevenindo interferência sem desacelerar testes independentes.

Testando aplicativos autenticados

A abordagem mais simples — faça login pela interface como um usuário real:

{
  "hooks": {
    "beforeEach": [
      { "type": "goto", "value": "/login" },
      { "type": "type", "selector": "#email", "value": "test@example.com" },
      { "type": "type", "selector": "#password", "value": "test-password" },
      { "type": "click", "text": "Sign In" },
      { "type": "wait", "selector": ".dashboard" }
    ]
  },
  "tests": [...]
}

Para SPAs com JWT, pule o formulário de login injetando o token diretamente:

{ "type": "set_storage", "value": "accessToken=eyJhbGciOiJIUzI1NiIs..." }

Ou defina globalmente na config:

// e2e.config.js
export default {
  authToken: 'eyJhbGciOiJIUzI1NiIs...',
  authStorageKey: 'accessToken',
};

Cada teste é executado em um contexto de navegador novo, então o estado de autenticação é automaticamente limpo entre testes.

Mais estratégias: Autenticação baseada em cookies, injeção de cabeçalho HTTP, bypass de OAuth/SSO, módulos de autenticação reutilizáveis e testes baseados em papéis — veja docs/authentication.md

Módulos reutilizáveis — extraia fluxos comuns com $use

Extraia fluxos comuns em módulos parametrizados:

// e2e/modules/login.json
{
  "$module": "login",
  "description": "Log in via the UI login form",
  "params": {
    "email": { "required": true, "description": "User email" },
    "password": { "required": true, "description": "User password" }
  },
  "actions": [
    { "type": "goto", "value": "/login" },
    { "type": "type", "selector": "#email", "value": "{{email}}" },
    { "type": "type", "selector": "#password", "value": "{{password}}" },
    { "type": "click", "text": "Sign In" },
    { "type": "wait", "value": "2000" }
  ]
}

Use em testes:

{
  "name": "dashboard-loads",
  "actions": [
    { "$use": "login", "params": { "email": "user@test.com", "password": "secret" } },
    { "type": "assert_text", "text": "Dashboard" }
  ]
}

Módulos suportam validação de parâmetros (parâmetros obrigatórios falham rapidamente), blocos condicionais ({{#param}}...{{/param}}), composição aninhada e detecção de ciclos.

Hooks — beforeAll / beforeEach / afterEach / afterAll

Execute ações em pontos do ciclo de vida. Defina globalmente na config ou por suíte:

{
  "hooks": {
    "beforeAll": [{ "type": "goto", "value": "/setup" }],
    "beforeEach": [{ "type": "goto", "value": "/" }],
    "afterEach": [{ "type": "screenshot", "value": "after.png" }],
    "afterAll": []
  },
  "tests": [...]
}

Importante: beforeAll é executado em uma página de navegador separada que é fechada antes dos testes começarem. Use beforeEach para estado que os testes precisam (cookies, localStorage, tokens de autenticação).

Padrões de exclusão — pule rascunhos de execuções --all

Pule testes exploratórios ou rascunhos de execuções --all:

// e2e.config.js
export default {
  exclude: ['explore-*', 'debug-*', 'draft-*'],
};

Execuções de suíte individuais (--suite) não são afetadas por padrões de exclusão.


🤖 Integração com IA

O ponto principal: seu agente escreve, executa e verifica testes para você.

Claude Code — instalação de plugin e instalação somente MCP
claude plugin marketplace add fastslack/mtw-e2e-runner
claude plugin install e2e-runner@matware

Isso dá ao Claude 17 ferramentas MCP, uma skill de fluxo de trabalho, 4 comandos de barra (/e2e-runner:run, /e2e-runner:create-test, /e2e-runner:verify-issue, /e2e-runner:capture) e 3 agentes especializados (test-analyzer, test-creator, test-improver).

Instalação somente MCP (apenas ferramentas, sem skill/comandos/agentes):

claude mcp add --transport stdio --scope user e2e-runner \
  -- npx -y -p @matware/e2e-runner e2e-runner-mcp
OpenCode
cp node_modules/@matware/e2e-runner/opencode.json ./
mkdir -p .opencode && cp -r node_modules/@matware/e2e-runner/.opencode/* .opencode/

Veja OPENCODE.md para detalhes.

As 17 ferramentas MCP
FerramentaDescrição
e2e_runExecuta testes (todos, por suíte ou por arquivo)
e2e_listLista as suítes de teste disponíveis
e2e_create_testCria um novo arquivo JSON de teste
e2e_create_moduleCria um módulo reutilizável
e2e_pool_statusVerifica a saúde do pool de Chrome
e2e_app_pool_statusInspeciona o pool de ambiente do aplicativo (forks, portas, drivers)
e2e_screenshotRecupera uma captura de tela por hash
e2e_captureCaptura captura de tela de qualquer URL
e2e_analyzeExtrai a estrutura da página (elementos interativos, formulários, cabeçalhos) e emite esqueletos de teste
e2e_dashboard_startInicia o painel web
e2e_dashboard_stopPara o painel web
e2e_dashboard_restartReinicia o painel (novo diretório/porta do projeto, limpa sessões obsoletas)
e2e_issueBusca issue e gera testes
e2e_network_logsConsulta logs de rede de uma execução
e2e_learningsConsulta insights de estabilidade
e2e_varsGerencia variáveis de projeto {{var.KEY}} com suporte a SQLite
e2e_neo4jGerencia o grafo de conhecimento Neo4j

Iniciar/parar o pool são apenas via CLI — não expostos via MCP.

Verificação visual — descreva a página, a IA julga

Descreva como a página deve parecer — a IA julga passou/falhou a partir das capturas de tela:

{
  "name": "dashboard-loads",
  "expect": "Patient list with at least 3 rows, no error messages, sidebar with navigation links",
  "actions": [
    { "type": "goto", "value": "/dashboard" },
    { "type": "wait", "selector": ".patient-list" }
  ]
}

Após as ações do teste serem concluídas, o runner captura automaticamente uma captura de tela de verificação. A resposta do MCP inclui o hash da captura de tela — o Claude Code a recupera e verifica visualmente contra sua descrição expect. Nenhuma chave de API é necessária.

Issue-para-teste — transforme um relatório de bug em um teste executável
Transforme issues do GitHub e GitLab em testes E2E executáveis. Cole a URL de uma issue e obtenha testes executáveis — automaticamente.

Como funciona:

  1. Buscar — Obtém os detalhes da issue (título, corpo, labels) via CLI gh ou glab
  2. Gerar — A IA cria ações de teste em JSON com base na descrição da issue
  3. Executar — Opcionalmente, executa os testes imediatamente para verificar se um bug é reproduzível
# Fetch and display
e2e-runner issue https://github.com/owner/repo/issues/42

# Generate a test file via Claude API
e2e-runner issue https://github.com/owner/repo/issues/42 --generate

# Generate + run + report
e2e-runner issue https://github.com/owner/repo/issues/42 --verify
# -> "BUG CONFIRMED" or "NOT REPRODUCIBLE"

No Claude Code, basta pedir:

"Busque a issue #42 e crie testes E2E para ela"

Lógica de verificação de bugs: Os testes gerados verificam o comportamento correto. Falha no teste = bug confirmado. Todos os testes passam = não reproduzível.

Autenticação: O GitHub exige a CLI gh, o GitLab exige a CLI glab. O GitLab self-hosted é suportado.


📊 Dashboard e insights

e2e-runner dashboard                  # Start on default port 8484
e2e-runner dashboard --port 9090      # Custom port
Tour do dashboard web — visualização ao vivo, histórico, galeria, status do pool

Execução ao vivo — monitore testes em tempo real com progresso passo a passo, durações e contagem de workers ativos.

Dashboard - Live test execution

Suites de teste — navegue por todas as suites entre projetos. Execute uma única suite ou todos os testes com um clique.

Dashboard - Test suites grid

Histórico de execuções — acompanhe tendências de taxa de aprovação com o gráfico integrado. Clique em qualquer linha para expandir os detalhes completos.

Dashboard - Run history

Detalhe da execução — selos de PASS/FAIL, miniaturas de capturas de tela com hashes copiáveis (ss:77c28b5a), erros de console formatados e logs de requisições de rede.

Dashboard - Run detail

Galeria de capturas de tela — navegue por todas as capturas de tela com busca por hash (capturas de ação, erro e verificação).

Dashboard - Screenshot gallery

Status do pool — saúde do pool do Chrome: slots disponíveis, sessões em execução, pressão de memória.

Dashboard - Pool status

Sistema de aprendizado — testes instáveis, seletores instáveis, APIs lentas

O runner aprende com cada execução de teste — construindo conhecimento sobre sua suite de testes ao longo do tempo. Consulte insights por meio da ferramenta MCP e2e_learnings:

ConsultaRetorna
summaryVisão geral completa da saúde: taxa de aprovação, testes instáveis, seletores instáveis, problemas de API
flakyTestes que passam apenas após novas tentativas
selectorsSeletores CSS com altas taxas de falha
pagesPáginas com erros de console, falhas de rede, problemas de tempo de carregamento
apisEndpoints de API com taxas de erro e latência (normalizados automaticamente: UUIDs, hashes, IDs)
errorsPadrões de erro mais frequentes, categorizados
trendsTaxa de aprovação ao longo do tempo (alterna automaticamente para horária quando todos os dados são de um único dia)
test:<name>Histórico detalhado de um teste específico
page:<path>Histórico detalhado de uma página específica
selector:<value>Histórico detalhado de um seletor específico

Armazenamento e exportação:

  • SQLite (~/.e2e-runner/dashboard.db) — padrão, sem configuração
  • Grafo de conhecimento Neo4j — opcional, para análise baseada em relacionamentos. Gerencie por meio da ferramenta MCP e2e_neo4j ou docker compose
  • Relatório Markdown (e2e/learnings.md) — gerado automaticamente após cada execução

Narração de teste: Cada execução de teste gera uma narrativa legível do que aconteceu passo a passo, visível na saída da CLI e no dashboard.

Tratamento de erros de rede — asserções, flag global, registro completo

Asserção explícita — coloque assert_no_network_errors após carregamentos críticos de página:

{ "type": "goto", "value": "/dashboard" },
{ "type": "wait", "selector": ".loaded" },
{ "type": "assert_no_network_errors" }

Flag global — defina failOnNetworkError: true para falhar automaticamente qualquer teste com erros de rede:

e2e-runner run --all --fail-on-network-error

Quando desabilitado (padrão), o runner ainda coleta e relata erros de rede — a resposta do MCP inclui um aviso quando os testes passam, mas têm erros de rede.

Registro completo de rede — todas as requisições XHR/fetch são capturadas com URL, método, status, duração, cabeçalhos de requisição/resposta e corpo da resposta (truncado em 50KB). Visualizável no dashboard com linhas expansíveis de detalhes de requisição.

Fluxo de detalhamento do MCP:

1. e2e_run          → compact networkSummary + runDbId
2. e2e_network_logs(runDbId)                     → all requests (url, method, status, duration)
3. e2e_network_logs(runDbId, errorsOnly: true)   → only failed requests
4. e2e_network_logs(runDbId, includeHeaders: true) → with headers
5. e2e_network_logs(runDbId, includeBodies: true)  → full request/response bodies

A resposta do e2e_run permanece compacta (~5KB) independentemente de quantas requisições foram capturadas. Use e2e_network_logs com o runDbId retornado para detalhar sob demanda.

Captura de tela — snapshot de qualquer URL sob demanda

Capture capturas de tela de qualquer URL sob demanda — sem necessidade de suite de testes:

e2e-runner capture https://example.com
e2e-runner capture https://example.com --full-page --selector ".loaded" --delay 2000

Por meio do MCP, a ferramenta e2e_capture suporta authToken e authStorageKey para páginas autenticadas — ela injeta o token no localStorage antes de navegar.

Cada captura de tela recebe um hash determinístico (ss:a3f2b1c9). Use e2e_screenshot para recuperar qualquer captura de tela por hash — ela retorna a imagem com metadados (nome do teste, etapa, tipo).


🌐 Drivers de navegador

O runner pode se comunicar com vários mecanismos de navegador por meio de diferentes drivers. O padrão é auto — ele testa cada URL do pool e escolhe o driver certo por pool.

DriverMecanismoSonda de detecçãoQuando usar
browserlessChromium real via browserless/pressure retorna JSONPadrão. Execução de JS de nível de produção, screencast, comportamento completo do Chrome
cdpCompatível com CDP genérico (Chrome puro, etc.)/json/version acessívelFallback para qualquer servidor CDP que não seja um dos outros
lightpandaLightpanda (Zig)/json/version Browser=lightpanda~9× mais rápido, ~16× menos memória que o Chrome headless — ideal para testes de alto volume estilo scraping
obscuraObscura (Rust + V8)/json/version Browser=obscura~30 MB de pegada de RAM, anti-detecção integrada (--stealth), permanece próximo do Chrome real via Puppeteer
steelSteel Browser/v1/sessions retorna JSONCiclo de vida de sessão gerenciado, API REST para orquestração
Escolha um driver por teste / force um por execução
{
  "tests": [
    {
      "name": "checkout flow (heavy JS, real Chrome)",
      "driver": "browserless",
      "actions": [...]
    },
    {
      "name": "scrape product page (lightweight)",
      "driver": "obscura",
      "fallbackDriver": "cdp",
      "actions": [...]
    }
  ]
}

driver é opcional. Se definido, apenas pools cujo driver detectado corresponda se tornam candidatos. fallbackDriver é opt-in explícito — sem ele, um driver de destino ausente falha o teste com uma mensagem clara. A ocupação do pool não aciona fallback; o runner aguarda dentro do conjunto filtrado.

Force um driver para uma execução inteira (as substituições da CLI vencem os campos por teste — útil para benchmarks A/B):

e2e-runner run --all --driver obscura
e2e-runner run --all --driver obscura --fallback-driver cdp
Executando cada driver localmente
# browserless (default) — managed by `pool start`
e2e-runner pool start

# Lightpanda — pool start uses templates/docker-compose-lightpanda.yml
e2e-runner pool start                 # with poolDriver: 'lightpanda' in config

# Obscura — install the binary and run it yourself
curl -LO https://github.com/h4ckf0r0day/obscura/releases/latest/download/obscura-x86_64-linux.tar.gz
tar xzf obscura-x86_64-linux.tar.gz
./obscura serve --port 9222 --stealth
# then point the runner at it: poolUrls: ['http://localhost:9222'], poolDriver: 'obscura'

⚙️ CLI, configuração e CI

Comandos da CLI
# Run tests
e2e-runner run --all                  # All suites
e2e-runner run --suite auth           # Single suite
e2e-runner run --tests path/to.json   # Specific file
e2e-runner run --inline '<json>'      # Inline JSON

# Pool management (CLI only, not MCP)
e2e-runner pool start                 # Start Chrome container
e2e-runner pool stop                  # Stop Chrome container
e2e-runner pool status                # Check pool health

# Issue-to-test
e2e-runner issue <url>                # Fetch issue
e2e-runner issue <url> --generate     # Generate test via AI
e2e-runner issue <url> --verify       # Generate + run + report

# Dashboard
e2e-runner dashboard                  # Start web dashboard

# Other
e2e-runner list                       # List available suites
e2e-runner capture <url>              # On-demand screenshot
e2e-runner init                       # Scaffold project
Opções da CLI
FlagPadrãoDescrição
--base-url <url>http://host.docker.internal:3000URL base do aplicativo
--pool-url <ws>ws://localhost:3333URL do WebSocket do pool do Chrome
--concurrency <n>3Workers de teste paralelos
--retries <n>0Repetir testes com falha N vezes
--action-retries <n>0Repetir ações com falha N vezes
--test-timeout <ms>60000Timeout por teste
--timeout <ms>10000Timeout padrão de ação
--output <format>jsonRelatório: json, junit, both
--env <name>defaultPerfil de ambiente
--fail-on-network-errorfalseFalhar testes com erros de rede
--project-name <name>nome do diretórioNome de exibição do projeto
--driver <name>(por teste)Forçar driver do pool para a execução: browserless, cdp, lightpanda, obscura, steel
--fallback-driver <name>nenhumFallback explícito se nenhum pool com --driver estiver acessível
Configuraçãoe2e.config.js e prioridade

Crie e2e.config.js na raiz do seu projeto:

export default {
  baseUrl: 'http://host.docker.internal:3000',
  concurrency: 4,
  retries: 2,
  actionRetries: 1,
  testTimeout: 30000,
  outputFormat: 'both',
  failOnNetworkError: true,
  exclude: ['explore-*', 'debug-*'],

  hooks: {
    beforeEach: [{ type: 'goto', value: '/' }],
  },

  environments: {
    staging: { baseUrl: 'https://staging.example.com' },
    production: { baseUrl: 'https://example.com', concurrency: 5 },
  },
};

Prioridade de configuração (a maior vence):

  1. Flags da CLI
  2. Variáveis de ambiente
  3. Arquivo de configuração (e2e.config.js ou e2e.config.json)
  4. Padrões

Quando --env <name> está definido, o perfil correspondente substitui tudo.

CI/CD — JUnit XML e GitHub Actions
e2e-runner run --all --output junit
jobs:
  e2e:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
      - run: npm ci
      - run: npx e2e-runner pool start
      - run: npx e2e-runner run --all --output junit
      - uses: mikepenz/action-junit-report@v4
        if: always()
        with:
          report_paths: e2e/screenshots/junit.xml
API programática
import { createRunner } from '@matware/e2e-runner';

const runner = await createRunner({ baseUrl: 'http://localhost:3000' });

const report = await runner.runAll();
const report = await runner.runSuite('auth');
const report = await runner.runFile('e2e/tests/login.json');
const report = await runner.runTests([
  { name: 'quick-check', actions: [{ type: 'goto', value: '/' }] },
]);

Requisitos

  • Node.js >= 20
  • Docker — apenas para Opção 3 (o pool paralelo do Chrome). As Opções 1 e 2 não precisam dele.

Licença

Copyright 2026 Matias Aguirre (fastslack) — Matware

Licenciado sob a Apache License, Versão 2.0. Consulte LICENSE para detalhes.