Underc0de - La Casa de los Informáticos

Informática => QA (Quality Assurance) => Mensaje iniciado por: ANTRAX en Septiembre 12, 2026, 10:57:13 PM

Título: Playwright: guia completa de automatizacion de pruebas end-to-end
Publicado por: ANTRAX en Septiembre 12, 2026, 10:57:13 PM
Playwright: guía completa de automatización de pruebas end-to-end

Buenas gente de Underc0de. En esta sección se habla bastante de automatización, así que armé una guía sobre Playwright, que en los últimos años se convirtió en una de las herramientas más sólidas para testing end-to-end. La idea es cubrir desde qué es y cómo funciona por dentro, hasta cómo configurarlo, escribir pruebas mantenibles y meterlo en un pipeline de CI.



1. ¿Qué es Playwright?

Playwright es un framework de automatización de navegadores desarrollado por Microsoft. Permite controlar Chromium, Firefox y WebKit (el motor de Safari) con una única API, lo que significa que una misma suite de pruebas corre sobre los tres motores de renderizado principales sin reescribir nada.

Aunque su uso más común es el testing end-to-end, también sirve para scraping, automatización de tareas repetitivas en la web, generación de PDFs o capturas, y monitoreo sintético de aplicaciones en producción.

Tiene bindings oficiales para JavaScript/TypeScript, Python, .NET y Java. En esta guía voy a usar TypeScript porque es donde el ecosistema está más maduro (el test runner propio, @playwright/test, sólo existe para JS/TS), pero los conceptos aplican igual a los demás lenguajes.

2. ¿Por qué no Selenium?

La diferencia clave es arquitectónica. Selenium se comunica con el navegador mediante el protocolo WebDriver, que funciona por HTTP: cada comando es una petición y una respuesta independientes. Eso introduce latencia y, sobre todo, deja al framework ciego respecto de lo que pasa dentro de la página entre comando y comando.

Playwright usa un único canal WebSocket persistente hacia el navegador (basado en el Chrome DevTools Protocol y equivalentes). Esto le permite:


Comparado con Cypress, la ventaja principal es que Playwright no corre dentro del navegador, con lo cual no sufre las limitaciones de same-origin, soporta múltiples pestañas y dominios en un mismo test, y tiene soporte real de WebKit.

3. Instalación

Lo más simple es usar el inicializador, que crea la estructura, el archivo de configuración y un workflow de CI de ejemplo:

npm init playwright@latest
Te va a preguntar si querés TypeScript o JavaScript, dónde poner los tests y si querés el workflow de GitHub Actions. Si preferís hacerlo a mano:

npm install -D @playwright/test
npx playwright install --with-deps

Ese segundo comando es importante: Playwright descarga sus propias builds de los navegadores en lugar de usar los que tenés instalados. Puede parecer pesado, pero es lo que garantiza que el test que pasa en tu máquina pase igual en CI. El flag --with-deps instala además las librerías de sistema que los navegadores necesitan en Linux, que es lo que suele romper dentro de los contenedores.

4. Configuración: playwright.config.ts

Acá está el corazón de la herramienta. Una configuración razonable para un proyecto real:

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

