Recorre el flujo
Se abre un navegador real en tu app. Inicia sesión, navega, rellena formularios — solo úsalo.
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
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
La parte cara — averiguar las acciones del navegador — ocurre una sola vez y se convierte en datos verificables guardados en caché.
Una tarea en lenguaje natural va al planificador. El LLM emite un plan de acciones JSON — una llamada, solo en la primera ejecución.
Un ejecutor determinista (Playwright) ejecuta el plan. Postcondiciones baratas de DOM/URL verifican cada acción — sin LLM.
La trayectoria queda en caché. Cada ejecución posterior la reproduce: cero llamadas al LLM, ~1 segundo, $0, el mismo plan siempre.
Nuevo en 1.0
¿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 Se abre un navegador real en tu app. Inicia sesión, navega, rellena formularios — solo úsalo.
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.
“■ finalizar” (o Ctrl-C). Windup escribe el escenario + cachea el plan. windup run <id> lo repite en $0.
Por qué Windup
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
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.
Describe la prueba en lenguaje natural. Sin selectores, sin page objects, sin código de prueba que mantener.
A partir de la 2ª ejecución: llm_calls=0, ~1s, $0. El plan en caché se ejecuta igual siempre.
Playwright con eventos de entrada confiables (isTrusted) — clics, escritura y navegación fiables.
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”.
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.
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.
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.
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.
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.
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.
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.
Desde las rutas sin test aún, el LLM redacta un escenario por ruta descubierta — cerrando el ciclo scan → cobertura → autoría.
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.
Indexa tus rutas y elementos directamente desde el código fuente (Next.js, react-router).
Las credenciales nunca entran en el escenario, la caché, el prompt del LLM ni git — solo referencias ENV:*, resueltas en tiempo de ejecución.
Dependencias entre escenarios (p. ej. "crear factura" depende de "login") — misma sesión, con caché por dependencia.
La IA escribe un informe posterior a la ejecución citando valores reales observados — precios, mensajes, confirmaciones.
Ante un fallo, la IA lee la página real y sugiere la corrección para tu escenario.
JUnit, JSON y HTML autocontenido (--reporter). Código de salida distinto de cero ante cualquier fallo.
Google Gemini y OpenAI, elegidos por ejecución (--llm openai:gpt-5-mini). windup costs rastrea el gasto por proveedor y modelo.
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.
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.
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.
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.
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.
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.
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.
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".
Una auditoría de accesibilidad gratuita (axe-core) en la página final de cada escenario — violaciones reportadas. Informativa; nunca falla la ejecución.
Reparte la suite por turnos entre runners de CI paralelos (--shard 1/4, 2/4, …), cada uno un job separado.
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.
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
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.
{
"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 — la segunda ejecución nunca toca el modelo.
CI / CD
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.
$ npx windup run --all --reporter junit \
--report-file reports/windup.xml Fiabilidad
Los replays se miden, no se prometen. El plan en caché produce el mismo resultado en cada ejecución — sin modelo, sin flakes.
Empezar
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.
$ 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 la era de la IA
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.
Pega esta URL en tu asistente (Claude, Cursor, Copilot, …).
https://windup.run/es/llms.txt 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: ... llms-full.txt — toda la documentación en un solo archivo · markdown por página en /es/docs/<page>.md · el estándar llms.txt