TL;DR

  • Playwright es el framework de automatización de Microsoft — auto-wait, assertions incorporados, 3 motores
  • Setup en 60 segundos: npm init playwright@latest crea proyecto con config, test y workflow CI
  • TypeScript-first con soporte IDE best-in-class, generación de código y localizadores de accesibilidad
  • Ejecución paralela gratuita de fábrica — 3-5x más rápido que Selenium o Cypress secuencial
  • Trace Viewer + UI Mode para debugging — DOM, red, consola en cada paso del test
  • API testing incorporado, reutilización de autenticación y regresión visual

Ideal para: Equipos que quieren herramientas modernas, TypeScript y ejecución paralela rápida Omite si: Necesitas Safari real en dispositivos o tienes gran infraestructura Selenium

Playwright es el framework de automatización de navegadores open-source de Microsoft, nombrado la tecnología de testing más adoptada en la encuesta State of JS 2024. Con 95K+ stars en GitHub y 1.5M+ weekly downloads en npm, controla Chromium, Firefox y WebKit mediante protocolos nativos, no el estándar más lento de WebDriver. El resultado es auto-wait, contextos de navegador en menos de 50ms y assertions con reintentos que eliminan los waits manuales responsables de la mayoría de tests flaky. Playwright incluye trace viewer para debugging con viaje en el tiempo, codegen que graba tests desde acciones del navegador, ejecución paralela gratuita en los tres motores, y API testing incorporado. La documentación oficial en playwright.dev/docs/intro cubre desde la instalación hasta patrones avanzados con fixtures. Este tutorial recorre localizadores, Page Objects, reutilización de estado de autenticación, intercepción de red, regresión visual y sharding en CI/CD con ejemplos prácticos en TypeScript.

“El testing cross-browser solía significar mantener tres suites de tests separadas o aceptar que solo Chrome realmente estaba cubierto. Playwright cambió eso — un archivo de test genuinamente funciona en Chromium, Firefox y WebKit con comportamiento idéntico y costo CI mínimo adicional. Ese es el nivel de cobertura que realmente genera confianza en los releases.” — Yuri Kan, Senior QA Lead

¿Qué es Playwright?

Playwright es un framework de automatización open-source de Microsoft. Controla Chromium, Firefox y WebKit vía protocolos de navegador (no WebDriver). La arquitectura completa está explicada en la documentación oficial de Playwright.

Por qué es diferente de Selenium:

  • Auto-wait — espera actionability de elementos (sin sleep() ni waits explícitos)
  • Web-first assertionsexpect(locator).toBeVisible() reintenta hasta timeout
  • Contextos de navegador — sesiones aisladas en ~50ms
  • Trace viewer — debugging con snapshots DOM, red, consola
  • Codegen — genera tests grabando acciones del navegador

Ecosistema en 2026: 95K+ stars en GitHub, 1.5M+ weekly downloads en npm. La ejecución paralela es 3-5x más rápida que Selenium secuencial, y la tasa de tests flaky cae del 12% a menos del 2%.

Instalación y Configuración

Crear Proyecto (60 Segundos)

npm init playwright@latest
# Elige: TypeScript, carpeta tests, GitHub Actions, instalar navegadores

Configuración para Producción

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

export default defineConfig({
  testDir: './tests',
  timeout: 30_000,
  expect: { timeout: 5_000 },
  fullyParallel: true,
  retries: process.env.CI ? 2 : 0,
  workers: process.env.CI ? 4 : undefined,

  reporter: [
    ['html', { open: 'never' }],
    ['list'],
  ],

  use: {
    baseURL: process.env.BASE_URL || 'http://localhost:3000',
    trace: 'on-first-retry',
    screenshot: 'only-on-failure',
    video: '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 7'] } },
    { name: 'mobile-safari', use: { ...devices['iPhone 14'] } },
  ],

  webServer: {
    command: 'npm run dev',
    url: 'http://localhost:3000',
    reuseExistingServer: !process.env.CI,
  },
});

Escribiendo Tu Primer Test

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

test('user can login with valid credentials', async ({ page }) => {
  await page.goto('/login');

  // Localizadores accesibles — por role, no CSS
  await page.getByLabel('Email').fill('user@example.com');
  await page.getByLabel('Password').fill('password123');
  await page.getByRole('button', { name: 'Sign In' }).click();

  // Web-first assertions — auto-reintento hasta visible o timeout
  await expect(page).toHaveURL('/dashboard');
  await expect(page.getByText('Welcome back')).toBeVisible();
});

Ejecutando Tests

