Escribe pruebas E2E en lenguaje natural. Reprodúcelas por $0.

El LLM planifica las acciones del navegador una vez. A partir de la segunda ejecución, Windup hace un replay determinista con cero llamadas al LLM~1 segundo, $0, resultados estables. Editas escenarios, no selectores.

$ npm i -D windupjs
  • Sin selectores, sin código de prueba
  • llm_calls=0 en replay
  • Playwright por debajo
windup run checkout
Grabación de terminal: se ejecuta un escenario en lenguaje natural; la primera ejecución planifica con llm_calls=1, la segunda hace replay desde caché con llm_calls=0 y $0
Terminal real — la primera ejecución planifica (llm_calls=1), la segunda hace replay desde caché a $0.

El problema

Las pruebas E2E escritas a mano se rompen cada vez que se mueve un selector. Los agentes de IA que manejan el navegador en cada ejecución son lentos, no deterministas y te cobran una llamada al LLM por prueba.

Windup planifica una vez y guarda en caché un plan de acciones validado. Los replays son deterministas y gratuitos. Cuando la app cambia y una verificación falla, el plan se invalida y se replanifica automáticamente — se autorepara, no queda silenciosamente incorrecto.

Cómo funciona

Planifica una vez con el LLM, luego reproduce sin él.

La parte cara — averiguar las acciones del navegador — ocurre una sola vez y se convierte en datos verificables guardados en caché.

  1. 1

    Planificar (una vez)

    Una tarea en lenguaje natural va al planificador. El LLM emite un plan de acciones JSON — una llamada, solo en la primera ejecución.

    llm_calls=1 · ~$0.0025
  2. 2

    Ejecutar + verificar

    Un ejecutor determinista (Playwright) ejecuta el plan. Postcondiciones baratas de DOM/URL verifican cada acción — sin LLM.

    eventos de entrada confiables
  3. 3

    Replay (gratis)

    La trayectoria queda en caché. Cada ejecución posterior la reproduce: cero llamadas al LLM, ~1 segundo, $0, el mismo plan siempre.

    llm_calls=0 · $0
  • Los planes son datos, no código — JSON validado por esquema — sin improvisación en tiempo de ejecución.
  • Verificación sin LLM — Las postcondiciones comprueban DOM/URL en cada acción.
  • Caché autorreparable — Una verificación fallida invalida el plan → replanifica.
  • Cero conocimiento del sitio incrustado — El motor no sabe nada de tu app de antemano.

Nuevo en 1.0

Autoría por demostración windup record

¿Prefieres mostrar antes que describir? windup record abre un navegador headful en tu app — recorres el flujo con clics, marcas qué verificar y finalizas. Windup escribe el escenario y cachea el plan grabado, así que se repite de forma determinista en $0, sin LLM.

npx windup record --url http://localhost:3000
1

Recorre el flujo

Se abre un navegador real en tu app. Inicia sesión, navega, rellena formularios — solo úsalo.

2

Marca la verificación

Una toolbar flotante abajo: pulsa ◉ y luego clic en el elemento que el test debe comprobar — o no marques nada para verificar la URL final.

3

Finaliza → replay $0

