Mejores prácticas de Playwright

Este capítulo resume las mejores prácticas más importantes en la escritura y el mantenimiento de pruebas de Playwright, para ayudarte a escribir pruebas estables y mantenibles.


Filosofía de pruebas

Probar el comportamiento visible para el usuario

Las pruebas automatizadas deben verificar lo que los usuarios finales pueden ver e interactuar, no los detalles de implementación del código.

Por ejemplo, las pruebas deben verificar que la página muestra el texto correcto, que los botones se pueden hacer clic y que el formulario redirige a la página correcta después del envío, en lugar de verificar el valor de retorno de una función de JavaScript o la estructura interna del DOM.

Ejemplo

// No recomendado: probar detalles de implementación
expect(await page.evaluate(() => window.__store.getState().user.name))
  .toBe('ejemplo');

// Recomendado: probar lo que el usuario ve
await expect(page.getByText('Bienvenido, ejemplo')).toBeVisible();

Aislamiento de pruebas

Cada prueba debe sercompletamente independientede otras pruebas, sin depender del estado de la prueba anterior.

Playwright proporciona un Context independiente por defecto, pero también debes asegurarte de no depender del orden de ejecución de las pruebas.

Ejemplo

// No recomendado: pruebas que dependen entre sí
let createdId;
test('Crear recurso', async ({ request }) => {
  const resp = await request.post('/api/items');
  createdId = (await resp.json()).id;  // Estado compartido
});
test('Usar el recurso creado', async ({ page }) => {
  await page.goto(`/items/${createdId}`);  // Depende del resultado de la prueba anterior
});

// Recomendado: cada prueba es autosuficiente
test('Crear y usar recurso', async ({ request, page }) => {
  const resp = await request.post('/api/items');
  const id = (await resp.json()).id;
  await page.goto(`/items/${id}`);
  await expect(page.getByText('Detalles del recurso')).toBeVisible();
});

Principio de prioridad de los localizadores

Usar los localizadores en el orden recomendado puede mejorar la estabilidad de las pruebas.

PrioridadMétodoEscenario aplicable
1getByRole()El elemento tiene un rol ARIA claro
2getByLabel()El elemento de formulario está asociado a una etiqueta (label)
3getByPlaceholder()El campo de entrada tiene placeholder
4getByText()El elemento tiene texto claro
5getByAltText()La imagen tiene atributo alt
6getByTitle()El elemento tiene atributo title
7getByTestId()Plan de respaldo
8locator()CSS/XPath, última opción

Evita usar nombres de clases CSS como localizadores.

Los nombres de clases son propensos a cambiar debido a refactorizaciones de estilos, lo que provoca fallos masivos en las pruebas.


Evitar esperas innecesarias

Aprovecha el mecanismo de espera automática de Playwright, evita escribir manualmentesleepowaitForTimeout。

Ejemplo

// No recomendado: espera codificada
await page.waitForTimeout(3000);
await page.getByText('Carga de datos completada').click();

// Recomendado: confiar en la espera automática y las aserciones
await expect(page.getByText('Cargando datos...')).toBeHidden({ timeout: 10000 });
await page.getByText('Carga de datos completada').click();

No probar servicios de terceros

Prueba solo lo que puedes controlar, no dependas de la disponibilidad de servicios de terceros.

Ejemplo

// No recomendado: depender de CDN o API externos
await page.goto('https://www.example.com/');
// La página puede cargar Google Analytics, fuentes externas, etc.

// Recomendado: interceptar solicitudes de terceros y simular (mock) servicios externos
await page.route('**/*analytics*', route => route.abort());
await page.route('**/external-api/**', route => {
  route.fulfill({ json: { status: 'ok' } });
});

Usar aserciones suaves expect.soft()

Al verificar múltiples condiciones independientes, las aserciones suaves pueden informar todos los fallos de una vez, en lugar de detenerse en el primer fallo.

Ejemplo

// Recomendado: la aserción suave verifica todos los campos a la vez
await expect.soft(page.getByLabel('Nombre de usuario')).toBeVisible();
await expect.soft(page.getByLabel('Contraseña')).toBeVisible();
await expect.soft(page.getByLabel('Correo electrónico')).toBeVisible();
await expect.soft(page.getByRole('button', { name: 'Registrarse' })).toBeEnabled();
// Si faltan varios campos, se informan todos a la vez

Organizar bien los archivos de prueba

PrácticaDescripción
Dividir archivos por módulo funcionallogin.spec.ts、checkout.spec.tsesperar
Usar describe para agruparColoca las pruebas relacionadas entest.describe()Medio
Usar bien beforeEachExtrae los pasos repetidos de navegación y preparación abeforeEach
Nombres de prueba descriptivosUn buen nombre explica "qué se hizo" y "qué se espera"
Extraer código comúnLos helpers utilizados en más de 3 archivos se extraen a un módulo compartido
No exagerar con DRY2-3 líneas duplicadas son más fáciles de mantener que una abstracción excesiva

Solución de problemas comunes

Pruebas inestables (flaky)

Causas y soluciones de las pruebas inestables:

CausaSolución
sleep codificado no es lo suficientemente largoUsar el mecanismo de espera automática en lugar de esperas fijas
Depender de servicios de tercerosUsarroute()Simular (mock) solicitudes externas
Las animaciones cambian la posición de los elementosEn la configuraciónanimations: 'disabled'
Datos residuales entre pruebasAsegúrate de que cada prueba cree y limpie sus datos de forma independiente
Lógica relacionada con el tiempoUsarpage.clocktiempo fijo

El localizador no encuentra el elemento

Pasos para solucionar:

  • Confirma si el elemento está en el DOM (usandotoBeAttached()en lugar detoBeVisible())
  • Confirma si el elemento está dentro del viewport
  • Confirma si está anidado en un iframe
  • En UI Mode, usa Pick Locator para verificar el localizador
  • Comprueba si hay múltiples elementos coincidentes (Locator requiere modo estricto por defecto)
Otras extensiones