TL;DR
- Playwright es el framework de automatización de Microsoft — auto-wait, assertions incorporados, 3 motores
- Setup en 60 segundos:
npm init playwright@latestcrea 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
Tus tests de Selenium tardan 45 minutos. Cypress no puede paralelizar sin pagar por su nube. Tus testers pasan horas debuggeando waits flaky.
Playwright resuelve estos problemas. Migré una suite de 200 tests de Selenium a Playwright — la ejecución bajó de 42 minutos a 8 en el mismo runner CI, y la tasa de tests flaky cayó de 12% a menos del 2%.
¿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).
Por qué es diferente de Selenium:
- Auto-wait — espera actionability de elementos (sin
sleep()ni waits explícitos) - Web-first assertions —
expect(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: 67K+ estrellas GitHub, 1.5M+ descargas npm semanales.
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
Prioridad de Localizadores
| Prioridad | Localizador | Ejemplo | Por qué |
|---|---|---|---|
| 1 | Role | getByRole('button', { name: 'Submit' }) | Accesibilidad, resiliente |
| 2 | Label | getByLabel('Email') | Estándar de forms |
| 3 | Placeholder | getByPlaceholder('Search') | Para inputs de búsqueda |
| 4 | Text | getByText('Welcome') | Contenido visible |
| 5 | Test ID | getByTestId('submit-btn') | Último recurso |
| 6 | CSS | locator('.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().
// 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
- Guía Avanzada de Playwright - Patrones avanzados y mejores prácticas
- Playwright vs Cypress - Comparación detallada con benchmarks
- Selenium vs Playwright - Guía de migración
- Puppeteer vs Playwright - Google vs Microsoft
- Tutorial de Cypress - Framework E2E alternativo
- Tutorial de Selenium - Básicos del framework legacy
- Cross-Browser Test Matrix - Estrategia de cobertura de browsers
- Visual AI Testing - Enfoques de regresión visual
- Gestión de Tests Flaky - Manejar tests inestables
- Tutorial de Automatización - Fundamentos de automatización
