# Playwright E2E Testing - MBInventario

## Setup

### 1. Instalar Playwright
```bash
npm install
npx playwright install chromium
```

### 2. Configurar Variables de Entorno
```bash
export BASE_URL="http://localhost"  # URL del servidor
export CI=false  # False para desarrollo, true en CI
```

### 3. Asegurar que el Servidor Está Corriendo
```bash
# Asegurate que MBInventario está disponible en http://localhost
# o configura BASE_URL según tu entorno
```

---

## Ejecutar Tests

### Todos los Tests
```bash
npm test
```

### Con UI (Recomendado para Desarrollo)
```bash
npm run test:ui
```

### Modo Headed (Navegador visible)
```bash
npm run test:headed
```

### Tests Específicos
```bash
npm run test:procesos    # Solo tests de Procesos/Install
npm run test:validations # Solo tests de validaciones
npm run test:smoke       # Solo smoke tests
```

### Debug Mode
```bash
npm run test:debug
```

### Ver Reporte HTML
```bash
npm run report
```

---

## Tests Incluidos

### 1. **procesos.spec.ts** - Procesos/Install Template Validation
- ✅ Página carga correctamente (200 status)
- ✅ Checkboxes existen con valores por defecto
- ✅ Cierres HTML válidos (h3 bien formados)
- ✅ Modal de progreso existe
- ✅ Función ejecutarSqlInstalacion accesible
- ✅ Form values sanitizados
- ✅ AJAX error handling muestra alerts

### 2. **validations.spec.ts** - Form & Twig Rendering
- ✅ Checkboxes mantienen estado en form
- ✅ Boolean values convertidos correctamente
- ✅ Empty form submission validado
- ✅ Special characters no corrompen valores
- ✅ Respuesta AJAX estructura validada
- ✅ Bootstrap validation classes aplicadas
- ✅ Variables Twig renderizan correctamente
- ✅ Condicionales Twig if/elseif funcionan
- ✅ path() helper genera URLs válidas
- ✅ raw filter no introduce XSS
- ✅ includes no rompen template
- ✅ Parent block inheritance funciona

### 3. **smoke.spec.ts** - Rutas Críticas
- ✅ BackOrder no devuelve 500
- ✅ Procesos no devuelve 500
- ✅ Reporte no devuelve 500
- ✅ HTML renderiado válido en cada ruta
- ✅ CSS y JS se cargan sin errores

---

## Helpers & Fixtures

### **AppPage**
```typescript
const appPage = new AppPage(page);
await appPage.goto('/procesos/install');
await appPage.login('user', 'pass');
await appPage.logout();
const isLogged = await appPage.isLoggedIn();
```

### **FormHelper**
```typescript
const formHelper = new FormHelper(page);
await formHelper.fillText('input#name', 'value');
await formHelper.checkCheckbox('#agree');
const isChecked = await formHelper.isCheckboxChecked('#agree');
await formHelper.submit('button#submitBtn');
```

### **AjaxHelper**
```typescript
const ajaxHelper = new AjaxHelper(page);
const response = await ajaxHelper.interceptAjaxResponse('POST', '/installajax');
const json = await ajaxHelper.getLastAjaxJson('/installajax');
```

---

## Añadir Nuevos Tests

### 1. Crear archivo en `tests/e2e/nombre.spec.ts`
```typescript
import { test, expect } from '../fixtures/fixtures';
import { ROUTES } from '../fixtures/data';

test('Mi test', async ({ page, appPage, formHelper }) => {
  await appPage.goto(ROUTES.procesos);
  await expect(page.locator('h1')).toBeVisible();
});
```

### 2. Registrarlo en `playwright.config.ts` (automático)

### 3. Ejecutar
```bash
npx playwright test tests/e2e/nombre.spec.ts
```

---

## CI/CD Integration

### Ejecutar en CI
```bash
CI=true npm test
```