npx playwright test                        # Todos los tests, todos los browsers
npx playwright test --project=chromium     # Un solo browser
npx playwright test --headed               # Ver ventana del browser
npx playwright test --debug                # Debugger paso a paso
npx playwright test --ui                   # Modo UI interactivo
npx playwright codegen localhost:3000      # Grabar tests

Localizadores: Encontrando Elementos Correctamente

Playwright recomienda localizadores basados en accesibilidad. La guía completa de prioridad de localizadores está en la referencia de localizadores de Playwright.

Prioridad de Localizadores

PrioridadLocalizadorEjemploPor qué
1RolegetByRole('button', { name: 'Submit' })Accesibilidad, resiliente
2LabelgetByLabel('Email')Estándar de forms
3PlaceholdergetByPlaceholder('Search')Para inputs de búsqueda
4TextgetByText('Welcome')Contenido visible
5Test IDgetByTestId('submit-btn')Último recurso
6CSSlocator('.btn-primary')Frágil, evitar

Patrones Avanzados

// Filtrar por contenido
page.locator('.card').filter({ hasText: 'Premium Plan' }).getByRole('button');

// Enésimo elemento
page.getByRole('listitem').nth(2);
page.getByRole('listitem').first();

// Encadenar (dentro de una sección)
page.getByRole('navigation').getByRole('link', { name: 'Settings' });

Assertions

Los assertions reintentan automáticamente hasta el timeout (5 segundos por defecto). Sin waitForSelector(). Todos los assertions web-first están listados en la referencia de assertions de Playwright.

// Visibilidad
await expect(page.getByText('Welcome')).toBeVisible();
await expect(page.getByText('Loading')).toBeHidden();

// Texto
await expect(page.getByRole('heading')).toHaveText('Dashboard');

// Estado
await expect(page.getByRole('button')).toBeEnabled();
await expect(page.getByRole('checkbox')).toBeChecked();

// URL y title
await expect(page).toHaveURL(/dashboard/);

// Cantidad y valor
await expect(page.getByRole('listitem')).toHaveCount(5);

// Assertions suaves (no detienen el test)
await expect.soft(page.getByText('Name')).toBeVisible();

Page Object Model

// pages/LoginPage.ts
export class LoginPage {
  readonly emailInput;
  readonly passwordInput;
  readonly submitButton;

  constructor(private page: Page) {
    this.emailInput = page.getByLabel('Email');
    this.passwordInput = page.getByLabel('Password');
    this.submitButton = page.getByRole('button', { name: 'Sign In' });
  }

  async goto() { await this.page.goto('/login'); }

  async login(email: string, password: string) {
    await this.emailInput.fill(email);
    await this.passwordInput.fill(password);
    await this.submitButton.click();
  }
}

Autenticación: Reutilizar Estado de Login

No hagas login antes de cada test. Playwright puede guardar y reutilizar estado de autenticación.

// auth.setup.ts
import { test as setup, expect } from '@playwright/test';
const authFile = 'playwright/.auth/user.json';

setup('authenticate', async ({ page }) => {
  await page.goto('/login');
  await page.getByLabel('Email').fill('user@example.com');
  await page.getByLabel('Password').fill('password123');
  await page.getByRole('button', { name: 'Sign In' }).click();
  await expect(page).toHaveURL('/dashboard');
  await page.context().storageState({ path: authFile });
});
// En playwright.config.ts — agrega setup como dependencia
projects: [
  { name: 'setup', testMatch: /.*\.setup\.ts/ },
  {
    name: 'chromium',
    use: { storageState: 'playwright/.auth/user.json' },
    dependencies: ['setup'],
  },
]

Ahora cada test inicia ya logueado — ahorrando 2-5 segundos por test.

Fixtures: Setup Personalizado

Fixtures son inyección de dependencias para tests. Reemplazan beforeEach/afterEach con setup composable y type-safe.

// fixtures.ts
import { test as base } from '@playwright/test';
import { LoginPage } from './pages/LoginPage';

export const test = base.extend<{ loginPage: LoginPage }>({
  loginPage: async ({ page }, use) => {
    const loginPage = new LoginPage(page);
    await loginPage.goto();
    await use(loginPage);
  },
});

API Testing

Playwright incluye API testing incorporado — sin necesidad de Supertest o Axios.

test('CRUD user flow', async ({ request }) => {
  // CREATE
  const createResponse = await request.post('/api/users', {
    data: { name: 'John', email: 'john@example.com' }
  });
  expect(createResponse.status()).toBe(201);
  const user = await createResponse.json();

  // READ
  const getResponse = await request.get(`/api/users/${user.id}`);
  expect(getResponse.ok()).toBeTruthy();

  // DELETE
  const deleteResponse = await request.delete(`/api/users/${user.id}`);
  expect(deleteResponse.status()).toBe(204);
});

