Percorra o fluxo
Um navegador real abre no seu app. Faça login, navegue, preencha formulários — é só usar.
O LLM planeja as ações do navegador uma vez. A partir da segunda execução, o Windup faz um replay determinístico com zero chamadas ao LLM — ~1 segundo, $0, resultados estáveis. Você edita cenários, não seletores.
$ npm i -D windupjs
O problema
Testes E2E escritos à mão quebram toda vez que um seletor muda de lugar. Agentes de IA que dirigem o navegador em cada execução são lentos, não determinísticos e cobram uma chamada ao LLM por teste.
O Windup planeja uma vez e guarda em cache um plano de ações validado. Os replays são determinísticos e gratuitos. Quando o app muda e uma verificação falha, o plano é invalidado e replanejado automaticamente — autorreparável, não silenciosamente errado.
Como funciona
A parte cara — descobrir as ações do navegador — acontece uma única vez e é transformada em dados verificáveis em cache.
Uma tarefa em linguagem natural vai para o planejador. O LLM emite um plano de ações em JSON — uma chamada, apenas na primeira execução.
Um executor determinístico (Playwright) roda o plano. Pós-condições baratas de DOM/URL verificam cada ação — sem LLM.
A trajetória fica em cache. Cada execução posterior faz replay dela: zero chamadas ao LLM, ~1 segundo, $0, o mesmo plano todas as vezes.
Novo no 1.0
Prefere mostrar a descrever? O windup record abre um navegador headful no seu app — você percorre o fluxo clicando, marca o que verificar e finaliza. O Windup escreve o cenário e cacheia o plano gravado, então ele replaya de forma determinística em $0, sem LLM.
npx windup record --url http://localhost:3000 Um navegador real abre no seu app. Faça login, navegue, preencha formulários — é só usar.
Uma toolbar flutuante embaixo: aperte ◉ e clique no elemento que o teste deve checar — ou não marque nada para verificar a URL final.
“■ finalizar” (ou Ctrl-C). O Windup escreve o cenário + cacheia o plano. windup run <id> replaya em $0.
Por que Windup
Scripts escritos à mão são baratos de rodar, mas caros de manter. Agentes de IA por execução são fáceis de escrever, mas lentos e não determinísticos. O Windup pega a metade boa de cada um.
| Dimensão | Scripts à mão | Agente de IA a cada execução | Windup |
|---|---|---|---|
| Autoria | Código + seletores | Linguagem natural | Linguagem natural |
| Custo por execução | $0 | LLM em cada execução | LLM apenas na 1ª execução |
| Velocidade | Rápido | Lento (modelo no loop) | ~1s replay |
| Determinismo | Alto | Baixo (improvisa) | Alto (mesmo plano toda vez) |
| App mudou | Você conserta o script | Pode fazer a coisa errada em silêncio | Verificação falha → replaneja |
Recursos
Uma CLI feita para projetos reais: autoria por prosa ou por demonstração, dependências, valores dinâmicos (OTP/magic-link), emulação de dispositivo, orçamentos de performance, stub de requests, barreiras de saúde em runtime, guard-rails de CI, diagnósticos de leitura e reporters — tudo que um fluxo de QA precisa.
Descreva o teste em linguagem simples. Sem seletores, sem page objects, sem código de teste para manter.
A partir da 2ª execução: llm_calls=0, ~1s, $0. O plano em cache roda igual todas as vezes.
Playwright com eventos de entrada confiáveis (isTrusted) — cliques, digitação e navegação confiáveis.
Pós-condições de DOM/URL checadas em cada ação, sem LLM no loop. Asserte texto visível, uma contagem de elementos, um atributo, ou que algo sumiu — não só “um seletor existe”.
Autoria por demonstração: dirige um navegador headful, marca a verificação com uma toolbar, finaliza — o Windup escreve o cenário e cacheia o plano gravado (replay $0). Uma senha digitada nunca entra no plano.
Diagnósticos de leitura a partir do ledger, sem LLM: histórico de pass-rate por cenário, por que um cenário re-planeja, e o que mudou entre dois runs. Mais windup badge para um SVG de status.
Roda um cenário num preset do Playwright com --device "iPhone 14" — viewport, UA, mobile/touch. Planos cacheados são keyados por dispositivo, então mobile e desktop são trajetórias separadas.
Captura o TTFB / FCP / LCP / CLS da página final com --web-vitals, e faz o run falhar quando config.budgets é ultrapassado — um gate de performance montado sobre o run que você já faz.
Faz stub de um request (um 500, uma lista vazia, uma chamada caída) e congela o relógio/timezone — por run, nunca cacheado. Aplique-os a um único cenário, então um teste de estado de erro não vaza pra todo run.
Faz um cenário falhar se a página logou um erro de console ou recebeu um 5xx silencioso durante o run (--fail-on-console / --fail-on-5xx) — um run não pode “passar” enquanto a página está quebrada por baixo.
Repete um flake (--retries), limita o relógio da suíte (--max-wall), para na primeira falha (--bail), ou põe um cenário flaky em quarentena pra ele reportar sem fazer o build falhar — exposto, nunca escondido.
Das rotas ainda sem teste, o LLM redige um cenário por rota descoberta — fechando o ciclo scan → cobertura → autoria.
Autoria assistida por LLM: escreve o cenário a partir das telas reais do seu app (mapa do site) + manifesto do projeto. --validate roda e refina até passar.
Indexa suas rotas e elementos direto do código-fonte (Next.js, react-router).
Credenciais nunca entram no cenário, no cache, no prompt do LLM ou no git — apenas referências ENV:*, resolvidas em tempo de execução.
Dependências entre cenários (ex.: "criar fatura" depende de "login") — mesma sessão, cache por dependência.
A IA escreve um resumo pós-execução citando valores reais observados — preços, mensagens, confirmações.
Em caso de falha, a IA lê a página real e sugere a correção do seu cenário.
JUnit, JSON e HTML autocontido (--reporter). Código de saída diferente de zero em qualquer falha.
Google Gemini e OpenAI, escolhidos por execução (--llm openai:gpt-5-mini). windup costs rastreia gastos por provedor e modelo.
Roda cenários em paralelo em um único navegador aquecido compartilhado com contextos isolados — ~2× mais rápido em uma suíte mista, mais ainda com planejamento ou fluxos longos. Sequencial por padrão.
Rode os mesmos cenários no Chromium (padrão), Firefox ou WebKit com --browser. Um único plano faz replay nos três — escreva uma vez, rode em todos.
Valores dinâmicos (códigos OTP, magic-links) obtidos em tempo de execução de uma fonte declarada pelo autor (cmd/http/fn). Um plano os usa via value_ref/url_ref — desbloqueia o login sem senha. resolveFields vincula um campo de forma determinística.
O estado de autenticação (storageState) de uma dependência é capturado uma vez e restaurado nos replays em cache — assim o fluxo de login não é reexecutado para cada dependente (deps≈0). O grande ganho de velocidade da suíte.
Injeta localStorage/sessionStorage antes de um plano rodar — chegue direto a um carrinho ou ao estado de um dispositivo de PDV, sem ida e volta ao servidor. Determinístico e seguro para CI.
Denylist de segurança: uma execução que mira um seletor ou URL proibido é abortada — a proteção de CI contra trocar a senha de teste, apagar dados ou persistir configuração.
Cruza as rotas que o windup scan indexou com seus cenários e lista as rotas que ainda não têm teste — lacunas de cobertura, encontradas automaticamente.
Verificação antes do CI: chave do LLM, navegador, cenários que fazem parse, sem fragmentos órfãos, mapa do site escaneado — pega primeiro os problemas comuns do tipo "vai quebrar no CI".
Uma auditoria de acessibilidade gratuita (axe-core) na página final de cada cenário — violações reportadas. Informativa; nunca falha a execução.
Divide a suíte em rodízio entre runners de CI paralelos (--shard 1/4, 2/4, …), cada um um job separado.
CI incremental: roda apenas os cenários que uma mudança de código ou de cenário afeta (git diff → atribuição de rotas), com um fallback seguro para a suíte completa — nunca um falso verde silencioso.
Prontidão reutilizável anti-flake por glob de rota: espere o app estar pronto antes de agir, definido uma vez em vez de repetido como hint em cada cenário.
Exemplo
Você escreve a intenção. A primeira execução planeja e paga uns décimos de centavo; toda execução depois dela é um replay do cache por $0.
{
"scenario_id": "checkout",
"task": "Log in as the qa account, add 'Backpack' to the cart, check out and verify the order confirmation message appears."
} $ windup run checkout # 1st run
PASS checkout cache=miss llm_calls=1 total=3003ms cost=$0.0024
$ windup run checkout # again — deterministic replay
PASS checkout cache=hit llm_calls=0 total=671ms cost=$0 cache=hit · llm_calls=0 · $0 — a segunda execução nunca toca no modelo.
CI / CD
Rode a suíte inteira em um navegador aquecido, faça o build falhar em qualquer cenário que falhar e gere relatórios legíveis por máquina ou por humanos.
$ npx windup run --all --reporter junit \
--report-file reports/windup.xml Confiabilidade
Os replays são medidos, não prometidos. O plano em cache produz o mesmo resultado em cada execução — sem modelo, sem instabilidade.
Começar
Node ≥ 20 e uma chave de API — GOOGLE_GENERATIVE_AI_API_KEY (Google, padrão) ou OPENAI_API_KEY (OpenAI) — em .env.local. As chaves são usadas apenas para planejar; replays do cache nunca chamam um LLM.
$ npm i -D windupjs $ npx windup init $ npx windup scan $ npx windup new "log in and create an invoice for ACME" $ npx windup run checkout Para a era da IA
Ninguém lê documentação mais — todo mundo entrega para um assistente. Por isso o Windup traz um llms.txt: toda a documentação, estruturada para máquinas. Aponte seu agente de código para ele, descreva os fluxos em palavras simples e ele escreve e roda os cenários por você.
Cole esta URL no seu assistente (Claude, Cursor, Copilot, …).
https://windup.run/pt/llms.txt Um prompt inicial pronto para colar — preencha com seus fluxos.
Leia https://windup.run/pt/llms.txt e configure testes E2E do Windup para o meu app, depois escreva cenários para estes fluxos: ... llms-full.txt — toda a documentação em um só arquivo · markdown por página em /pt/docs/<page>.md · o padrão llms.txt