Que Es Playwright?

Playwright es un framework moderno de automatizacion de navegadores creado por Microsoft. Proporciona una API unica para controlar navegadores Chromium, Firefox y WebKit. Lanzado en 2020, se ha convertido rapidamente en la opcion mas popular para nuevos proyectos de automatizacion.

Por Que Playwright?

CaracteristicaPlaywrightSelenium
Auto-waitingIncorporadoWaits manuales requeridos
Multi-navegadorChromium, Firefox, WebKitRequiere drivers separados
VelocidadMuy rapidoModerado
LocatorsBasados en rol, texto, test-idCSS, XPath, ID
DebuggingTrace Viewer, InspectorSolo screenshots
API testingIncorporadoRequiere herramienta separada
CodegenIncorporadoNo disponible
Ejecucion paralelaNativaRequiere Grid

Configuracion de Playwright

JavaScript/TypeScript

npm init playwright@latest

Python

pip install playwright
playwright install

Escribiendo tu Primer Test

import { test, expect } from '@playwright/test';

test('usuario puede hacer login y ver dashboard', async ({ page }) => {
  await page.goto('https://app.example.com/login');
  await page.fill('[data-testid="email"]', 'admin@test.com');
  await page.fill('[data-testid="password"]', 'secret123');
  await page.click('[data-testid="submit"]');

  await expect(page).toHaveURL('/dashboard');
  await expect(page.locator('.welcome')).toHaveText('Welcome, Admin');
});

test('login invalido muestra error', async ({ page }) => {
  await page.goto('https://app.example.com/login');
  await page.fill('[data-testid="email"]', 'wrong@test.com');
  await page.fill('[data-testid="password"]', 'wrongpass');
  await page.click('[data-testid="submit"]');

  await expect(page.locator('.error')).toHaveText('Credenciales invalidas');
});

Locators Poderosos

Locators Basados en Rol (Recomendado)

await page.getByRole('button', { name: 'Iniciar Sesion' }).click();
await page.getByRole('textbox', { name: 'Email' }).fill('admin@test.com');
await page.getByLabel('Email').fill('admin@test.com');
await page.getByPlaceholder('Ingresa tu email').fill('admin@test.com');
await page.getByText('Iniciar Sesion').click();
await page.getByTestId('login-submit').click();

Encadenamiento y Filtrado de Locators

await page.locator('.product-card').filter({ hasText: 'Mouse Inalambrico' })
  .getByRole('button', { name: 'Agregar al Carrito' }).click();

await page.locator('.product-card').nth(0).click();
await page.locator('.product-card').first().click();

Auto-Waiting

// Sin waits manuales — Playwright lo maneja
await page.click('#submit');
// Playwright espera: visible, estable, habilitado, recibiendo eventos

await expect(page.locator('.result')).toHaveText('Exito');
// Playwright reintenta hasta que la asercion pasa (dentro del timeout)

Assertions Web-First

await expect(page).toHaveTitle('Dashboard');
await expect(page).toHaveURL(/dashboard/);
await expect(page.locator('.status')).toHaveText('Activo');
await expect(page.locator('.item')).toHaveCount(5);
await expect(page.locator('#btn')).toBeVisible();
await expect(page.locator('#btn')).toBeEnabled();

Configuracion

import { defineConfig, devices } from '@playwright/test';

export default defineConfig({
  testDir: './tests',
  timeout: 30000,
  retries: process.env.CI ? 2 : 0,
  workers: process.env.CI ? 4 : undefined,
  reporter: [['html'], ['junit', { outputFile: 'results.xml' }]],

  use: {
    baseURL: 'https://app.example.com',
    screenshot: 'only-on-failure',
    video: 'retain-on-failure',
    trace: 'retain-on-failure',
  },

  projects: [
    { name: 'chromium', use: { ...devices['Desktop Chrome'] } },
    { name: 'firefox', use: { ...devices['Desktop Firefox'] } },
    { name: 'webkit', use: { ...devices['Desktop Safari'] } },
    { name: 'mobile-chrome', use: { ...devices['Pixel 5'] } },
    { name: 'mobile-safari', use: { ...devices['iPhone 13'] } },
  ],
});

Funcionalidades Avanzadas

Trace Viewer

npx playwright test
npx playwright show-trace trace.zip

El trace muestra: screenshots en cada paso, snapshots del DOM, requests de red, logs de consola y codigo fuente.

Codegen — Grabar Tests

npx playwright codegen https://app.example.com

Codegen abre un navegador y graba tus interacciones, generando codigo de test en tiempo real.

API Testing (Incorporado)

test('crear usuario via API', async ({ request }) => {
  const response = await request.post('/api/users', {
    data: { name: 'Test User', email: 'test@example.com' },
  });
  expect(response.ok()).toBeTruthy();
  const user = await response.json();
  expect(user.name).toBe('Test User');
});

test('admin crea usuario via API, verifica en UI', async ({ page, request }) => {
  const response = await request.post('/api/users', {
    data: { name: 'Nuevo Usuario', email: 'new@test.com' }
  });
  const user = await response.json();
  await page.goto(`/admin/users/${user.id}`);
  await expect(page.locator('.user-name')).toHaveText('Nuevo Usuario');
});

Intercepcion de Red

await page.route('/api/users', route => {
  route.fulfill({
    status: 200,
    body: JSON.stringify([{ id: 1, name: 'Mock User' }]),
  });
});

const [response] = await Promise.all([
  page.waitForResponse('/api/checkout'),
  page.click('#pay-button'),
]);
expect(response.status()).toBe(200);

Multiples Contextos de Navegador

test('dos usuarios interactuan en tiempo real', async ({ browser }) => {
  const adminContext = await browser.newContext();
  const userContext = await browser.newContext();
  const adminPage = await adminContext.newPage();
  const userPage = await userContext.newPage();

  await adminPage.goto('/admin/chat');
  await adminPage.fill('#message', 'Hola usuario!');
  await adminPage.click('#send');

  await userPage.goto('/chat');
  await expect(userPage.locator('.message')).toHaveText('Hola usuario!');

  await adminContext.close();
  await userContext.close();
});

Ejecutando Tests

npx playwright test                           # Todos los tests
npx playwright test tests/login.spec.ts       # Archivo especifico
npx playwright test --project=firefox         # Navegador especifico
npx playwright test --headed                  # Modo con interfaz
npx playwright test --ui                      # Modo interactivo
npx playwright test --debug tests/login.spec.ts  # Debug
npx playwright show-report                    # Reporte HTML

Ejercicio: Construye un Suite de Tests con Playwright

Crea un suite completo de Playwright:

  1. Inicializa un proyecto con TypeScript
  2. Configura 3 proyectos de navegador (Chrome, Firefox, WebKit)
  3. Crea Page Objects para Login, Dashboard y Settings
  4. Escribe 8 tests: login (valido/invalido), navegacion, formulario, API + UI, mock de red, multi-viewport, comparacion de screenshot
  5. Configura traces y screenshots al fallar
  6. Ejecuta tests en paralelo en todos los navegadores
  7. Genera y revisa el reporte HTML

Puntos Clave

  • El auto-waiting de Playwright elimina la mayoria de tests inestables por timing
  • Los locators basados en rol son la estrategia mas resistente
  • El Trace Viewer proporciona capacidades de debugging inigualables
  • API testing incorporado permite mezclar setup rapido por API con verificacion UI
  • Codegen graba interacciones y genera codigo de test
  • Ejecucion paralela nativa en Chromium, Firefox y WebKit
  • Los fixtures de Playwright se integran naturalmente con Page Object Model