Intercepción de red y Mock en Playwright

Este capítulo presenta cómo usar Playwright para interceptar, modificar y simular solicitudes de red, logrando pruebas independientes que no dependen de la API del backend.


Qué es la intercepción de red

La intercepción de red te permite intervenir cuando el navegador realiza solicitudes HTTP.

Puedesbloquear solicitudes, modificar respuestas, devolver datos simulados, para que las pruebas no dependan de API externas ni del estado de la red.


page.route() para interceptar solicitudes

page.route(url, handler)Se utiliza para interceptar todas las solicitudes de red que coinciden con el patrón de URL especificado.

Intercepción básica

Ejemplo

test('Interceptar todas las solicitudes de imágenes', async ({ page }) => {
  // Interceptar todas las imágenes PNG y JPEG
  await page.route('**/*.{png,jpg,jpeg}', route => route.abort());

  // Navegar a la página (las imágenes no se cargarán)
  await page.goto('https://www.example.com/');
  // La página puede cargar más rápido porque no se descargan imágenes
});

Patrones de coincidencia de URLSe admiten los siguientes formatos:

PatrónEjemploDescripción
URL completa'https://api.example.com/users'Coincidencia exacta
Comodines Glob'**/api/**'**Coincide con cualquier ruta
Expresión regular/\/api\/v\d\/users/Coincidencia flexible
Funciónurl => url.includes('/api/')Coincidencia mediante lógica de programación

route.abort() para bloquear solicitudes

Ejemplo

test('Bloquear scripts de análisis de terceros', async ({ page }) => {
  // Bloquear scripts de análisis como Google Analytics
  await page.route('**/*analytics*', route => route.abort());
  // Bloquear archivos CSS
  await page.route('**/*.css', route => route.abort());

  await page.goto('https://www.example.com/');
  // La página se carga sin estilos, pero no afecta las pruebas funcionales
});

route.fulfill() para simular respuestas

route.fulfill()Es el método de Mock más potente, puede devolver cualquier respuesta personalizada.

Mock de datos JSON

Ejemplo

test('Mock de la API de lista de usuarios', async ({ page }) => {
  // Interceptar la API de lista de usuarios y devolver datos simulados
  await page.route('**/api/users', async route => {
    await route.fulfill({
      status: 200,
      contentType: 'application/json',
      json: [
        { id: 1, name: 'ejemplo_user', email: '[email protected]' },
        { id: 2, name: 'test_user', email: '[email protected]' },
      ],
    });
  });

  await page.goto('https://www.example.com/users');
  // La página mostrará los datos Mock en lugar de los datos reales de la API
});

Mock de respuestas de error

Ejemplo

test('Probar el manejo de errores de la API', async ({ page }) => {
  // Simular un error 500 del servidor
  await page.route('**/api/data', async route => {
    await route.fulfill({
      status: 500,
      contentType: 'application/json',
      json: { error: 'Error interno del servidor' },
    });
  });

  await page.goto('https://www.example.com/dashboard');
  // Verificar que el mensaje de error se muestre correctamente
  await expect(page.getByText('Error interno del servidor')).toBeVisible();
});

route.continue() continuar después de modificar

No devuelve directamente datos simulados, sino que continúa enviando al servidor después de modificar la solicitud o respuesta real.

Ejemplo

test('Modificar cabeceras de solicitud', async ({ page }) => {
  await page.route('**/api/**', async (route, request) => {
    // Modificar las cabeceras de la solicitud, añadir una cabecera personalizada
    const headers = {
      ...request.headers(),
      'X-Custom-Header': 'EJEMPLO-TEST',
    };
    await route.continue({ headers });
  });

  await page.goto('https://www.example.com/');
});

test('Modificar datos POST', async ({ page }) => {
  await page.route('**/api/login', async (route, request) => {
    // Sobrescribir el body de la solicitud POST
    const postData = JSON.parse(request.postData() || '{}');
    postData.mode = 'test';  // Añadir marcador de prueba
    await route.continue({
      postData: JSON.stringify(postData),
    });
  });
});

route.fetch() solicitud real

En la función de manejo de Mock, se puede usarroute.fetch()para enviar realmente la solicitud y obtener la respuesta real, y luego modificarla.

Ejemplo

test('Modificar la respuesta real', async ({ page }) => {
  await page.route('**/api/products', async route => {
    // Primero obtener la respuesta real
    const response = await route.fetch();
    const body = await response.json();

    // Modificar los datos de la respuesta
    body.items[0].name = 'EJEMPLO nombre del producto modificado';

    // Devolver los datos modificados
    await route.fulfill({
      status: response.status(),
      contentType: 'application/json',
      json: body,
    });
  });
});

Intercepción a nivel de Context vs intercepción a nivel de Page

MétodoAlcanceEscenario de uso
page.route()Solo la página actualMock de red para una sola página
context.route()Todas las páginas bajo ese ContextReglas de Mock compartidas por múltiples páginas

Ejemplo

test.beforeEach(async ({ context }) => {
  // Interceptar en todo el Context, aplica a todas las páginas
  await context.route('**/*.css', route => route.abort());
});

test('Prueba 1', async ({ page }) => { /* Sin CSS */ });
test('Prueba 2', async ({ page }) => { /* Sin CSS */ });

Grabación y reproducción de archivos HAR

Los archivos HAR (HTTP Archive) pueden registrar todas las solicitudes de red de la página y luego reproducirlas como simulación.

Ejemplo

test('Usar archivo HAR para Mock', async ({ page }) => {
  // Cargar el registro de red desde el archivo HAR y reproducirlo
  await page.routeFromHAR('tests/hars/api-responses.har');

  await page.goto('https://www.example.com/');
  // Todas las solicitudes coincidentes obtendrán la respuesta desde el archivo HAR
});
# 录制 HAR 文件
npx playwright open --save-har=tests/hars/api-responses.har https://www.example.com/

Los archivos HAR son adecuados para simular respuestas de API numerosas o complejas. Graba una vez, y las pruebas posteriores se reproducen desde el HAR, sin depender del servidor real.

Otras extensiones