Matware E2E Runner
Ejecutor de pruebas E2E basado en JSON con ejecución paralela de grupo de Chrome, verificación visual y 16 herramientas MCP.
Documentación
Inglés · Español
@matware/e2e-runner
El ejecutor de pruebas E2E nativo para IA que escribe, ejecuta y depura pruebas por ti.
E2E Runner te permite probar tu aplicación web sin escribir código de prueba. Las pruebas son JSON simple — y ni siquiera tienes que escribirlo tú: solo pídeselo a Claude Code.
🎬 Escribe una prueba pidiéndola — luego mírala ejecutarse
El panel en vivo mientras se ejecuta una suite — cada paso transmite una captura de pantalla al feed, en tiempo real.
Con el servidor MCP integrado, crear una prueba es una conversación — sin documentación, sin sintaxis que memorizar:
Tú: Crea una prueba E2E para el flujo de inicio de sesión y ejecútala.
Claude Code: escribe la prueba, la ejecuta en un navegador real y te informa — ✅
login-flowpasó en 2.3s · captura de pantalla guardada · sin errores de red.
Detrás de escena, Claude simplemente escribió y ejecutó esto. Una prueba es solo JSON — una lista ordenada de lo que hace un usuario:
[
{ "name": "login-flow", "actions": [
{ "type": "goto", "value": "/login" },
{ "type": "type", "selector": "#email", "value": "user@test.com" },
{ "type": "type", "selector": "#password", "value": "secret" },
{ "type": "click", "text": "Sign In" },
{ "type": "assert_text", "text": "Welcome back" },
{ "type": "screenshot", "value": "logged-in.png" }
]}
]
Sin imports, sin describe/it, sin paso de compilación. Si puedes leerlo, puedes escribirlo — o simplemente pídelo.
Conéctalo a Claude Code (2 comandos):
claude plugin marketplace add fastslack/mtw-e2e-runner
claude plugin install e2e-runner@matware
Ahora di "crea una prueba para X y ejecútala" — Claude obtiene 17 herramientas MCP, comandos de barra y agentes especializados.
¿Usas otro agente (Cursor, Codex, Copilot, más de 40)? Instala la habilidad:
npx skills add fastslack/mtw-e2e-runner
📖 Contenido
| Sección | Qué incluye | |
|---|---|---|
| 🚀 | Instalación y primera prueba | configuración npm · ejecuta con tu propio Chrome (sin Docker), Obscura o un pool de Docker |
| ✨ | Lo que obtienes | resumen de funciones de un vistazo |
| ✍️ | Escribir pruebas | formato de prueba · catálogo completo de acciones · reintentos · serial · módulos · autenticación · hooks |
| 🤖 | Integración con IA | Claude Code · OpenCode · 17 herramientas MCP · verificación visual · de issue a prueba |
| 📊 | Panel e información | panel en vivo · sistema de aprendizaje · registros de red · captura de pantalla |
| 🌐 | Controladores de navegador | browserless · cdp · lightpanda · obscura · steel |
| ⚙️ | CLI, configuración y CI | comandos · banderas · e2e.config.js · GitHub Actions · API programática |
🚀 Instalación — es diminuto
npm install --save-dev @matware/e2e-runner
npx e2e-runner init # scaffolds e2e/ with a sample test + config
Luego elige cómo ejecutar el navegador. No necesitas Docker a menos que quieras el pool paralelo:
Opción 1 · Usa el Chrome que ya tienes — sin Docker ⭐
Lanza cualquier navegador Chromium con un puerto de depuración y apunta el ejecutor hacia él:
google-chrome --headless=new --remote-debugging-port=9222 & # or brave / chromium / msedge
CHROME_POOL_URL=http://localhost:9222 POOL_DRIVER=cdp npx e2e-runner run --all
O intégralo en e2e.config.js para no repetirlo nunca:
export default {
baseUrl: 'http://localhost:3000', // your app — plain localhost, no docker hostname
poolUrls: ['http://localhost:9222'],
poolDriver: 'cdp',
};
Nada que instalar más allá de npm, y baseUrl es solo localhost (el navegador está en tu máquina).
Opción 2 · Obscura — un binario pequeño, sin Docker
Un único binario de ~30 MB con detección anti-detección integrada. Instálalo una vez, ejecútalo, apunta el ejecutor hacia él:
obscura serve --port 9222 --stealth &
CHROME_POOL_URL=http://localhost:9222 POOL_DRIVER=obscura npx e2e-runner run --all
npx e2e-runner pool start (con poolDriver: 'obscura' en tu configuración) imprime el comando de instalación exacto para tu sistema operativo.
Opción 3 · Pool de Docker — paralelo, para CI y suites grandes
Un pool de Chrome compartido y gestionado por cola que ejecuta muchas pruebas a la vez:
npx e2e-runner run --all # the first run auto-starts the Docker pool for you
Requiere Docker. Configura baseUrl: 'http://host.docker.internal:3000' para que el Chrome en contenedor pueda alcanzar tu aplicación.
¿Por qué host.docker.internal (solo opción Docker)?
Con el pool de Docker, Chrome se ejecuta dentro de un contenedor, por lo que localhost allí significa el contenedor — no tu máquina. host.docker.internal conecta con tu host. En Linux (Docker Engine, no Docker Desktop) agrega --add-host=host.docker.internal:host-gateway, o usa tu IP de LAN. Las opciones 1 y 2 no tienen esto — el navegador es local, así que localhost simple funciona.
Escribe tu primera prueba
Abre e2e/tests/sample.json — un flujo es una lista ordenada de acciones:
[
{ "name": "homepage loads", "actions": [
{ "type": "goto", "value": "/" },
{ "type": "assert_text", "text": "Welcome" },
{ "type": "screenshot", "value": "home.png" }
]}
]
Ejecútala con npx e2e-runner run --all. Los resultados — aprobado/fallido, tiempos, capturas de pantalla, errores de red — se imprimen en tu terminal y en el panel web si está abierto.
Agregar OpenCode (opcional)
cp node_modules/@matware/e2e-runner/opencode.json ./
mkdir -p .opencode && cp -r node_modules/@matware/e2e-runner/.opencode/* .opencode/
Consulta OPENCODE.md para más detalles.
Actualización
Cada método de instalación se actualiza por separado — actualiza el que uses:
# npm dependency (per project)
npm install --save-dev @matware/e2e-runner@latest
# Claude Code plugin
claude plugin update e2e-runner@matware
# MCP-only install (npx caches the package — pin @latest to force a refresh)
claude mcp add --transport stdio --scope user e2e-runner \
-- npx -y -p @matware/e2e-runner@latest e2e-runner-mcp
[!NOTA] Dos trampas: (1)
npxprefiere una copia encontrada en elnode_modulesdel proyecto sobre su propio caché — si un proyecto fija una versión antigua, el servidor MCP y el panel ejecutan esa versión antigua, así que actualiza también la dependencia del proyecto. (2) Los procesos ya en ejecución mantienen el código antiguo en memoria: después de actualizar, reinicia el panel y reconecta el servidor MCP (/mcp→e2e-runner→ Reconectar, o reinicia tu sesión).
✨ Lo que obtienes
🧪 Pruebas sin código — archivos JSON que cualquier persona de tu equipo puede leer y escribir. Sin JavaScript, sin compilación, sin bloqueo de framework.
🤖 Pruebas impulsadas por IA — Claude Code crea, ejecuta y depura pruebas de forma nativa a través de 17 herramientas MCP. Pídele "prueba el flujo de pago" y construye el JSON, lo ejecuta y te informa.
🐛 Pipeline de issue a prueba — Pega una URL de issue de GitHub o GitLab. El ejecutor la obtiene, genera pruebas E2E, las ejecuta y te dice: bug confirmado o no reproducible.
👁️ Verificación visual — Describe cómo debería verse la página en inglés simple. La IA captura una captura de pantalla y juzga aprobado/fallido según tu descripción. Sin configuración de comparación de píxeles.
🧠 Sistema de aprendizaje — Rastrea la estabilidad de las pruebas entre ejecuciones. Detecta pruebas flaky, selectores inestables, APIs lentas y patrones de error — luego muestra información accionable.
⚡ Ejecución paralela — Ejecuta N pruebas simultáneamente contra un pool de navegadores compartido (browserless, CDP crudo, Lightpanda, Obscura o Steel). Modo serial disponible para pruebas que comparten estado.
🎯 Controladores de navegador conectables — Elige el motor que se adapte a cada prueba: Chrome real vía browserless, Lightpanda u Obscura para ejecuciones rápidas y ligeras, Steel para sesiones gestionadas. Configura driver por prueba o anula toda la ejecución con --driver.
📊 Panel en tiempo real — Vista de ejecución en vivo, historial de ejecuciones con gráficos de tasa de aprobación, galería de capturas de pantalla con búsqueda por hash, registros de solicitudes de red expandibles.
🔁 Reintentos inteligentes — Reintentos a nivel de prueba y de acción con retrasos configurables. Las pruebas flaky se detectan y se marcan automáticamente.
📦 Módulos reutilizables — Extrae flujos comunes (inicio de sesión, navegación, configuración) en módulos parametrizados y refiérelos con $use.
🏗️ Listo para CI — Salida XML JUnit, código de salida 1 en fallo, capturas de pantalla de error capturadas automáticamente. Ejemplo de GitHub Actions incluido.
🌐 Multi-proyecto — Un panel agrega resultados de pruebas de todos tus proyectos. Un pool de Chrome los sirve a todos.
🐳 Portátil — Chrome se ejecuta en Docker, las pruebas son archivos JSON en tu repositorio. Funciona en cualquier máquina con Node.js y Docker.
✍️ Escribir pruebas
Todo sobre la creación de pruebas — el formato de archivo, el vocabulario completo de acciones, reintentos, aislamiento de estado y reutilización. Expande lo que necesites:
Formato de prueba y estructura de archivos
Cada archivo .json en e2e/tests/ contiene un array de pruebas. Cada prueba tiene un name y actions secuenciales:
[
{
"name": "homepage-loads",
"actions": [
{ "type": "goto", "value": "/" },
{ "type": "assert_visible", "selector": "body" },
{ "type": "assert_url", "value": "/" },
{ "type": "screenshot", "value": "homepage.png" }
]
}
]
Los archivos de suite pueden tener prefijos numéricos para ordenar (01-auth.json, 02-dashboard.json). La bandera --suite coincide con o sin el prefijo, así que --suite auth encuentra 01-auth.json.
Catálogo de acciones — navegación, entrada e interacción
| Acción | Campos | Descripción |
|---|---|---|
goto | value | Navegar a URL (relativa a baseUrl o absoluta) |
click | selector o text | Hacer clic por selector CSS o texto visible. El modo texto también toma scope: "dialog", visible: true, last: true |
type / fill | selector, value | Limpiar campo y escribir texto |
wait | selector, text, gone, o value (ms) | Esperar a que aparezca un elemento/texto, a que gone desaparezca (spinner/diálogo), o retraso fijo. Prefiere condiciones sobre value fijos |
screenshot | value (nombre de archivo) | Capturar una captura de pantalla |
select | selector, value | Seleccionar una opción de lista desplegable |
clear | selector | Limpiar un campo de entrada |
press | value | Pulsar una tecla del teclado (Enter, Tab, etc.) |
scroll | selector o value (px) | Desplazarse a un elemento o por cantidad de píxeles |
hover | selector | Pasar el cursor sobre un elemento |
evaluate | value | Ejecutar JavaScript en el contexto del navegador |
navigate | value | Navegación del navegador (back, forward, reload) |
clear_cookies | — | Limpiar todas las cookies de la página actual |
wait_network_idle | opcional value (ms de inactividad, predeterminado 500), timeout | Esperar hasta que la red haya estado inactiva durante value ms — útil después de acciones que disparan solicitudes en segundo plano |
set_storage | value ("key=val"), opcional selector: "session" | Establecer una clave localStorage (o sessionStorage con selector: "session") |
gql | value (consulta), opcional text (variables JSON), opcional selector (aserción) | Ejecutar una consulta/mutación GraphQL vía fetch en la página, con el token de autenticación leído de localStorage. Falla en errores de GraphQL. selector es una expresión JS que se evalúa contra la r de respuesta (p. ej. "r.data.users.length > 0"). Instala window.__e2eGql para pasos evaluate posteriores |
Clic por texto — cuando click usa text en lugar de selector, busca en elementos interactivos y de contenido comunes:
button, a, [role="button"], [role="tab"], [role="menuitem"], [role="option"],
[role="listitem"], div[class*="cursor"], span, li, td, th, label, p, h1-h6
{ "type": "click", "text": "Sign In" }
Aserciones — verifica texto, elementos, URLs, conteos y red
| Acción | Campos | Descripción | |--------|--------|-------------| | `assert_text` | `text` | Verifica que el texto exista en cualquier parte de la página (subcadena) | | `assert_no_text` | `text` | Verifica que el texto NO aparezca en ninguna parte de la página — opuesto de `assert_text` | | `assert_text_in` | `selector`, `text`, opcional `value: "exact"` | Verifica texto dentro de un contenedor con alcance. `text` es una expresión regular que no distingue mayúsculas por defecto; `value: "exact"` cambia a subcadena que distingue mayúsculas | | `assert_element_text` | `selector`, `text`, opcional `value: "exact"` | Verifica que el texto del elemento contenga (o coincida exactamente) con el texto esperado | | `assert_url` | `value` | Verifica la ruta URL actual o la URL completa. Las rutas (`/dashboard`) se comparan solo contra el nombre de la ruta | | `assert_visible` | `selector` | Verifica que el elemento exista y sea visible | | `assert_not_visible` | `selector` | Verifica que el elemento esté oculto o no exista | | `assert_attribute` | `selector`, `value` | Comprueba el atributo: `"type=email"` para el valor, `"disabled"` para la existencia | | `assert_class` | `selector`, `value` | Verifica que el elemento tenga una clase CSS | | `assert_input_value` | `selector`, `value` | Verifica que el `.value` de entrada/selección/área de texto contenga texto | | `assert_matches` | `selector`, `value` (expresión regular) | Verifica que el texto del elemento coincida con un patrón de expresión regular | | `assert_count` | `selector`, `value` | Verifica el conteo de elementos: exacto (`"5"`), u operadores (`">3"`, `">=1"`, `"<10"`) | | `assert_no_network_errors` | — | Falla si alguna solicitud de red falló (p. ej., `ERR_CONNECTION_REFUSED`) | | `assert_storage` | `value` (`"key"` o `"key=expected"`), opcional `selector: "session"` | Verifica que una clave `localStorage`/`sessionStorage` exista o tenga un valor específico | | `assert_visual` | `value` (imagen dorada), opcional `selector`, `text` (diferencia máxima, p. ej., `"0.02"`), `fullPage`, `maskRegions`, `threshold` | Regresión visual: compara una captura de pantalla contra una referencia dorada. La primera ejecución guarda la dorada; las ejecuciones posteriores fallan si más píxeles difieren que el umbral (predeterminado 2%) y escriben una imagen de diferencia | | `get_text` | `selector` | Extrae el texto del elemento (sin aserción, nunca falla). Resultado: `{ value: "..." }` |
Acciones conscientes del framework — React/MUI sin plantilla de evaluate
Estas acciones manejan patrones comunes en aplicaciones React/MUI que normalmente requieren plantilla verbosa de evaluate:
| Acción | Campos | Descripción |
|---|---|---|
type_react | selector, value, opcional blur, waitAfter | Escribe en entradas controladas de React usando el asignador de valor nativo. Despacha eventos input + change para que el estado de React se actualice correctamente. blur: true confirma al desenfocar; waitAfter: "<ms>" espera después (autocompletado con debounce). |
click_regex | text (expresión regular), opcional selector, opcional value: "last" | Haz clic en el elemento cuyo textContent coincida con una expresión regular (sin distinguir mayúsculas). Predeterminado: primera coincidencia. Usa value: "last" para la última coincidencia. |
click_option | text | Haz clic en un elemento [role="option"] por texto — común en menús desplegables de autocompletado/selección. |
select_combobox | text, opcional selector, filter, openWait/filterWait/waitAfter | Abre un Autocompletado/Selección de MUI, opcionalmente escribe filter, luego haz clic en la opción que coincida con text. Retrocede entre [role="option"], .MuiAutocomplete-option, li.MuiMenuItem-root. |
focus_autocomplete | text (texto de etiqueta) | Enfoca una entrada de autocompletado por su texto de etiqueta. Admite MUI y [role="combobox"] genérico. |
click_chip | text | Haz clic en un elemento chip/etiqueta por texto. Busca [class*="Chip"], [class*="chip"], [data-chip]. |
click_icon | value (id de icono), opcional selector (alcance) | Haz clic en un icono por fragmento de data-testid/data-icon/aria-label/clase o <title> SVG — MUI, FontAwesome, Heroicons, etc. Haz clic en el ancestro cliqueable más cercano (botón, enlace, pestaña). |
click_menu_item | text, opcional selector (alcance) | Haz clic en un elemento de menú por texto en [role="menuitem"], .dropdown-item, .menu-item, MUI MenuItem. |
click_in_context | text (texto del contenedor), selector (hijo) | Haz clic en un elemento hijo dentro del contenedor más pequeño que coincida con text — p. ej., el botón de eliminar de una tarjeta/fila específica. |
// Before: 5 lines of evaluate boilerplate
{ "type": "evaluate", "value": "const input = document.querySelector('#search'); const nativeSet = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value').set; nativeSet.call(input, 'term'); input.dispatchEvent(new Event('input', {bubbles: true})); input.dispatchEvent(new Event('change', {bubbles: true}));" }
// After: 1 action
{ "type": "type_react", "selector": "#search", "value": "term" }
Acciones de múltiples pestañas — ventanas emergentes, ventanas OAuth y flujos entre pestañas
| Acción | Campos | Descripción |
|---|---|---|
open_tab | value (URL), opcional text (etiqueta) | Abre una nueva pestaña y navega a la URL (relativa a baseUrl o absoluta). La etiqueta predeterminada es tab-<n> |
switch_tab | value | Cambia la pestaña activa por etiqueta, índice numérico o coincidencia de título/URL (expresión regular o subcadena). "default" regresa a la pestaña original |
wait_for_tab | opcional text (etiqueta), timeout | Espera una nueva pestaña/ventana emergente abierta por la aplicación (window.open, target="_blank") y la convierte en la pestaña activa |
assert_tab_count | value | Verifica el número de pestañas abiertas: exacto ("2") u operadores (">=2") |
close_tab | opcional value (etiqueta) | Cierra la pestaña actual (o nombrada) y vuelve a la última restante |
Todas las acciones posteriores se ejecutan en la pestaña activa:
{ "type": "click", "text": "Open report" }
{ "type": "wait_for_tab", "text": "report" }
{ "type": "assert_text", "text": "Quarterly results" }
{ "type": "close_tab" }
Reintentos y detección de flakiness
Reintento a nivel de prueba — reintenta una prueba completa en caso de fallo. Configúralo globalmente mediante configuración o por prueba:
{ "name": "flaky-test", "retries": 3, "timeout": 15000, "actions": [...] }
Las pruebas que pasan después del reintento se marcan como flaky en el informe y el sistema de aprendizaje.
Reintento a nivel de acción — reintenta una sola acción sin volver a ejecutar toda la prueba. Útil para clics y esperas sensibles al tiempo:
{ "type": "click", "selector": "#dynamic-btn", "retries": 3 }
{ "type": "wait", "selector": ".lazy-loaded", "retries": 2 }
Configúralo globalmente: actionRetries en la configuración, --action-retries <n> CLI, o variable de entorno ACTION_RETRIES. Retraso entre reintentos: actionRetryDelay (predeterminado 500ms).
Pruebas seriales — para pruebas que comparten estado
Las pruebas que comparten estado (p. ej., dos pruebas que modifican el mismo registro) pueden competir cuando se ejecutan en paralelo. Márcalas como seriales:
{ "name": "create-patient", "serial": true, "actions": [...] }
{ "name": "verify-patient-list", "serial": true, "actions": [...] }
Las pruebas seriales se ejecutan una a la vez después de que todas las pruebas paralelas terminen — evitando interferencias sin ralentizar las pruebas independientes.
Probando aplicaciones autenticadas
El enfoque más simple — inicia sesión a través de la interfaz de usuario como un usuario real:
{
"hooks": {
"beforeEach": [
{ "type": "goto", "value": "/login" },
{ "type": "type", "selector": "#email", "value": "test@example.com" },
{ "type": "type", "selector": "#password", "value": "test-password" },
{ "type": "click", "text": "Sign In" },
{ "type": "wait", "selector": ".dashboard" }
]
},
"tests": [...]
}
Para SPA con JWT, omite el formulario de inicio de sesión inyectando el token directamente:
{ "type": "set_storage", "value": "accessToken=eyJhbGciOiJIUzI1NiIs..." }
O configúralo globalmente en la configuración:
// e2e.config.js
export default {
authToken: 'eyJhbGciOiJIUzI1NiIs...',
authStorageKey: 'accessToken',
};
Cada prueba se ejecuta en un contexto de navegador nuevo, por lo que el estado de autenticación está automáticamente limpio entre pruebas.
Más estrategias: Autenticación basada en cookies, inyección de encabezados HTTP, omisiones de OAuth/SSO, módulos de autenticación reutilizables y pruebas basadas en roles — consulta docs/authentication.md
Módulos reutilizables — extrae flujos comunes con $use
Extrae flujos comunes en módulos parametrizados:
// e2e/modules/login.json
{
"$module": "login",
"description": "Log in via the UI login form",
"params": {
"email": { "required": true, "description": "User email" },
"password": { "required": true, "description": "User password" }
},
"actions": [
{ "type": "goto", "value": "/login" },
{ "type": "type", "selector": "#email", "value": "{{email}}" },
{ "type": "type", "selector": "#password", "value": "{{password}}" },
{ "type": "click", "text": "Sign In" },
{ "type": "wait", "value": "2000" }
]
}
Úsalos en pruebas:
{
"name": "dashboard-loads",
"actions": [
{ "$use": "login", "params": { "email": "user@test.com", "password": "secret" } },
{ "type": "assert_text", "text": "Dashboard" }
]
}
Los módulos admiten validación de parámetros (los parámetros requeridos fallan rápidamente), bloques condicionales ({{#param}}...{{/param}}), composición anidada y detección de ciclos.
Hooks — beforeAll / beforeEach / afterEach / afterAll
Ejecuta acciones en puntos del ciclo de vida. Defínelos globalmente en la configuración o por suite:
{
"hooks": {
"beforeAll": [{ "type": "goto", "value": "/setup" }],
"beforeEach": [{ "type": "goto", "value": "/" }],
"afterEach": [{ "type": "screenshot", "value": "after.png" }],
"afterAll": []
},
"tests": [...]
}
Importante:
beforeAllse ejecuta en una página de navegador separada que se cierra antes de que comiencen las pruebas. UsabeforeEachpara el estado que las pruebas necesitan (cookies, localStorage, tokens de autenticación).
Patrones de exclusión — omite borradores de --all
Omite pruebas exploratorias o borradores de las ejecuciones de --all:
// e2e.config.js
export default {
exclude: ['explore-*', 'debug-*', 'draft-*'],
};
Las ejecuciones de suites individuales (--suite) no se ven afectadas por los patrones de exclusión.
🤖 Integración con IA
El punto principal: tu agente escribe, ejecuta y verifica pruebas por ti.
Claude Code — instalación del plugin e instalación solo MCP
claude plugin marketplace add fastslack/mtw-e2e-runner
claude plugin install e2e-runner@matware
Esto le da a Claude 17 herramientas MCP, una habilidad de flujo de trabajo, 4 comandos de barra (/e2e-runner:run, /e2e-runner:create-test, /e2e-runner:verify-issue, /e2e-runner:capture) y 3 agentes especializados (test-analyzer, test-creator, test-improver).
Instalación solo MCP (solo herramientas, sin habilidad/comandos/agentes):
claude mcp add --transport stdio --scope user e2e-runner \
-- npx -y -p @matware/e2e-runner e2e-runner-mcp
OpenCode
cp node_modules/@matware/e2e-runner/opencode.json ./
mkdir -p .opencode && cp -r node_modules/@matware/e2e-runner/.opencode/* .opencode/
Consulta OPENCODE.md para más detalles.
Las 17 herramientas MCP
| Herramienta | Descripción |
|---|---|
e2e_run | Ejecuta pruebas (todas, por suite o por archivo) |
e2e_list | Lista las suites de pruebas disponibles |
e2e_create_test | Crea un nuevo archivo JSON de prueba |
e2e_create_module | Crea un módulo reutilizable |
e2e_pool_status | Verifica el estado del grupo de Chrome |
e2e_app_pool_status | Inspecciona el grupo del entorno de la aplicación (forks, puertos, controladores) |
e2e_screenshot | Recupera una captura de pantalla por hash |
e2e_capture | Captura una captura de pantalla de cualquier URL |
e2e_analyze | Extrae la estructura de la página (elementos interactivos, formularios, encabezados) y emite andamios de prueba |
e2e_dashboard_start | Inicia el panel web |
e2e_dashboard_stop | Detiene el panel web |
e2e_dashboard_restart | Reinicia el panel (nuevo directorio/puerto del proyecto, limpia sesiones obsoletas) |
e2e_issue | Obtiene un problema y genera pruebas |
e2e_network_logs | Consulta registros de red para una ejecución |
e2e_learnings | Consulta información de estabilidad |
e2e_vars | Administra variables de proyecto {{var.KEY}} respaldadas por SQLite |
e2e_neo4j | Administra el grafo de conocimiento Neo4j |
El inicio/detención del grupo es solo CLI — no se expone a través de MCP.
Verificación visual — describe la página, la IA la juzga
Describe cómo debería verse la página — la IA juzga aprobado/fallido a partir de capturas de pantalla:
{
"name": "dashboard-loads",
"expect": "Patient list with at least 3 rows, no error messages, sidebar with navigation links",
"actions": [
{ "type": "goto", "value": "/dashboard" },
{ "type": "wait", "selector": ".patient-list" }
]
}
Después de que las acciones de prueba se completen, el ejecutor captura automáticamente una captura de pantalla de verificación. La respuesta MCP incluye el hash de la captura de pantalla — Claude Code la recupera y verifica visualmente contra tu descripción de expect. No se requiere clave API.
De problema a prueba — convierte un informe de error en una prueba ejecutable
Convierte issues de GitHub y GitLab en pruebas E2E ejecutables. Pega una URL de issue y obtén pruebas ejecutables — automáticamente.
Cómo funciona:
- Obtener — Extrae los detalles del issue (título, cuerpo, etiquetas) mediante
ghoglabCLI - Generar — La IA crea acciones de prueba JSON basadas en la descripción del issue
- Ejecutar — Opcionalmente ejecuta las pruebas inmediatamente para verificar si un bug es reproducible
# Fetch and display
e2e-runner issue https://github.com/owner/repo/issues/42
# Generate a test file via Claude API
e2e-runner issue https://github.com/owner/repo/issues/42 --generate
# Generate + run + report
e2e-runner issue https://github.com/owner/repo/issues/42 --verify
# -> "BUG CONFIRMED" or "NOT REPRODUCIBLE"
En Claude Code, solo pregunta:
"Obtén el issue #42 y crea pruebas E2E para él"
Lógica de verificación de bugs: Las pruebas generadas verifican el comportamiento correcto. Falla de prueba = bug confirmado. Todas las pruebas pasan = no reproducible.
Autenticación: GitHub requiere gh CLI, GitLab requiere glab CLI. Se admite GitLab autoalojado.
📊 Panel de control e información
e2e-runner dashboard # Start on default port 8484
e2e-runner dashboard --port 9090 # Custom port
Recorrido por el panel web — vista en vivo, historial, galería, estado del pool
Ejecución en vivo — monitorea pruebas en tiempo real con progreso paso a paso, duraciones y recuento de workers activos.
Suites de pruebas — explora todas las suites en todos los proyectos. Ejecuta una sola suite o todas las pruebas con un clic.
Historial de ejecuciones — sigue las tendencias de tasa de aprobación con el gráfico integrado. Haz clic en cualquier fila para expandir el detalle completo.
Detalle de ejecución — insignias PASS/FAIL, miniaturas de capturas de pantalla con hashes copiables (ss:77c28b5a), errores de consola formateados y registros de solicitudes de red.
Galería de capturas — explora todas las capturas de pantalla con búsqueda por hash (capturas de acciones, errores y verificaciones).
Estado del pool — salud del pool de Chrome: espacios disponibles, sesiones en ejecución, presión de memoria.
Sistema de aprendizaje — pruebas inestables, selectores inestables, APIs lentas
El runner aprende de cada ejecución de prueba — acumulando conocimiento sobre tu suite de pruebas con el tiempo. Consulta información mediante la herramienta MCP e2e_learnings:
| Consulta | Devuelve |
|---|---|
summary | Resumen completo de salud: tasa de aprobación, pruebas inestables, selectores inestables, problemas de API |
flaky | Pruebas que solo pasan después de reintentos |
selectors | Selectores CSS con altas tasas de fallo |
pages | Páginas con errores de consola, fallos de red, problemas de tiempo de carga |
apis | Endpoints de API con tasas de error y latencia (normalizados automáticamente: UUIDs, hashes, IDs) |
errors | Patrones de error más frecuentes, categorizados |
trends | Tasa de aprobación a lo largo del tiempo (cambia automáticamente a horaria cuando todos los datos son de un día) |
test:<name> | Historial detallado de una prueba específica |
page:<path> | Historial detallado de una página específica |
selector:<value> | Historial detallado de un selector específico |
Almacenamiento y exportación:
- SQLite (
~/.e2e-runner/dashboard.db) — predeterminado, sin configuración - Grafo de conocimiento Neo4j — opcional, para análisis basado en relaciones. Gestiona mediante la herramienta MCP
e2e_neo4jodocker compose - Informe Markdown (
e2e/learnings.md) — generado automáticamente después de cada ejecución
Narración de pruebas: Cada ejecución de prueba genera una narrativa legible por humanos de lo que sucedió paso a paso, visible en la salida CLI y en el panel de control.
Manejo de errores de red — aserciones, bandera global, registro completo
Aserción explícita — coloca assert_no_network_errors después de cargas críticas de página:
{ "type": "goto", "value": "/dashboard" },
{ "type": "wait", "selector": ".loaded" },
{ "type": "assert_no_network_errors" }
Bandera global — establece failOnNetworkError: true para fallar automáticamente cualquier prueba con errores de red:
e2e-runner run --all --fail-on-network-error
Cuando está deshabilitada (predeterminado), el runner aún recopila e informa errores de red — la respuesta MCP incluye una advertencia cuando las pruebas pasan pero tienen errores de red.
Registro de red completo — todas las solicitudes XHR/fetch se capturan con URL, método, estado, duración, encabezados de solicitud/respuesta y cuerpo de respuesta (truncado a 50KB). Visible en el panel de control con filas de detalle de solicitud expandibles.
Flujo de profundización MCP:
1. e2e_run → compact networkSummary + runDbId
2. e2e_network_logs(runDbId) → all requests (url, method, status, duration)
3. e2e_network_logs(runDbId, errorsOnly: true) → only failed requests
4. e2e_network_logs(runDbId, includeHeaders: true) → with headers
5. e2e_network_logs(runDbId, includeBodies: true) → full request/response bodies
La respuesta de e2e_run se mantiene compacta (~5KB) independientemente de cuántas solicitudes se hayan capturado. Usa e2e_network_logs con el runDbId devuelto para profundizar en los detalles bajo demanda.
Captura de pantallas — instantánea de cualquier URL bajo demanda
Captura pantallas de cualquier URL bajo demanda — no se requiere suite de pruebas:
e2e-runner capture https://example.com
e2e-runner capture https://example.com --full-page --selector ".loaded" --delay 2000
Mediante MCP, la herramienta e2e_capture admite authToken y authStorageKey para páginas autenticadas — inyecta el token en localStorage antes de navegar.
Cada captura obtiene un hash determinista (ss:a3f2b1c9). Usa e2e_screenshot para recuperar cualquier captura por hash — devuelve la imagen con metadatos (nombre de prueba, paso, tipo).
🌐 Controladores de navegador
El runner puede comunicarse con múltiples motores de navegador a través de diferentes controladores. El predeterminado es auto — sondea cada URL de pool y elige el controlador correcto por pool.
| Controlador | Motor | Sonda de detección | Cuándo usar |
|---|---|---|---|
browserless | Chromium real mediante browserless | /pressure devuelve JSON | Predeterminado. Ejecución JS de grado de producción, screencast, comportamiento completo de Chrome |
cdp | Compatible con CDP genérico (Chrome sin procesar, etc.) | /json/version alcanzable | Respaldo para cualquier servidor CDP que no sea uno de los otros |
lightpanda | Lightpanda (Zig) | /json/version Browser=lightpanda | ~9× más rápido, ~16× menos memoria que Chrome sin interfaz — ideal para pruebas de tipo scraping de alto volumen |
obscura | Obscura (Rust + V8) | /json/version Browser=obscura | ~30 MB de huella de RAM, anti-detección integrada (--stealth), se mantiene cerca de Chrome real mediante Puppeteer |
steel | Steel Browser | /v1/sessions devuelve JSON | Ciclo de vida de sesión gestionado, API REST para orquestación |
Elige un controlador por prueba / fuerza uno por ejecución
{
"tests": [
{
"name": "checkout flow (heavy JS, real Chrome)",
"driver": "browserless",
"actions": [...]
},
{
"name": "scrape product page (lightweight)",
"driver": "obscura",
"fallbackDriver": "cdp",
"actions": [...]
}
]
}
driver es opcional. Si se establece, solo los pools cuyo controlador detectado coincida se convierten en candidatos. fallbackDriver es opt-in explícito — sin él, un controlador objetivo faltante falla la prueba con un mensaje claro. La ocupación del pool no activa el respaldo; el runner espera dentro del conjunto filtrado.
Fuerza un controlador para una ejecución completa (los overrides de CLI ganan sobre los campos por prueba — útil para benchmarks A/B):
e2e-runner run --all --driver obscura
e2e-runner run --all --driver obscura --fallback-driver cdp
Ejecutando cada controlador localmente
# browserless (default) — managed by `pool start`
e2e-runner pool start
# Lightpanda — pool start uses templates/docker-compose-lightpanda.yml
e2e-runner pool start # with poolDriver: 'lightpanda' in config
# Obscura — install the binary and run it yourself
curl -LO https://github.com/h4ckf0r0day/obscura/releases/latest/download/obscura-x86_64-linux.tar.gz
tar xzf obscura-x86_64-linux.tar.gz
./obscura serve --port 9222 --stealth
# then point the runner at it: poolUrls: ['http://localhost:9222'], poolDriver: 'obscura'
⚙️ CLI, configuración y CI
Comandos CLI
# Run tests
e2e-runner run --all # All suites
e2e-runner run --suite auth # Single suite
e2e-runner run --tests path/to.json # Specific file
e2e-runner run --inline '<json>' # Inline JSON
# Pool management (CLI only, not MCP)
e2e-runner pool start # Start Chrome container
e2e-runner pool stop # Stop Chrome container
e2e-runner pool status # Check pool health
# Issue-to-test
e2e-runner issue <url> # Fetch issue
e2e-runner issue <url> --generate # Generate test via AI
e2e-runner issue <url> --verify # Generate + run + report
# Dashboard
e2e-runner dashboard # Start web dashboard
# Other
e2e-runner list # List available suites
e2e-runner capture <url> # On-demand screenshot
e2e-runner init # Scaffold project
Opciones CLI
| Bandera | Predeterminado | Descripción |
|---|---|---|
--base-url <url> | http://host.docker.internal:3000 | URL base de la aplicación |
--pool-url <ws> | ws://localhost:3333 | URL WebSocket del pool de Chrome |
--concurrency <n> | 3 | Workers de prueba paralelos |
--retries <n> | 0 | Reintentar pruebas fallidas N veces |
--action-retries <n> | 0 | Reintentar acciones fallidas N veces |
--test-timeout <ms> | 60000 | Tiempo de espera por prueba |
--timeout <ms> | 10000 | Tiempo de espera de acción predeterminado |
--output <format> | json | Informe: json, junit, both |
--env <name> | default | Perfil de entorno |
--fail-on-network-error | false | Fallar pruebas con errores de red |
--project-name <name> | nombre de dir | Nombre de visualización del proyecto |
--driver <name> | (por prueba) | Forzar controlador de pool para la ejecución: browserless, cdp, lightpanda, obscura, steel |
--fallback-driver <name> | ninguno | Respaldo explícito si ningún pool con --driver es alcanzable |
Configuración — e2e.config.js y prioridad
Crea e2e.config.js en la raíz de tu proyecto:
export default {
baseUrl: 'http://host.docker.internal:3000',
concurrency: 4,
retries: 2,
actionRetries: 1,
testTimeout: 30000,
outputFormat: 'both',
failOnNetworkError: true,
exclude: ['explore-*', 'debug-*'],
hooks: {
beforeEach: [{ type: 'goto', value: '/' }],
},
environments: {
staging: { baseUrl: 'https://staging.example.com' },
production: { baseUrl: 'https://example.com', concurrency: 5 },
},
};
Prioridad de configuración (gana la más alta):
- Banderas CLI
- Variables de entorno
- Archivo de configuración (
e2e.config.jsoe2e.config.json) - Predeterminados
Cuando se establece --env <name>, el perfil coincidente anula todo.
CI/CD — JUnit XML y GitHub Actions
e2e-runner run --all --output junit
jobs:
e2e:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- run: npm ci
- run: npx e2e-runner pool start
- run: npx e2e-runner run --all --output junit
- uses: mikepenz/action-junit-report@v4
if: always()
with:
report_paths: e2e/screenshots/junit.xml
API programática
import { createRunner } from '@matware/e2e-runner';
const runner = await createRunner({ baseUrl: 'http://localhost:3000' });
const report = await runner.runAll();
const report = await runner.runSuite('auth');
const report = await runner.runFile('e2e/tests/login.json');
const report = await runner.runTests([
{ name: 'quick-check', actions: [{ type: 'goto', value: '/' }] },
]);
Requisitos
- Node.js >= 20
- Docker — solo para Opción 3 (el pool paralelo de Chrome). Las opciones 1 y 2 no lo necesitan.
Licencia
Copyright 2026 Matias Aguirre (fastslack) — Matware
Licenciado bajo la Licencia Apache, Versión 2.0. Consulta LICENSE para más detalles.