|
| 1 | +--- |
| 2 | +name: qa-visual |
| 3 | +description: Use when you need to launch, run, drive, or visually verify AFKode itself — reproducing UI/terminal bugs (scroll, rendering, last line hidden, layout), taking screenshots of the real app, typing into a live Claude Code tab, or acting as QA after a change to src/ or src-tauri/. |
| 4 | +--- |
| 5 | + |
| 6 | +# QA visual de AFKode (build + CDP + screenshots) |
| 7 | + |
| 8 | +## Overview |
| 9 | + |
| 10 | +AFKode es Tauri 2 + WebView2. El release no trae devtools, pero WebView2 |
| 11 | +acepta depuración remota vía variable de entorno al lanzar. Con |
| 12 | +`playwright-core` conectado por CDP se puede manejar la UI real, escribir |
| 13 | +en un tab de Claude Code de verdad y capturar pantalla para verificar |
| 14 | +visualmente. |
| 15 | + |
| 16 | +**Principio: una prueba visual = lanzar la app real, manejarla, y LEER el |
| 17 | +screenshot.** Un frame en blanco es un fallo de lanzamiento, no un pass. |
| 18 | + |
| 19 | +## Preflight (obligatorio, en orden) |
| 20 | + |
| 21 | +1. **¿Estoy corriendo dentro de AFKode?** Si el ancestro del proceso es |
| 22 | + `afkode.exe`, matar la app mata esta sesión. Verifica: |
| 23 | + ```powershell |
| 24 | + $p = Get-CimInstance Win32_Process -Filter "ProcessId = $PID" |
| 25 | + while ($p) { $p.Name; $p = Get-CimInstance Win32_Process -Filter "ProcessId = $($p.ParentProcessId)" -ErrorAction SilentlyContinue } |
| 26 | + ``` |
| 27 | + Si aparece `afkode.exe` en la cadena: NO cierres la app; pide al usuario |
| 28 | + correr la prueba desde otra terminal. |
| 29 | +2. **Instancia corriendo:** `tauri-plugin-single-instance` hace que un |
| 30 | + segundo lanzamiento solo enfoque la primera. Hay que cerrar la que corre: |
| 31 | + `(Get-Process afkode).CloseMainWindow()`, espera 3s, y si sigue viva |
| 32 | + `Stop-Process -Force`. El session restore reofrece los tabs al reabrir, |
| 33 | + no se pierde nada. |
| 34 | + |
| 35 | +## Build |
| 36 | + |
| 37 | +```powershell |
| 38 | +npm run tauri build -- --no-bundle # solo el exe, sin instaladores (~2-3 min) |
| 39 | +# exe: src-tauri\target\release\afkode.exe |
| 40 | +``` |
| 41 | + |
| 42 | +Para cambios solo de frontend igual hace falta el build completo: el exe |
| 43 | +embebe `dist/`. |
| 44 | + |
| 45 | +## Lanzar con CDP |
| 46 | + |
| 47 | +```powershell |
| 48 | +$env:WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS = '--remote-debugging-port=9333' |
| 49 | +Start-Process 'C:\Projects\afkode\src-tauri\target\release\afkode.exe' |
| 50 | +# verificar: Invoke-WebRequest http://127.0.0.1:9333/json/version |
| 51 | +``` |
| 52 | + |
| 53 | +La variable solo aplica a procesos lanzados desde esa shell. |
| 54 | + |
| 55 | +## Driver |
| 56 | + |
| 57 | +Usa/adapta [drive.js](drive.js) (probado). Setup una vez por scratchpad: |
| 58 | +`npm init -y; npm i playwright-core`, y ejecuta `node drive.js` **desde el |
| 59 | +scratchpad** para que `require("playwright-core")` resuelva. |
| 60 | + |
| 61 | +**Solo inspección (instancia ya corriendo):** salta el bloque que abre tab |
| 62 | +(`#btn-new-tab` + launcher) — clickearlo muta la sesión viva del usuario. |
| 63 | +Conecta, screenshot, geometría, y nada más. |
| 64 | + |
| 65 | +Claves: |
| 66 | + |
| 67 | +| Qué | Cómo | |
| 68 | +|---|---| |
| 69 | +| Conectar | `chromium.connectOverCDP("http://127.0.0.1:9333")` | |
| 70 | +| Página principal | url `http://tauri.localhost/` (hud/palette son otras páginas) | |
| 71 | +| Estado UI | `#tabs .tab`, `#empty-state` (oculto = hay sesión activa), `.resume-bar` | |
| 72 | +| Abrir tab | `#btn-new-tab` fuerza el picker; launchers = `button[data-cmd]` (`claude`, `""` = shell) | |
| 73 | +| Esperar a Claude Code | poll hasta que `.term-loader` desaparezca (~10-30 s) | |
| 74 | +| Escribir en el terminal | focus a `.term-pane.active textarea.xterm-helper-textarea`, luego `page.keyboard.type(text, {delay: 3})` | |
| 75 | +| No enviar el prompt | simplemente no mandes Enter | |
| 76 | +| Verificar | `page.screenshot()` y **leer la imagen** con la herramienta Read | |
| 77 | +| Geometría | comparar rects de `.term-pane.active`, `.xterm-screen` y el textarea (posición del cursor) | |
| 78 | +| Título de tab | `textContent` incluye el glifo `×` del botón cerrar — no hagas match exacto | |
| 79 | + |
| 80 | +**Invariantes de geometría (pass/fail):** `.xterm-screen` contenido en el |
| 81 | +pane; `screen.bottom ≤ pane.bottom + 0.5` (si no, hay filas recortadas — |
| 82 | +el bug clásico de "última línea invisible"); el textarea (celda del cursor) |
| 83 | +dentro del rect del screen. |
| 84 | + |
| 85 | +## Cleanup |
| 86 | + |
| 87 | +- Mata la instancia de prueba (`Stop-Process`) o déjala si el usuario va a |
| 88 | + seguir usándola — pero avisa que tiene el puerto de debugging abierto. |
| 89 | +- Si cerraste la app instalada del usuario (`AppData\Local\AFKode\afkode.exe`), |
| 90 | + reláncala o avisa explícitamente qué quedó corriendo. |
| 91 | + |
| 92 | +## Common mistakes |
| 93 | + |
| 94 | +| Error | Realidad | |
| 95 | +|---|---| |
| 96 | +| Lanzar segunda instancia para probar | single-instance la reduce a un focus de la primera; cierra la vieja primero | |
| 97 | +| Buscar devtools en el release | no está compilado; usa `WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS` | |
| 98 | +| Matar afkode sin chequear ancestría | si esta sesión corre dentro de afkode, te suicidas | |
| 99 | +| `page.keyboard.type` sin enfocar el xterm | el texto va a ninguna parte; enfoca el `textarea.xterm-helper-textarea` del pane activo | |
| 100 | +| Declarar éxito sin leer el screenshot | el screenshot es la evidencia; hay que mirarlo | |
| 101 | +| Probar justo tras `spawn` | Claude Code tarda; espera a que `.term-loader` desaparezca | |
0 commit comments