# Testing — 1v9: Convertite en Leyenda

Este documento describe el workflow de testing que usamos para verificar el juego de punta a punta.
Es reproducible en cualquier máquina con Node.js ≥18 y Python 3 + Playwright.

---

## 1. Validación de sintaxis JS

Extraemos el `<script>` inline y lo chequeamos con Node (sin ejecutarlo):

```bash
python3 -c "import re; open('/tmp/game.js','w').write(re.search(r'<script>(.*?)</script>', open('index.html').read(), re.S).group(1))"
node --check /tmp/game.js && echo "JS OK"
```

Esto detecta errores de sintaxis antes de tocar el navegador.

---

## 2. Smoke test local (Playwright)

Levantamos un servidor estático y jugamos una carrera completa con un bot, detectando
errores de consola y fallos de red:

```bash
python3 -m http.server 8899 --bind 0.0.0.0 &
```

Un script Playwright (chromium headless) que:
1. Abre la página en viewport móvil (390×844).
2. Completa la creación de player.
3. Elige una oferta de academia.
4. Juega hasta el resumen (clic en opciones/continuar).
5. Captura **0 errores de consola**, **0 requests fallidos** y que el resumen se muestre.

```python
from playwright.async_api import async_playwright
async def main():
    async with async_playwright() as p:
        browser = await p.chromium.launch()
        page = await browser.new_page(viewport={"width":390,"height":844})
        errs = []
        page.on("pageerror", lambda e: errs.append(str(e)))
        page.on("console", lambda m: errs.append(m.text) if m.type=="error" else None)
        page.on("requestfailed", lambda r: errs.append(r.url))
        await page.goto("http://127.0.0.1:8899/")
        # ... click thru ...
        print("ERRORS:", errs)
```

---

## 3. Layout check (sin lectura de imágenes)

Como el modelo no puede ver screenshots, verificamos el layout programáticamente:

- **Overflow horizontal**: `document.documentElement.scrollWidth > window.innerWidth` debe ser `false`.
- **Timeline colapsada en mobile**: el `.tl-body` debe tener la clase `closed` por default en viewport <768px.
- **Design tokens**: `getComputedStyle(document.documentElement)` debe devolver `--accent-ovr:#d9730a`, etc.

---

## 4. Verificación de mecánicas (tests dirigidos)

### Gating de competencias (1ª división)
Empezar en un equipo de **2ª división** y confirmar que NO aparecen eventos internacionales
hasta ascender a 1ª. Se rastrea el `dc-cat` de cada decisión contra el `G.div`.

### Cadencia de fichajes
Jugar y registrar en qué splits aparecen eventos "Fichaje". Debe ser **≥ split 4** y ~2 por carrera
(no en cada split).

### Diversidad de competencias
Jugar 10+ carreras y confirmar que aparecen las 5 (First Stand, MSI, EWC, Asian Games, Worlds).

### Stats / backend
Verificar que `G.stats` no tenga claves fantasma (`valor`) ni `NaN` al final de la carrera.

---

## 5. Export de imagen

Se fuerza el fin de carrera con datos de prueba, se clickea "Descargar imagen" y se valida el PNG con PIL:

```python
from PIL import Image
img = Image.open(path)
print(img.size, img.mode)          # 1080x1920 RGBA
print(img.convert('RGB').getpixel((100,100)))  # ~(10,10,12) dark bg
print(img.convert('L').getextrema())           # rango de luminancia (texto presente)
```

---

## 6. Test final contra producción (HTTPS)

Repetimos los smoke tests contra `https://lolero.cbcren.online` (no solo local), para validar
el deploy real (Caddy + TLS + serve de logos).

---

## Resultado esperado

- 0 errores de consola, 0 requests fallidos.
- Resumen alcanzado en 100% de las carreras.
- Sin overflow horizontal en desktop ni mobile.
- Export 1080×1920 PNG válido.
- Las 5 competencias aparecen; fichajes ≥ split 4; 2ª división no va a internacionales.