Escreva testes E2E em linguagem simples. Replay por $0.

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
  • Sem seletores, sem código de teste
  • llm_calls=0 no replay
  • Playwright por baixo dos panos
windup run checkout
Gravação de terminal: um cenário em linguagem natural roda; a primeira execução planeja com llm_calls=1, a segunda faz replay do cache com llm_calls=0 e $0
Terminal real — a primeira execução planeja (llm_calls=1), a segunda faz replay do cache por $0.

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

Planeje uma vez com o LLM, depois faça replay sem ele.

A parte cara — descobrir as ações do navegador — acontece uma única vez e é transformada em dados verificáveis em cache.

  1. 1

    Planejar (uma vez)

    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.

    llm_calls=1 · ~$0.0025
  2. 2

    Executar + verificar

    Um executor determinístico (Playwright) roda o plano. Pós-condições baratas de DOM/URL verificam cada ação — sem LLM.

    eventos de entrada confiáveis
  3. 3

    Replay (grátis)

    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.

    llm_calls=0 · $0
  • Planos são dados, não código — JSON validado por schema — sem improviso em tempo de execução.
  • Verificação sem LLM — Pós-condições checam DOM/URL em cada ação.
  • Cache autorreparável — Uma verificação que falha invalida o plano → replaneja.
  • Zero conhecimento do site embutido — O motor não sabe nada sobre o seu app de antemão.

Novo no 1.0

Autoria por demonstração windup record

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
1

Percorra o fluxo

Um navegador real abre no seu app. Faça login, navegue, preencha formulários — é só usar.

2

Marque a verificação

Uma toolbar flutuante embaixo: aperte ◉ e clique no elemento que o teste deve checar — ou não marque nada para verificar a URL final.

3

Finalize → replay $0

“■ finalizar” (ou Ctrl-C). O Windup escreve o cenário + cacheia o plano. windup run <id> replaya em $0.

  • Uma senha digitada nunca entra no plano — vai pro .env.local e é referenciada como um ENV value_ref.
  • Seletores gravados seguem a prioridade do próprio motor (#id → [data-testid] → [name] → type → role/texto), com um fallback por nome acessível.
  • Uma mudança real de UI invalida o cache? Ele se auto-repara re-planejando pela tarefa, como qualquer cenário.
Como o windup record funciona →

Por que Windup

A confiabilidade dos scripts, a ergonomia da linguagem natural.

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

Tudo que um fluxo de QA precisa — menos os seletores.

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.

Cenários em linguagem natural

Descreva o teste em linguagem simples. Sem seletores, sem page objects, sem código de teste para manter.

Planeje uma vez, replay grátis

A partir da 2ª execução: llm_calls=0, ~1s, $0. O plano em cache roda igual todas as vezes.

Execução determinística

Playwright com eventos de entrada confiáveis (isTrusted) — cliques, digitação e navegação confiáveis.

Verificação barata

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

windup record

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.

windup trends / why / diff

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.

Emulação de dispositivo

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.

Web vitals + orçamentos

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.

config.network / config.clock

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.

Barreiras de saúde em runtime

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.

Guard-rails de CI

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.

windup suggest-scenarios

Das rotas ainda sem teste, o LLM redige um cenário por rota descoberta — fechando o ciclo scan → cobertura → autoria.

windup new

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.

windup scan

Indexa suas rotas e elementos direto do código-fonte (Next.js, react-router).

windup secret

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.

depends_on

Dependências entre cenários (ex.: "criar fatura" depende de "login") — mesma sessão, cache por dependência.

run --summary

A IA escreve um resumo pós-execução citando valores reais observados — preços, mensagens, confirmações.

run --suggest

Em caso de falha, a IA lê a página real e sugere a correção do seu cenário.

Relatórios de CI

JUnit, JSON e HTML autocontido (--reporter). Código de saída diferente de zero em qualquer falha.

Multi-provedor

Google Gemini e OpenAI, escolhidos por execução (--llm openai:gpt-5-mini). windup costs rastreia gastos por provedor e modelo.

run --concurrency

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.

Multi-navegador

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.

config.resolve

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.

Session snapshots

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.

config.seed

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.

config.forbid

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.

windup coverage

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.

windup doctor

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

run --a11y

Uma auditoria de acessibilidade gratuita (axe-core) na página final de cada cenário — violações reportadas. Informativa; nunca falha a execução.

run --all --shard

Divide a suíte em rodízio entre runners de CI paralelos (--shard 1/4, 2/4, …), cada um um job separado.

run --all --changed

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.

readySignals

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

Um cenário é linguagem natural em JSON. Duas execuções contam a história toda.

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.

checkout.json cenário
{
  "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 saída
$ 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

Coloque no seu pipeline. Códigos de saída e relatórios inclusos.

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.

ci — uma linha bash
$ npx windup run --all --reporter junit \
    --report-file reports/windup.xml
  • --all roda todos os cenários em um único navegador aquecido para a suíte inteira.
  • --concurrency <n> roda cenários em paralelo (~2× mais rápido em uma suíte mista); --browser firefox|webkit para rodar multi-navegador.
  • Código de saída diferente de zero quando qualquer cenário falha.
  • --reporter junit|json|html; windup costs --json rastreia gasto com IA no pipeline.

Confiabilidade

Determinístico significa determinístico.

Os replays são medidos, não prometidos. O plano em cache produz o mesmo resultado em cada execução — sem modelo, sem instabilidade.

60/60
replays de cache aprovados
4 cenários × 15 replays — zero instabilidade
llm_calls=0
em cada replay
login · checkout de múltiplos passos · adicionar/remover · um 2º site
~$0.0025
por geração
modelo padrão, gemini-3.1-flash-lite
106 routes
dogfood em produção
rodado contra um app real de produção
Mascote do Windup segurando um sinal de visto verde

Começar

Cinco comandos do zero a um teste com replay.

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.

Mascote do Windup correndo
$ npm i -D windupjs
O Chromium é provisionado automaticamente
$ npx windup init
3 perguntas → windup.config.ts
$ npx windup scan
indexa as rotas do seu app a partir do código-fonte
$ npx windup new "log in and create an invoice for ACME"
autoria assistida por LLM
$ npx windup run checkout
1ª execução planeja · depois replay ~1s, $0
Node ≥ 20Google Gemini ou OpenAIPlaywright incluídoMIT

Para a era da IA

Deixe sua IA montar os testes.

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

1

Dê a documentação à sua IA

Cole esta URL no seu assistente (Claude, Cursor, Copilot, …).

https://windup.run/pt/llms.txt
2

Descreva o que testar

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