export default defineConfig({
  testDir: './tests',
  fullyParallel: true,
  forbidOnly: !!process.env.CI,
  retries: process.env.CI ? 2 : 0,
  workers: process.env.CI ? 2 : undefined,
  reporter: [['html'], ['list']],

  use: {
    baseURL: process.env.BASE_URL || 'http://localhost:3000',
    trace: 'on-first-retry',
    screenshot: 'only-on-failure',
    video: 'retain-on-failure',
    actionTimeout: 10000,
  },

  projects: [
    { name: 'chromium', use: { ...devices['Desktop Chrome'] } },
    { name: 'firefox',  use: { ...devices['Desktop Firefox'] } },
    { name: 'webkit',   use: { ...devices['Desktop Safari'] } },
    { name: 'mobile',   use: { ...devices['Pixel 7'] } },
  ],

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

Repaso lo que más importa:


5. Escribiendo pruebas: locators y assertions

Un test básico:

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

test('un usuario puede iniciar sesión', async ({ page }) => {
  await page.goto('/login');

  await page.getByLabel('Usuario').fill('antrax');
  await page.getByLabel('Contraseña').fill('hunter2');
  await page.getByRole('button', { name: 'Ingresar' }).click();

  await expect(page.getByRole('heading', { name: 'Panel' })).toBeVisible();
  await expect(page).toHaveURL('/dashboard');
});

Notá que no hay una sola espera explícita. Cada acción espera sola a que el elemento esté listo, y cada expect reintenta hasta que se cumple la condición o vence el timeout.

El punto más importante para la mantenibilidad a largo plazo es cómo seleccionás los elementos. El orden de preferencia recomendado es:

[list=1]

Un detalle conceptual importante: un locator en Playwright es perezoso. Escribir page.getByRole('button') no busca nada en ese momento; sólo describe cómo encontrar el elemento. La búsqueda ocurre recién al usarlo. Por eso podés guardar un locator en una variable y reutilizarlo aunque el DOM se haya vuelto a renderizar, sin el temido StaleElementReferenceException de Selenium.

6. Page Object Model

Cuando la suite crece, conviene encapsular la interacción con cada pantalla:

export class LoginPage {
  constructor(private page: Page) {}

  usuario  = () => this.page.getByLabel('Usuario');
  password = () => this.page.getByLabel('Contraseña');
  submit   = () => this.page.getByRole('button', { name: 'Ingresar' });

  async login(user: string, pass: string) {
    await this.page.goto('/login');
    await this.usuario().fill(user);
    await this.password().fill(pass);
    await this.submit().click();
  }
}

Así, si mañana cambia el formulario, tocás un solo archivo y no cincuenta tests.

7. Las tres herramientas que más tiempo ahorran

Codegen. Abre un navegador, grabás lo que hacés a mano y te escribe el test:

npx playwright codegen https://tu-sitio.com
No lo uses como salida final, porque genera código verboso, pero para descubrir qué locator usar en un componente raro es rapidísimo.

Trace Viewer. Esta es la killer feature. Con trace: 'on-first-retry', cuando un test falla en CI se genera un archivo con la línea de tiempo completa: un snapshot del DOM antes y después de cada acción, el log de red, la consola y el código fuente sincronizado. Lo abrís con:

npx playwright show-trace trace.zip
Podés retroceder al momento exacto del fallo e inspeccionar el DOM como si tuvieras las DevTools abiertas ahí. Se acabó el "en mi máquina anda" y el debuggear a fuerza de screenshots.

Modo UI. Para desarrollo local:

npx playwright test --ui
Watch mode, viaje en el tiempo entre pasos y selección visual de locators.

8. Interceptar la red

Para tests deterministas conviene aislar el frontend del backend:

test('muestra un mensaje si la API falla', async ({ page }) => {
  await page.route('**/api/usuarios', route =>
    route.fulfill({ status: 500, body: '{"error":"boom"}' })
  );
  await page.goto('/usuarios');
  await expect(page.getByText('No pudimos cargar')).toBeVisible();
});

Poder probar los caminos de error sin tener que tirar abajo un servicio real es algo que en Selenium requiere infraestructura aparte.

9. Autenticación reutilizable

Loguearse por UI en cada test es lento. La solución es hacerlo una vez en un setup, guardar el estado de sesión y reusarlo:

// auth.setup.ts
setup('autenticar', async ({ page }) => {
  await page.goto('/login');
  await page.getByLabel('Usuario').fill(process.env.TEST_USER);
  await page.getByLabel('Contraseña').fill(process.env.TEST_PASS);
  await page.getByRole('button', { name: 'Ingresar' }).click();
  await page.context().storageState({ path: 'playwright/.auth/user.json' });
});

Después, en el config, los proyectos que dependan de ese setup arrancan con storageState ya cargado y autenticados. En suites grandes esto baja los tiempos de minutos a segundos.

10. Integración con CI

Un workflow mínimo de GitHub Actions:

name: e2e
on: [push, pull_request]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: 20 }
      - 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/

El if: always() es clave: querés el reporte y los traces especialmente cuando la corrida falla.

Para proyectos grandes se puede paralelizar con sharding (--shard=1/4) repartiendo la suite entre varias máquinas y juntando los reportes al final.

11. Buenas prácticas




En resumen: Playwright resuelve de raíz los problemas que históricamente hicieron odiar al testing E2E, que eran la inestabilidad, la lentitud y lo difícil que resultaba diagnosticar un fallo en CI. La curva de aprendizaje es corta si venís de cualquier otro framework, y el Trace Viewer por sí solo ya justifica la migración.

¿Alguien lo está usando en producción? Me interesa leer experiencias con suites grandes, sobre todo cómo manejan los tiempos de ejecución y el sharding.

Saludos!