Aprender AI-DLC creando un juego, parte 3: tests E2E automáticos

Parte 3 de la serie AI-DLC: un comando ejecuta el registro con el código real del correo, el inicio de sesión y una contraseña incorrecta en Linux, Chromium, Firefox y WebKit contra un backend de prueba; 28 de 28 comprobaciones por requisito y plataforma pasan en 0,7 minutos, tres veces seguidas, sin tocar nunca el grupo de usuarios de producción

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:

En resumen

  1. 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.
  2. 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ó.
  3. 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.
  4. 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-push de 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-1 solo 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.

Arquitectura de las pruebas de extremo a extremo automáticas: en la máquina del desarrollador, Playwright Test maneja Chromium, Firefox y WebKit mediante un hook en la página y una exportación de prueba de Linux sin ventana por 127.0.0.1 con un token; los escenarios se registran contra un grupo de prueba de Cognito en un sandbox de Amplify, Cognito envía el código a un subdominio e2e, Amazon SES lo guarda en un bucket de S3 que lo borra al día, el ejecutor lee el código y borra las cuentas de prueba; Amplify Hosting de producción y su grupo de Cognito solo se comprueban en modo lectura

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.1 con 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 (AccessDenied en ses: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ónPlataformasEscenariosComprobaciones (requisito × plataforma)Tiempo
1Linux3 / 3todas pasanmenos de 1 min
2Chromium, Firefox, WebKit9 / 921 / 210,7 min
3–5las cuatro12 / 12 cada una28 / 28 cada una0,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 /aidlc hasta 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.