e2e: tests end-to-end donde tú decides cuánta IA entra
La idea en una frase
No hay que elegir entre tests deterministas y tests con IA: se elige cuánta IA lleva cada paso, y el modelo se paga una vez.
Es la propuesta de e2e, de TesterArmy: un framework de testing end-to-end para web y móvil (TypeScript, Apache-2.0) en el que describes un objetivo en lenguaje natural y un agente maneja la app para alcanzarlo, y luego compruebas el resultado con locators y assertions en el mismo test. Todo lo que sigue sale de su README y de su documentación; no lo he probado.
Tres tipos de paso, un solo test
Un test de e2e combina tres tipos de paso, y solo dos llaman al modelo:
| Paso | API | ¿Llama al modelo? |
|---|---|---|
| Goal | agent.act |
Sí, salvo que el caché lo reproduzca |
| Assertion | agent.assert, agent.waitFor, agent.extract |
Sí |
| Locator | screen, expect |
No |
El ejemplo de su README:
test('a member upgrades to Pro', async ({ app, agent, screen }) => { await app.open('/settings/billing');
await agent.act('upgrade the workspace to the Pro plan'); await agent.assert('the invoice preview shows a prorated amount');
await expect(screen.getByRole('status')).toContainText('Pro');});Concepto: la primera línea es un agente, la última es el testing de siempre, determinista y gratis. La IA solo entra donde la pones tú.
Acciones:
- Usa
agent.actpara los flujos (qué hay que conseguir) y un locator para el resultado exacto (qué debe quedar en pantalla). - Locators en este orden de preferencia: rol y nombre, luego label, y el test id en último lugar.
- Para valores que cambian en cada ejecución (un email con timestamp),
unique(): así el paso se puede reproducir.
El replay cache: pagar el modelo una vez
Es lo que resuelve el problema económico del testing con IA. Un paso de agente que una comprobación posterior verifica queda grabado, y la siguiente ejecución lo reproduce sin llamar al modelo hasta que la app cambia. El resumen de cada ejecución lo cuenta:
AI 4.1k tokens · 2 model calls · anthropic/claude-sonnet-4.5Cache 4 replayed · 1 handed off · 1 missedNo es «grabar y rezar». Al reproducir, el runner:
- Busca cada control grabado por rol, nombre, test id y contexto, y se para si la coincidencia es ambigua.
- Comprueba la ruta final y lo que el paso cambió: qué controles aparecieron (con su estado: marcado, expandido…) y cuáles desaparecieron.
- Exige que al menos un cambio ocurra durante el replay: un resultado que ya estaba en pantalla antes de las acciones que deberían producirlo no prueba nada.
- Si algo no cuadra, no falla: degrada. El agente sigue desde la pantalla actual con el registro de lo que se ejecutó y por qué se paró (el
handed offdel resumen).
Detalles que demuestran que lo han pensado:
- Ids, tokens y timestamps en la URL se leen como placeholder:
/orders/42?t=1727780000y/orders/7?t=1727780999son la misma ruta.?mode=safey?mode=unsafe, no. - El texto que cambia en cada ejecución (fechas, duraciones, ids) no se usa para comparar.
- Solo se graba si pasa una verificación posterior: un locator matcher,
agent.assertoagent.waitFor. Unexpect(value).toBe()sobre un valor suelto o unagent.extractno cuentan.
Acción: pon siempre un check del resultado justo después de cada agent.act. Sin él, el paso nunca se graba y pagas el modelo en cada ejecución de CI.
Fallar no es lo mismo que no saber
agent.assert distingue dos resultados que casi ninguna herramienta separa:
ASSERTION_FAILED: la afirmación es falsa.ASSERTION_INCONCLUSIVE: no hay evidencia suficiente en pantalla (el dato está en otra página, aún carga o solo está en los píxeles).
Un test que no puede ver el resultado no debería decir que la app está rota.
Las otras dos assertions:
agent.waitForespera una condición y solo llama al modelo cuando la pantalla cambia.agent.extractlee datos de la pantalla a un tipo (Zod, o cualquier Standard Schema), que luego compruebas con unexpectnormal.
Con vision: true el juicio incluye una captura enmascarada. Avisan de que las imágenes añaden tokens, y tras rellenar un secreto no se envían más capturas en ese paso.
Modelos de decisión en vez de un chat
El paquete @e2e-dev/decision ejecuta agent.act y agent.assert con un modelo de decisión en lugar de un LLM. Para cada acción responde a una sola pregunta: qué operación y sobre qué elemento, eligiendo entre las opciones que salen del árbol semántico de la pantalla. Nunca genera texto libre.
- Cuando la operación es escribir, un modelo de texto pequeño redacta el valor. Lo que devuelve un modelo nunca se convierte en un selector, una URL ni una tecla, y los campos de contraseña no le llegan.
- Sirve cualquier proveedor que responda preguntas de elección con distribuciones de probabilidad; su ejemplo usa
typeSafeAi.decisionModel('jev-latest'). - Dos umbrales opcionales,
minProbabilityyminConfidence, bloquean acciones dudosas y convierten assertions débiles en inconclusas. Ellos mismos advierten de que el umbral es una decisión tuya: mídelo con tus tests antes de tocarlo.
Es la idea de Jev aplicada a un caso concreto: muchas decisiones pequeñas, tipadas y con probabilidad, en vez de un modelo que conversa.
Bug bashes: solo bugs con un test que falla
La parte más ambiciosa. Un bug bash lanza varias sesiones de exploración a la vez, cada una sobre un área de la app, y solo reporta como bug lo que un test de repro confirma.
Concepto:
- El agente lee las rutas de la app y, en una rama, el diff.
- Escribe de 5 a 10 charters: un objetivo de una frase sobre un área, con una postura (usuario nuevo, números y copy, input de borde, estado tras recargar, caminos de error). Cada uno corre con su propia persona, cuatro a la vez.
- Descarta lo que tiene una causa conocida: el entorno local, el diseño previsto, los datos semilla o los límites del propio explorador (un enlace que abre otra pestaña, por ejemplo).
- Escribe un test de repro por hallazgo, que afirma el comportamiento esperado. El hallazgo es un bug solo si ese test falla.
Acciones:
- Los tests de repro llevan el tag
bugbash: sácalos del run que bloquea el merge cone2e run --exclude-tag bugbash. - Cuando se arregla el bug, el test pasa: quítale el tag y se queda como test de regresión.
- El vídeo del explorador no se enmascara: si escribió una contraseña, revísalo antes de compartirlo.
Hecho para agentes de código
- Servidor MCP con sesiones en vivo, varias a la vez, para que un agente compruebe locators contra la app.
- Una skill (
npx skills add tester-army/e2e) con temas comobug-bash. - La documentación entera viaja en el paquete npm, en
node_modules/e2e/docs, para que los agentes la lean sin conexión.
Cautelas
- Muy joven (creado en julio de 2026) y camino de la 1.0: los autores avisan de que las APIs y la configuración pueden cambiar entre versiones menores.
- No aísla el código del test: corre con tus permisos. Para PRs no confiables hace falta un sandbox externo sin secretos ni tokens de escritura.
- Envía telemetría anónima por defecto (comandos, motores, dónde fallan las ejecuciones; no contenido ni credenciales). Se desactiva con
E2E_TELEMETRY_DISABLED=1. - Plataformas: web con Playwright (Chromium, Firefox, WebKit) y móvil con agent-device (simuladores de iOS y emuladores de Android), con la misma API. Agnóstico a la plataforma, no al lenguaje: es TypeScript.
Por dónde empezar
Hay guías de migración desde Playwright, Cypress, Selenium, Detox y Maestro, todas incrementales:
- La de Playwright propone correr e2e al lado de Playwright y migrar fichero a fichero.
- La de Cypress conserva tus atributos
data-cy(web({ testIdAttribute: 'data-cy' })).
Lo razonable: elegir un flujo que hoy sea frágil (muchos selectores, cambia a menudo), reescribirlo con un agent.act y un check determinista detrás, y mirar en el resumen de CI cuántos pasos se reproducen gratis y cuántos acaban en el agente.
Mi opinión
Me quedo con tres cosas:
- El grado de IA se decide paso a paso. Es la forma correcta de plantearlo: el agente para llegar, el locator para comprobar. No hace falta apostar el test entero a un modelo.
- El replay cache es lo que lo hace viable en CI. Pagar el modelo solo cuando la app cambia, y degradar al agente en vez de fallar, convierte el coste de cada ejecución en el coste de cada cambio. Y la regla de que un efecto que ya estaba en pantalla no prueba nada es exactamente el tipo de detalle que separa una herramienta seria de una demo.
INCONCLUSIVEy los bugs con repro son honestidad aplicada. Ni el test ni el bug bash reportan lo que no pueden demostrar. Es lo que más me gustaría ver en cualquier herramienta que use un modelo para juzgar.
Lo probaría con un flujo frágil y un ojo en la telemetría y en el aislamiento, pero no lo pondría todavía como base de toda la suite de un producto: la 1.0 aún no ha llegado.
Bibliografía:
- tester-army/e2e: Next generation e2e testing framework for web and mobile apps. TesterArmy
- Core concepts. Documentación de e2e
- Caching. Documentación de e2e
- Decision models. Documentación de e2e
- Bug bashes. Documentación de e2e
- Security. Documentación de e2e