“■ finalizar” (o Ctrl-C). Windup escribe el escenario + cachea el plan. windup run <id> lo repite en $0.

  • Una contraseña tipeada nunca entra al plan — se guarda en .env.local y se referencia como un ENV value_ref.
  • Los selectores grabados siguen la prioridad del propio motor (#id → [data-testid] → [name] → type → role/texto), con un fallback por nombre accesible.
  • ¿Un cambio real de UI invalida el cache? Se auto-repara re-planificando desde la tarea, como cualquier escenario.
Cómo funciona windup record →

Por qué Windup

La fiabilidad de los scripts, la ergonomía del lenguaje natural.

Los scripts escritos a mano son baratos de ejecutar pero caros de mantener. Los agentes de IA por ejecución son fáciles de escribir pero lentos y no deterministas. Windup toma la mitad buena de cada uno.

Dimensión Scripts escritos a mano Agente de IA en cada ejecución Windup
Autoría Código + selectores Lenguaje natural Lenguaje natural
Coste por ejecución $0 LLM en cada ejecución LLM solo en la 1ª ejecución
Velocidad Rápido Lento (modelo en el bucle) ~1s replay
Determinismo Alto Bajo (improvisa) Alto (el mismo plan siempre)
La app cambió Arreglas el script Puede hacer algo incorrecto en silencio La verificación falla → replanifica

Características

Todo lo que necesita un flujo de QA — menos los selectores.

Una CLI hecha para proyectos reales: autoría por prosa o por demostración, dependencias, valores dinámicos (OTP/magic-link), emulación de dispositivos, presupuestos de performance, stub de requests, barreras de salud en runtime, guard-rails de CI, diagnósticos de solo lectura y reporters — todo lo que un flujo de QA necesita.

Escenarios en lenguaje natural

Describe la prueba en lenguaje natural. Sin selectores, sin page objects, sin código de prueba que mantener.

Planifica una vez, reproduce gratis

A partir de la 2ª ejecución: llm_calls=0, ~1s, $0. El plan en caché se ejecuta igual siempre.

Ejecución determinista

Playwright con eventos de entrada confiables (isTrusted) — clics, escritura y navegación fiables.

Verificación barata

Postcondiciones de DOM/URL comprobadas en cada acción, sin LLM en el bucle. Asserta texto visible, un conteo de elementos, un atributo, o que algo desapareció — no solo “un selector existe”.

windup record

Autoría por demostración: maneja un navegador headful, marca la verificación con una toolbar, finaliza — Windup escribe el escenario y cachea el plan grabado (replay $0). Una contraseña tipeada nunca entra al plan.

windup trends / why / diff

Diagnósticos de solo lectura desde el ledger, sin LLM: historial de pass-rate por escenario, por qué un escenario re-planifica, y qué cambió entre dos runs. Además windup badge para un SVG de estado.

Emulación de dispositivos

Corre un escenario en un preset de Playwright con --device "iPhone 14" — viewport, UA, mobile/touch. Los planes cacheados se keyean por dispositivo, así mobile y desktop son trayectorias separadas.

Web vitals + presupuestos

Captura el TTFB / FCP / LCP / CLS de la página final con --web-vitals, y haz fallar el run cuando se supera config.budgets — un gate de performance montado sobre el run que ya haces.

config.network / config.clock

Stub de un request (un 500, una lista vacía, una llamada caída) y congela el reloj/timezone — por run, nunca cacheado. Aplícalos a un solo escenario, así un test de estado de error no se filtra a cada run.

Barreras de salud en runtime

Haz fallar un escenario que registró un error de consola o recibió un 5xx silencioso durante el run (--fail-on-console / --fail-on-5xx) — un run no puede “pasar” mientras la página está rota por debajo.

Guard-rails de CI

Reintenta un flake (--retries), limita el reloj de la suite (--max-wall), para en la primera falla (--bail), o pon en cuarentena un escenario flaky para que reporte sin hacer fallar el build — expuesto, nunca oculto.

windup suggest-scenarios

Desde las rutas sin test aún, el LLM redacta un escenario por ruta descubierta — cerrando el ciclo scan → cobertura → autoría.

windup new

Autoría asistida por LLM: escribe el escenario a partir de las pantallas reales de tu app (mapa del sitio) + el manifiesto del proyecto. --validate lo ejecuta y refina hasta que pasa.

windup scan

Indexa tus rutas y elementos directamente desde el código fuente (Next.js, react-router).

windup secret

Las credenciales nunca entran en el escenario, la caché, el prompt del LLM ni git — solo referencias ENV:*, resueltas en tiempo de ejecución.

depends_on

Dependencias entre escenarios (p. ej. "crear factura" depende de "login") — misma sesión, con caché por dependencia.

run --summary

La IA escribe un informe posterior a la ejecución citando valores reales observados — precios, mensajes, confirmaciones.

run --suggest

Ante un fallo, la IA lee la página real y sugiere la corrección para tu escenario.

Reporters de CI

JUnit, JSON y HTML autocontenido (--reporter). Código de salida distinto de cero ante cualquier fallo.

Multiproveedor

Google Gemini y OpenAI, elegidos por ejecución (--llm openai:gpt-5-mini). windup costs rastrea el gasto por proveedor y modelo.

run --concurrency

Ejecuta escenarios en paralelo sobre un único navegador caliente compartido con contextos aislados — ~2× más rápido en una suite mixta, más con planificación o flujos largos. Secuencial por defecto.

Multinavegador

Ejecuta los mismos escenarios en Chromium (por defecto), Firefox o WebKit con --browser. Un único plan se reproduce en los tres — escribe una vez, ejecuta en todos.

config.resolve

Valores dinámicos (códigos OTP, magic-links) obtenidos en tiempo de ejecución desde una fuente declarada por el autor (cmd/http/fn). Un plan los usa mediante value_ref/url_ref — desbloquea el inicio de sesión sin contraseña. resolveFields vincula un campo de forma determinista.

Session snapshots

El estado de autenticación (storageState) de una dependencia se captura una vez y se restaura en los replays desde caché — así el flujo de login no se reejecuta para cada dependiente (deps≈0). La gran mejora de velocidad de la suite.

config.seed

Inyecta localStorage/sessionStorage antes de que un plan se ejecute — llega directo a un carrito o al estado de un dispositivo TPV, sin ida y vuelta al servidor. Determinista y seguro para CI.

config.forbid

Denylist de seguridad: una ejecución que apunta a un selector o URL prohibido se aborta — la salvaguarda de CI contra cambiar la contraseña de prueba, borrar datos o persistir configuración.

windup coverage

Cruza las rutas que windup scan indexó con tus escenarios y lista las rutas que aún no tienen prueba — huecos de cobertura, encontrados automáticamente.

windup doctor

Comprobación previa al CI: clave del LLM, navegador, escenarios que parsean, sin fragmentos huérfanos, mapa del sitio escaneado — detecta primero los problemas típicos del tipo "va a romperse en CI".

run --a11y

Una auditoría de accesibilidad gratuita (axe-core) en la página final de cada escenario — violaciones reportadas. Informativa; nunca falla la ejecución.

run --all --shard

Reparte la suite por turnos entre runners de CI paralelos (--shard 1/4, 2/4, …), cada uno un job separado.

run --all --changed

CI incremental: ejecuta solo los escenarios que afecta un cambio de código o de escenario (git diff → atribución de rutas), con un fallback seguro a la suite completa — nunca un falso verde silencioso.

readySignals

Preparación reutilizable anti-flakes por glob de ruta: espera a que la app esté lista antes de actuar, definida una vez en lugar de repetida como hint en cada escenario.

Ejemplo

Un escenario es lenguaje natural en JSON. Dos ejecuciones cuentan toda la historia.

Tú escribes la intención. La primera ejecución planifica y paga unas décimas de céntimo; cada ejecución posterior es un replay desde caché a $0.

checkout.json escenario
{
  "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 salida
$ 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 — la segunda ejecución nunca toca el modelo.

CI / CD

Intégralo en tu pipeline. Códigos de salida e informes incluidos.

Ejecuta toda la suite en un navegador caliente, haz fallar el build ante cualquier escenario fallido y emite informes legibles por máquina o por humanos.

ci — una línea bash
$ npx windup run --all --reporter junit \
    --report-file reports/windup.xml
  • --all ejecuta cada escenario en un único navegador caliente para toda la suite.
  • --concurrency <n> ejecuta escenarios en paralelo (~2× más rápido en una suite mixta); --browser firefox|webkit para ejecutar multinavegador.
  • Código de salida distinto de cero cuando cualquier escenario falla.
  • --reporter junit|json|html; windup costs --json rastrea el gasto de IA en el pipeline.

Fiabilidad

Determinista significa determinista.

Los replays se miden, no se prometen. El plan en caché produce el mismo resultado en cada ejecución — sin modelo, sin flakes.

60/60
replays desde caché superados
4 escenarios × 15 replays — cero flakes
llm_calls=0
en cada replay
login · checkout multipaso · añadir/quitar · un 2º sitio
~$0.0025
por generación
modelo por defecto, gemini-3.1-flash-lite
106 routes
dogfood en producción
ejecutado contra una app de producción real
La mascota de Windup sosteniendo una marca de verificación verde

Empezar

Cinco comandos de cero a una prueba con replay.

Node ≥ 20 y una clave de API — GOOGLE_GENERATIVE_AI_API_KEY (Google, por defecto) o OPENAI_API_KEY (OpenAI) — en .env.local. Las claves se usan solo para planificar; los replays en caché nunca llaman a un LLM.

La mascota de Windup corriendo
$ npm i -D windupjs
Chromium se aprovisiona automáticamente
$ npx windup init
3 preguntas → windup.config.ts
$ npx windup scan
indexa las rutas de tu app desde el código fuente
$ npx windup new "log in and create an invoice for ACME"
autoría asistida por LLM
$ npx windup run checkout
1ª ejecución planifica · luego replay ~1s, $0
Node ≥ 20Google Gemini u OpenAIPlaywright incluidoMIT

Para la era de la IA

Deja que tu IA arme las pruebas.

Ya nadie lee la documentación — se la pasa a un asistente. Por eso Windup incluye un llms.txt: toda la documentación, estructurada para máquinas. Apunta tu agente de código hacia él, describe los flujos con palabras y él escribe y ejecuta los escenarios por ti.

1

Dale la documentación a tu IA

Pega esta URL en tu asistente (Claude, Cursor, Copilot, …).

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

Describe qué probar

Un prompt inicial listo para pegar — completa tus flujos.

Lee https://windup.run/es/llms.txt y configura pruebas E2E de Windup para mi app, luego escribe escenarios para estos flujos: ...