Hoy no hay simuladores. Hoy tu código controla un navegador real contra una app real.
De cero a 5 tests verdes en tu máquina.
Sesión 3 de la serie, formato LAB: ellos trabajan, tú guías. Prerrequisitos: Coding Base + Coding Classes vistos, laptop con permisos de instalación, internet. Ritmo sugerido: misiones 1-2 todos juntos (setup es donde más se atascan), 3-5 guiadas, 6-7 semi-libres con apoyo. Duración realista: 2-3 horas con pausas.
Cada una con objetivo, comandos copiables (click = copiar 📋) y criterio de éxito verificable — sabrás exactamente cuándo la lograste.
Checkbox en cada misión. Se guarda en tu navegador: cierra y vuelve cuando quieras, tu avance sigue ahí.
Atáscate primero, pide pista después. El atasco es parte del entrenamiento — en el trabajo real no hay slide con la respuesta.
Esto NO es para mirar. Cada misión se hace en TU terminal y TU editor, en paralelo.
Nadie se queda atrás: el archivo es tuyo para siempre. Lo que no termines hoy, lo terminas en casa.
Coding Base ✓ y Coding Classes ✓ (o saber: variables, funciones, async/await, clases). Sin eso, primero esos decks.
Establece el contrato del lab: trabajo activo, pistas solo tras intentar, criterio de éxito como juez (no tu opinión). El checkbox persistente baja la ansiedad de los lentos. Pide a todos abrir terminal AHORA — la transición mental de "ver slides" a "trabajar" ocurre en este momento.
App real construida A PROPÓSITO para práctica de QA automation. Rompe lo que quieras — para eso existe.
Login / Registro24 componentes UIDashboard kanbanAPI + docs
email: testuser@upex.dev
password: Test123!
También puedes registrar tu propio usuario — eso será uno de tus tests.
Regla de oro del lab: los códigos de ejemplo en estas slides muestran la FORMA correcta. Los selectores exactos de cada elemento los descubres TÚ con codegen y el inspector — así funciona el trabajo real: nadie te regala los selectores.
M1-M2 → kit + proyecto
M3-M4 → grabar y ejecutar tu primer test
M5 → romper y diagnosticar
M6 → 4 specs a mano
M7 → 🏆 suite completa verde
Navega el dojo en vivo 2 minutos: login con las credenciales demo, muestra el dashboard y la página de componentes. La regla de oro es el seguro anti-frustración: si un selector de las slides no coincide exacto con la app, ESO es lo esperado — descubrirlos es la habilidad que entrena este lab. Valida antes de la clase que el dojo esté arriba.
1. Descarga e instala (versión LTS / estable):
nodejs.org → Node.js LTS · code.visualstudio.com → VS Code
2. Abre una terminal y verifica:
$ node --version v22.16.0 ← cualquier v18+ sirve $ npm --version 10.9.2
Cierra y reabre la terminal después de instalar (la terminal vieja no conoce programas nuevos). En Windows: usa la terminal de VS Code o PowerShell, no CMD viejo.
La misión más aburrida y la más traicionera: permisos de admin, antivirus corporativo, terminal sin refrescar. No avances hasta que TODOS tengan las dos versiones en pantalla. Explica qué es Node en una frase: "el motor que ejecuta JavaScript fuera del navegador — Playwright corre sobre él". npm viene incluido con Node.
El asistente pregunta — responde así:
| ¿TypeScript o JavaScript? | TypeScript ✓ |
| ¿Carpeta de tests? | tests (default) |
| ¿GitHub Actions workflow? | false (hoy no) |
| ¿Instalar browsers? | true ✓ (tarda unos minutos) |
Entra al proyecto y ejecuta los tests de ejemplo:
Running 6 tests using 4 workers 6 passed (8.3s)
Corriste 6 tests de ejemplo (incluidos en el proyecto) contra playwright.dev en 3 navegadores — SIN abrir ninguna ventana. Playwright corre headless (invisible) por defecto: por eso es tan rápido.
npx playwright test termina con 6 passed.npm init playwright = instalador oficial: descarga Playwright + navegadores (Chromium/Firefox/WebKit propios — no usa tu Chrome). La descarga de browsers tarda: lanza el comando y aprovecha para explicar mientras instala. El "6 passed" sin ventanas visibles sorprende — anticipa la explicación headless de la pista.
import { test, expect } from "@playwright/test"; test("has title", async ({ page }) => { await page.goto("https://playwright.dev/"); await expect(page).toHaveTitle(/Playwright/); });
Inventario de lo que reconoces: import ✓ test() ✓ async ({ page }) ✓ await ✓ expect ✓ — cero sorpresas. Las dos sesiones anteriores fueron exactamente para este momento.
Momento de cosecha: el árbol es el de Coding Base slide 32 y el spec se lee completo con lo aprendido. Pide a alguien que LEA el example.spec.ts en voz alta explicando cada línea — validación pública de que las bases están. Menciona playwright.config.ts sin profundizar: "ahí viven los 3 browsers del 6 passed; lo exploramos en Playwright Pro".
Se abren DOS ventanas: el navegador y el inspector (donde aparece el código en vivo). Ahora, en el navegador:
1. Navega al login
2. Escribe email y password demo
3. Click en el botón de entrar
4. Mira el inspector: 👀 el código se escribió solo
5. Copia el código grabado a un archivo nuevo:
tests/login.spec.ts — créalo en VS Code y pega adentro de un test("login", async ({ page }) => { ... }) si codegen no lo envolvió ya.
Verifica que el panel "Record" esté activo (botón rojo). Si cerraste el inspector por accidente: cierra todo y relanza el comando.
Codegen es un borrador, no un producto. Graba TODO lo que haces (incluso clicks accidentales) y no agrega aserciones inteligentes. La próxima slide: limpiarlo.
tests/login.spec.ts con el flujo de login grabado por codegen.El momento mágico del lab: ven su click convertirse en código instantáneamente. Deja que graben libremente 3-4 minutos. Codegen además SUGIERE los buenos locators (getByLabel, getByRole) — fíjate cómo los eligió y úsalo en la siguiente slide. Anticipa la limpieza: nadie entrega código grabado tal cual.
await page.goto("https://dojo.upexgalaxy.com/"); await page.getByRole("link", { name: "Login" }).click(); await page.getByLabel("Email").click(); ← click inútil await page.getByLabel("Email").fill("testuser@upex.dev"); await page.getByLabel("Password").click(); ← otro await page.getByLabel("Password").fill("Test123!"); await page.getByRole("button", { name: "Sign in" }).click(); // ...y AQUÍ TERMINA. ¿Dónde está la verificación? 😱
test("login exitoso en el dojo", async ({ page }) => { await page.goto("https://dojo.upexgalaxy.com/login"); await page.getByLabel("Email").fill("testuser@upex.dev"); await page.getByLabel("Password").fill("Test123!"); await page.getByRole("button", { name: /sign in/i }).click(); await expect(page).toHaveURL(/dashboard/); });
Limpieza: clicks inútiles fuera, goto directo al login, y el expect que codegen nunca escribe — sin aserción no hay test, hay paseo.
Regla profesional: codegen para descubrir locators y esqueleto, humano para intención y aserciones. Nota los locators getByLabel/getByRole que codegen eligió — son los modernos (semánticos, estables); mejor que #ids del simulador de decks anteriores: la app puede cambiar ids, pero "el botón que dice Sign in" es estable. Recuerda la regla de oro: si los textos exactos del dojo difieren, ajustan con lo que codegen grabó — eso ES el ejercicio.
1. Con navegador visible (headed):
2. El modo que vas a AMAR — UI mode:
▶ Corre tu test desde la lista
⏱️ Click en cada paso de la línea de tiempo: viaje en el tiempo — ves la página ANTES y DESPUÉS de cada acción
🔍 Pestaña "Locator": pasa el mouse sobre la página y te dice el locator de cada elemento
npx playwright test login filtra por nombre de archivo. Verifica que tu archivo se llame login.spec.ts y esté dentro de tests/.
Headed produce la foto del lab: el navegador llenando el formulario solo — el momento que vinieron a buscar. UI mode es la herramienta de trabajo diaria #1: time-travel + locator picker (esa pestaña les resuelve "¿qué selector uso?" para la misión 6). Déjalos jugar 5 minutos: cada minuto en UI mode hoy ahorra horas después.
1. En tu login.spec.ts cambia la password a "incorrecta"
2. Corre con la caja negra activada:
3. Falla (esperado ✓). Abre el reporte y el trace:
✗ login.spec.ts:3 › login exitoso Error: expect(page).toHaveURL(/dashboard/) Expected pattern: /dashboard/ Received string: "…/login" ← se quedó en login at login.spec.ts:9:24
En el reporte, click en el test rojo → Trace: línea de tiempo con screenshots de cada paso, red, consola. La caja negra completa del fallo.
Tres preguntas SIEMPRE: ¿qué esperaba? (Expected) ¿qué encontró? (Received) ¿en qué línea? (at …). El error de Playwright es un reporte de bug bien escrito — tu oficio es leerlos.
Misión anti-miedo: el rojo es información, no fracaso. El test "falló" porque ENCONTRÓ algo — login con password mala no llega al dashboard: ¡el test funciona! Distinción importante a sembrar: este fallo es "test correcto detectando comportamiento esperado del sistema" — en el trabajo real distinguirán bug real vs test mal escrito con estas mismas herramientas. No olviden restaurar la password.
TimeoutError: waiting for getByLabel("Email") — ¿qué significa?La opción C es la mala práctica más común de los juniors: timeout arriba y a rezar. Mata esa intuición HOY: timeout largo no arregla locators rotos. El reflejo correcto: trace/UI mode → mirar la página real → corregir el locator. La opción A enseña a no escalar sin diagnosticar.
| Spec | Pasos (Act) | Aserción mínima (Assert) |
|---|---|---|
| 1 · login-invalid.spec.ts | Login con password mala | El mensaje de error es visible |
| 2 · register.spec.ts | Registra un usuario nuevo (email único: usa Date.now()) | Llegas logueado o ves confirmación |
| 3 · navigation.spec.ts | Desde el home, navega a la página de componentes | La URL y el título cambian |
| 4 · components.spec.ts | Interactúa con un componente (checkbox, select…) | El estado del componente cambió |
const email = `tester${Date.now()}@upex.dev`;Date.now() = milisegundos actuales → cada corrida genera un email distinto y el test es repetible. Tu primer truco de test data dinámica.
npx playwright test <nombre>.El corazón del lab — 40-60 minutos de trabajo semi-libre. Tu rol: circular y destrabar. Atascos típicos: locator no encontrado (→ UI mode pestaña Locator), olvido de await (→ ya saben diagnosticarlo), registro falla en segunda corrida (→ pista del email único — además es la primera vez que NECESITAN test data dinámica, concepto de oro). Quien termine rápido: spec extra de logout.
test("login inválido muestra error", async ({ page }) => { // 1. ARRANGE — prepara el escenario await page.goto("https://dojo.upexgalaxy.com/login"); // 2. ACT — ejecuta la acción bajo prueba await page.getByLabel("Email").fill("testuser@upex.dev"); await page.getByLabel("Password").fill("incorrecta"); await page.getByRole("button", { name: /sign in/i }).click(); // 3. ASSERT — verifica el resultado esperado await expect(page.getByText(/invalid|incorrect/i)).toBeVisible(); });
Precondiciones de tu test case manual: "estando en la página de login…"
Los pasos. UNA acción principal bajo prueba por test.
El resultado esperado. Test sin expect no es test — es paseo.
AAA = la estructura de su test case manual con otros nombres: precondiciones / pasos / resultado esperado. Los comentarios del ejemplo son didácticos — en código real la estructura se nota sola con líneas en blanco. Regla "una acción principal por test": si el título lleva un "y" (prueba esto Y aquello), son dos tests.
Playwright espera solo a que los elementos aparezcan (auto-wait). waitForTimeout(5000) = test lento Y flaky. Si crees necesitarlo, falta un expect intermedio.
getByRole("button", { name: "Sign in" }) sobrevive rediseños; .btn-primary > div:nth-child(2) muere mañana. Locators semánticos = mantenimiento barato.
Título describe UN comportamiento verificable. Si necesitas "y" en el título, divide en dos tests.
Escribe 3 líneas → corre. Feedback inmediato = errores chicos y fáciles. Escribir 50 líneas sin correr = arqueología de bugs.
Cuatro hábitos que separan juniors de profesionales desde el día 1. El anti-sleep es el más importante: auto-wait es LA ventaja de Playwright sobre Selenium viejo; cada waitForTimeout es una confesión de no entender qué se espera. getByRole conecta con la limpieza de codegen (slide 8). Imprime estos 4 en la memoria antes del trabajo libre de M6.
Running 15 tests using 4 workers 5 specs × 3 browsers 15 passed (31.2s) 🎉
✅ Lista de tests por browser (¡corrieron en 3!)
⏱️ Duración de cada test
📷 Click en cualquiera → pasos detallados
Este reporte es lo que un QA Engineer adjunta como evidencia de ejecución
Bienvenida/o a los bugs cross-browser — los mismos pasos, distinto motor. Mira el trace de ESE browser. Si no lo resuelves hoy, anótalo: es exactamente el tipo de hallazgo que un QA reporta.
El boss revela el multiplicador: escribieron 5 tests, corrieron 15 — 3 browsers gratis (config por defecto). Eso manual serían horas; aquí 30 segundos. El reporte HTML es presentable a un lead tal cual: así se ve la evidencia profesional. Si aparece fallo cross-browser real, celébralo: hallazgo legítimo en su primer día.
Mentalidad final del lab: el rojo intermitente no se ignora ni se borra — se diagnostica con evidencia (trace). La opción B es la tentación real en equipos con prisa: tests borrados = cobertura perdida en silencio. Anticipa que Playwright Pro ataca flakiness de frente con hooks y datos aislados.
Termina las misiones pendientes — tu progreso quedó guardado en este archivo.
Spec de logout + spec del kanban del dashboard (drag & drop: investígalo).
Playwright Pro: hooks, fixtures, tu LoginPage (POM) conectada a tests reales, y API testing contra el dojo.
Lee el tablero de misiones en voz alta y celebra el progreso real (no todos llegan a 7/7 hoy — está diseñado así; el archivo persiste su avance). Logro de hoy en una frase: instalaron su entorno profesional y escribieron su primera suite real multi-browser contra una app de verdad. Recoge atascos comunes para ajustar la próxima sesión. Anuncia Playwright Pro: ahí el Page Object de Coding Classes conoce a Playwright real.