Aprender AI-DLC creando un juego, parte 3: tests E2E automáticos
Esta es la parte 3 de una serie sobre aprender AI-DLC creando un juego, World Rift Conflict, en Godot con un backend en AWS. La parte 2 terminó con una prueba de concepto de inicio de sesión que pasó, pero solo porque la comprobé a mano. Esta parte hace que esas comprobaciones se ejecuten solas.
Partes publicadas:
- Parte 1: configuración
- Parte 2: prueba de concepto
- Parte 3: tests E2E automáticos (este artículo)
- Parte 4: lo que vio la revisión
- Parte 5: dentro de una etapa
En resumen
- Un solo comando,
npm run e2e, registra a un jugador de prueba nuevo, lee el código de confirmación de un correo real, inicia sesión y prueba un código incorrecto y una contraseña incorrecta. Se ejecuta en una build de Linux sin ventana y en Chromium, Firefox y WebKit, contra un backend de prueba. - Tres ejecuciones completas seguidas pasaron las 28 comprobaciones por requisito y plataforma, en unos 0,7 minutos cada una. El grupo de usuarios de producción no se tocó.
- AI-DLC adaptó un plan de 7 etapas a este trabajo. Las prácticas y los requisitos llevaron 18 preguntas guiadas, casi todas respondidas con la opción recomendada. AWS necesitó dos autorizaciones mías.
- Una revisión de solo lectura de la cuenta de AWS antes del despliegue eliminó mi único paso manual: los registros DNS.
La pregunta
En la parte 2, la prueba de extremo a extremo era un runbook: exportar la build de Linux, registrarse con una dirección que yo pudiera leer, copiar el código de mi bandeja de entrada, iniciar sesión, probar una contraseña incorrecta y repetir todo en Chrome. Funcionó, y no sobreviviría a las próximas diez funcionalidades.
Así que el siguiente trabajo fue automatizar. Cuando el agente lo entendió primero como "automatizar la comprobación del inicio de sesión", corregí el alcance (cito mis palabras tal cual, en inglés):
it is not for automating the sign in only, it is for automating any e2e test or automation that you can do without my intervention. One thing is to stop at sensible gates and other different to waste time waiting for things that you can do/try yourself
Es decir: no es solo el inicio de sesión, sino cualquier prueba o automatización que el agente pueda hacer sin mí; parar en las aprobaciones sensatas está bien, esperar por cosas que puede hacer o intentar él mismo no. Esa frase se convirtió en el requisito que dio forma a todo lo demás.
Un plan a la medida del trabajo
Lo empecé con /aidlc compose, que propone un plan para la tarea en lugar de usar un alcance fijo. Pregunté qué significaba cada tipo de plan antes de elegir (ahora el agente tiene que explicar cada opción, una regla que guardé al principio de este trabajo), elegí "Tailor a plan" y lo guardé como alcance reutilizable, godot-e2e-automation.
Se quedó con siete etapas: Reverse Engineering, Practices Discovery, Requirements Analysis, Domain Design, Code Generation, Build and Test y CI Pipeline. Omitió la ideación, las historias de usuario y las unidades de trabajo, que aportan poco a un kit de pruebas hecho por un solo desarrollador.
Primero las prácticas, después los requisitos
Reverse Engineering leyó el repositorio y escribió nueve archivos de conocimiento del código. El más útil fue la evaluación de calidad: enumeraba los obstáculos exactos para automatizar, con opciones para cada uno. Cognito envía por correo un código que ningún script puede leer. La build web lo dibuja todo en un único canvas. Y cada ejecución real necesita un backend.
Practices Discovery preguntó entonces cómo trabaja este proyecto a partir de ahora. Ocho preguntas, y las respuestas quedaron como reglas permanentes en la memoria del equipo:
- Un hook
pre-pushde git ejecuta las pruebas antes de cada push. GitHub no puede imponer la protección de ramas en un repositorio privado gratuito, así que esta es la barrera que mantenemos nosotros. - Las pruebas se ejecutan contra un entorno de prueba separado, nunca contra el grupo de usuarios de producción.
- Las pruebas unitarias y de escena, rápidas, corren dentro de la build de Amplify, así que una prueba que falla detiene el despliegue. Las de extremo a extremo, lentas, corren en mi máquina, lanzadas por el agente.
- Primero los escenarios de aceptación, después el código, después las pruebas unitarias.
- La cobertura se mide por requisito y plataforma, porque todavía no existe una herramienta de cobertura para GDScript.
Requirements Analysis hizo ocho preguntas más. Las dos que más pesaron:
- El código por correo. Elegí un buzón de prueba real en lugar de confirmar las cuentas con una llamada de administrador. Es el paso por el que pasa todo jugador nuevo, y solo un correo real notaría si se rompe.
- El canvas. Elegí un hook solo para pruebas incluido en exportaciones de prueba aparte. Las builds para jugadores nunca lo contienen.
También elegí los tres motores de navegador, porque WebKit representa a Safari y al iPad, la única plataforma que no puedo comprobar yo mismo en Linux.
El diseño
Domain Design devolvió 16 bloques y 8 decisiones, cada una con las opciones que descartó. Antes de preguntar nada, el agente pidió a un ayudante de investigación que comprobara los hechos de los que dependían sus opciones:
- Amazon SES recibe correo en
us-east-1solo para un dominio verificado, y una cuenta puede tener un único conjunto de reglas de recepción activo por región. - gdUnit4 6.2.2 listaba Godot 4.7.1 pero todavía no 4.7.2. GUT admitía 4.7 pero no tenía límite de tiempo por prueba.
- Godot no entrega pulsaciones de teclado ni ratón simuladas en modo sin ventana.
Ese último hecho decidió la forma del hook de pruebas: escribe el texto de los campos y emite las señales de los botones, igual que ya hacían las pruebas de escena, así que todo funciona sin ventana.
Las decisiones principales:
- Backend de prueba: un único sandbox de Amplify de larga duración llamado
e2e, desplegado desde mi máquina. Una segunda rama alojada solo se desplegaría con un push, y el push es mi paso, así que las ejecuciones no podrían ocurrir sin mí. - Buzón de prueba: su propia pila CDK pequeña. Si viviera dentro del sandbox, borrar el sandbox borraría el dominio verificado y tendría que volver a añadir los registros DNS.
- Un solo ejecutor: Playwright Test ejecuta cada escenario en las cuatro plataformas. En los navegadores habla con el hook a través de la página; en Linux lanza el juego exportado y habla con el mismo hook por
127.0.0.1con un token de un solo uso. - Barrera de producción: antes de cada ejecución, y otra vez antes de lanzar cada build, el ejecutor compara el ID del grupo de usuarios de prueba con el de producción y se niega si coinciden o si falta alguno.
Generación de código
El plan tenía 17 pasos y 57 tareas, con los escenarios de aceptación primero, como decían las prácticas. Lo aprobé y un agente desarrollador lo construyó en local, sin ninguna acción en AWS, como exigen las reglas del proyecto. No se activó ninguna de sus dos condiciones de parada: que gdUnit4 no funcionara en Godot 4.7.2 o que gdtoolkit no pudiera leer el código.
Los resultados locales:
npm run test:godot 29 test cases | 0 errors | 0 failures
npm run test:unit tests 89 pass 89 fail 0
npm run test:infra tests 8 pass 8 fail 0
playwright --list 13 tests (3 scenarios x 4 platforms + production smoke)
Una desviación merece nota. La build de prueba de Linux no escribía nada en su registro hasta que el agente activó run/flush_stdout_on_print, y solo para las builds con la etiqueta e2e, así que las builds para jugadores siguen igual.
Build and Test: la parte de AWS
Aquí es donde la regla de "parar solo cuando haga falta" dio resultado. Antes de pedirme autorización, el agente revisó la cuenta en modo lectura y encontró tres hechos:
- CDK ya estaba inicializado (bootstrap) en
us-east-1. - El DNS de mi dominio era una zona alojada de Route 53 en la misma cuenta. Su correo principal pasa por ImprovMX, y un subdominio
e2e.nuevo no lo tocaría. - Mi rol de inicio de sesión no podía leer SES en absoluto (
AccessDeniedenses:DescribeActiveReceiptRuleSet).
Así que hizo tres preguntas en lugar de la prevista: autorización para el sandbox, autorización para el buzón con los registros DNS escritos en Route 53 por la propia pila, y si algo más en la cuenta recibe correo por SES. Respondí "Go", "Go + DNS in Route 53" y "Not sure".
"Not sure" cambió el diseño en el momento. Ahora la pila activa sus reglas de recepción mediante un pequeño recurso personalizado que se niega a reemplazar otro conjunto de reglas activo, y las desactiva al borrar la pila. Eso eliminó mi paso manual de DNS y el riesgo de desactivar algo que había olvidado.
Deployment completed in 42.097 seconds (sandbox e2e)
WorldRiftE2EMail ... Total time: 151.35s (mail stack)
PASS: the DNS records answer
La primera ejecución se detuvo antes de cualquier escenario, como estaba diseñado: "ENVIRONMENT NOT READY: the production outputs file ... is missing". La barrera necesita el ID del grupo de producción para poder rechazarlo. Con el ID de la app en un archivo de configuración ignorado por git, las siguientes ejecuciones pasaron:
| Ejecución | Plataformas | Escenarios | Comprobaciones (requisito × plataforma) | Tiempo |
|---|---|---|---|---|
| 1 | Linux | 3 / 3 | todas pasan | menos de 1 min |
| 2 | Chromium, Firefox, WebKit | 9 / 9 | 21 / 21 | 0,7 min |
| 3–5 | las cuatro | 12 / 12 cada una | 28 / 28 cada una | 0,7–0,8 min |
WebKit, el único motor que no podía comprobar a mano, pasó todas las veces. Después, el grupo de prueba tenía 0 usuarios, el buzón estaba vacío y el grupo de producción seguía mostrando su último cambio del día anterior.
Dos comprobaciones más se ejecutan antes de que algo llegue a producción. El nuevo paso de amplify.yml que ejecuta las pruebas de Godot antes de la exportación web se ejecutó dentro de la imagen de build real, desde una copia limpia, antes de cualquier push (29 de 29). Y el hook pre-push pasó sus siete comprobaciones.
Lo único que no podía pasar
Un objetivo no se podía comprobar: el requisito decía que el entorno de prueba cuesta como mucho unos 5 dólares al mes y que "the first month's bill confirms it", es decir, que la factura del primer mes lo confirma. Esa factura todavía no existe. AI-DLC cuenta un objetivo que no se puede verificar como una comprobación fallida y me pidió aceptarlo o parar. Lo acepté como tarea pendiente para noviembre.
Esa redacción fue mía, no un fallo de AI-DLC. Guardé una regla para que no se repita: los requisitos fijan criterios que se puedan comprobar dentro del trabajo, y todo lo que necesite datos futuros pasa a ser una tarea pendiente.
Las cifras
De aidlc engine runtime summary --json:
- 10 etapas aprobadas, 0 fallidas (3 de inicialización más las 7 del plan).
- 57 ejecuciones de sensores, 54 pasaron.
- 30 entradas en los diarios de etapa y 10 aprendizajes guardados como reglas del proyecto.
- 179 minutos desde el primer
/aidlchasta la última aprobación.
Lo que me diría a mí mismo
- Di pronto, con tus palabras, qué significa "terminado". Una frase sobre no esperar por mí dio forma al backend, al buzón y a los pasos de despliegue.
- Deja que el agente mire antes de preguntar. Una revisión de solo lectura de la cuenta convirtió un paso manual de DNS en un recurso de la pila.
- Elige el navegador que no puedes probar tú. Para mí era WebKit.
- Escribe criterios de aceptación que puedas comprobar hoy.
Qué viene después
Las pruebas funcionan y volverán a ejecutarse con cada funcionalidad nueva: añadir un escenario es añadir un archivo. La parte 4 mira la otra mitad de este trabajo: lo que los revisores y las comprobaciones de AI-DLC detectaron antes de que nada de esto se ejecutara.