Características automáticas:
- 2 reintentos en caso de falla
- Screenshots en fallos
- Video de ejecución retenido en fallos
- Reporte HTML generado
- Tests ejecutados en orden serial (1 worker)

---

## Troubleshooting

### "Connection refused"
- Asegurar que servidor está corriendo en BASE_URL

### "TIMEOUT"
- Aumentar en `playwright.config.ts`: webServer.timeout

### Tests fallan por autenticación
- Algunos tests pueden fallar sin login (esto es esperado)
- Para tests autenticados, usar `appPage.login()` en test

### Reportes no abren
```bash
npm run report
```

### Actualizar Playwright
```bash
npm install @playwright/test@latest
```

---

## Variables de Fixtures

### TEST_USERS (tests/fixtures/data.ts)
```typescript
admin: { username, password, role }
user: { username, password, role }
```

### TEST_DATA
```typescript
backorder: { cliente, producto, cantidad }
reporte: { fechaInicio, fechaFin }
```

### ROUTES
```typescript
/login, /backorder, /procesos, /procesos/install, /reporte
```

---

## Next Steps

1. ✅ Ejecutar tests locales
2. ✅ Validar plantillas en navegador
3. ✅ Ejecutar con `npm run test:ui` para debugging visual
4. ✅ Verificar reporte HTML
5. ✅ Integrar en CI/CD pipeline

---

## Guiones sueltos (no son specs de Playwright)

Además de los `.spec.ts`, en `tests/e2e/` hay guiones `.mjs` que se corren a mano
contra un sitio que ya está andando. No los levanta `playwright test`: se invocan
con `node` y devuelven 0 si pasan, 1 si fallan.

| Guion | Qué comprueba |
|---|---|
| `margen-nominal-22810.mjs` | Que un margen nominal guardado no se reinicie a cero. Es el tiquete #22810 (Elena lo entra y se le vuelve a cero); el arreglo fue el PR #751. Hace el camino completo en el navegador —entrar, abrir el producto, escribir, guardar, volver a abrirlo— porque revisar el código no alcanzaba. |

```bash
MBINV_CLAVE=<clave> node tests/e2e/margen-nominal-22810.mjs <base_url> [plu]
```

La clave va por variable de entorno y **no** como argumento: lo que se pasa en la
línea de comandos lo ve cualquiera con `ps auxww` y queda en el historial del shell.
`MBINV_USUARIO` cambia el usuario, que por omisión es `mb`.

Deja capturas de pantalla en `/tmp/margen-*.png` para poder mirar qué pasó.
## ⚠️ Correr las pruebas dentro de un worktree

Los worktrees no tienen `vendor/` propio: se le hace un enlace al del checkout
principal. Eso trae una trampa que **no da ningún error**.

El classmap de composer guarda **rutas absolutas**, así que
`MB\UserBundle\Controller\SecurityController` se resuelve al archivo del checkout
**principal** — no al de la rama que se está probando. Las pruebas ejercitan el
código de `main` y devuelven verdes o rojos que no corresponden a la rama.

Pasó de verdad el 18-ago-2026: una prueba del PR #850 «demostraba» que el arreglo
no funcionaba. El arreglo estaba bien; lo que se estaba ejecutando era el archivo
de `main`, sin el cambio.

**La forma correcta de correrlas en un worktree:**

```bash
php vendor/phpunit/phpunit/phpunit -c phpunit.xml \
    --bootstrap tests/bootstrap-worktree.php --filter LoQueSea
```

Ese bootstrap antepone un autocargador PSR-4 para `MB\` apuntando al `src/` del
directorio actual, que gana sobre el classmap. Desde el checkout principal no hace
falta: `phpunit.xml` ya usa `app/autoload.php` y ahí las rutas coinciden.

**Cómo darse cuenta de que se está cayendo en la trampa:**

```php
$r = new \ReflectionClass('MB\...\LaClaseQueCambiaste');
echo $r->getFileName();   // ¿apunta al worktree o al checkout principal?
```