Intercepción de Red

// Mockear respuesta API
test('mostrar usuarios mockeados', async ({ page }) => {
  await page.route('/api/users', async (route) => {
    await route.fulfill({
      status: 200,
      contentType: 'application/json',
      body: JSON.stringify([{ id: 1, name: 'Mock User' }])
    });
  });
  await page.goto('/users');
  await expect(page.getByText('Mock User')).toBeVisible();
});

// Bloquear requests de terceros (acelerar tests)
await page.route('**/*google-analytics*', route => route.abort());

Testing de Regresión Visual

test('homepage coincide con snapshot', async ({ page }) => {
  await page.goto('/');
  await expect(page).toHaveScreenshot('homepage.png', {
    fullPage: true,
    maxDiffPixelRatio: 0.01, // Permitir 1% diferencia de píxeles
  });
});

Primera ejecución crea screenshots base. Las siguientes comparan contra las bases. Actualizar: npx playwright test --update-snapshots.

Debugging

UI Mode (Mejor para Desarrollo)

npx playwright test --ui

Test runner interactivo con watch mode, time-travel, pick locator, inspector de red.

Trace Viewer (Mejor para Fallos en CI)

npx playwright test --trace on
npx playwright show-trace test-results/trace.zip

Muestra timeline de cada acción con snapshots DOM, requests de red y consola. Esencial para debuggear tests que solo fallan en CI.

Integración CI/CD

name: Playwright Tests
on: [push, pull_request]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: 22 }
      - run: npm ci
      - run: npx playwright install --with-deps
      - run: npx playwright test
      - uses: actions/upload-artifact@v4
        if: always()
        with:
          name: playwright-report
          path: playwright-report/

Sharding para Suites Grandes

strategy:
  matrix:
    shard: [1/4, 2/4, 3/4, 4/4]
steps:
  - run: npx playwright test --shard=${{ matrix.shard }}

IA en Desarrollo con Playwright

Las herramientas de IA se integran naturalmente con la API legible de Playwright.

Lo que la IA hace bien:

  • Generar tests desde user stories — “usuario agrega item al carrito y hace checkout”
  • Convertir tests de Selenium/Cypress a sintaxis Playwright
  • Escribir clases Page Object desde URL o estructura HTML
  • Crear configuraciones de mock de red desde specs de API

Lo que necesita humanos:

  • Estrategia y cobertura de tests
  • Debuggear tests flaky visuales o de timing
  • Optimización de rendimiento (workers, sharding, traces)

Prompt útil:

Genera tests Playwright TypeScript para un flujo de checkout: agregar al carrito, llenar envío, seleccionar pago, confirmar orden. Usa Page Object Model y localizadores getByRole.

FAQ

¿Es Playwright mejor que Selenium?

Playwright ofrece auto-wait (elimina problemas de timing), ejecución más rápida vía protocolos de browser (no WebDriver), API TypeScript moderno. Selenium tiene soporte más amplio de browsers legacy y mayor comunidad. Para proyectos nuevos en 2026, Playwright es la mejor opción. Para suites Selenium existentes con 1000+ tests, el costo de migración puede superar los beneficios.

¿Es Playwright gratis?

Sí, completamente. Open-source bajo Apache 2.0. A diferencia de Cypress, no hay planes pagos. Ejecución paralela, trace viewer, grabación de video, regresión visual — todo gratis.

¿Puede Playwright testear apps móviles?

Playwright testea web móvil mediante emulación de dispositivos — simula viewports de iPhone, Android, tablets con eventos touch. Para apps nativas de app stores, usa Appium o XCUITest/Espresso.

¿Qué lenguajes soporta Playwright?

TypeScript, JavaScript, Python, Java, C#. TypeScript/JavaScript tienen más funciones (testing de componentes, fixtures de API) y mejor documentación. Python es excelente para equipos pytest.

¿Cuánto tiempo toma aprender Playwright?

Un developer puede escribir primeros tests en 1-2 horas con codegen. Dominar Page Objects, fixtures, reutilización de autenticación e integración CI toma 1-2 semanas. La curva de aprendizaje es más suave que Selenium gracias a auto-wait y mejores mensajes de error.

¿Puede Playwright hacer testing de regresión visual?

Sí, incorporado. await expect(page).toHaveScreenshot() captura y compara screenshots automáticamente. Primera ejecución crea imágenes base, siguientes detectan diferencias de píxeles. Configura sensibilidad con maxDiffPixelRatio.

Recursos Oficiales

Ver También