Playwright Test

Playwright, además de ser una herramienta de automatización de navegadores, incluye unframework de pruebas completo —— Playwright Test。

Playwright Test nos ayuda a organizar casos de prueba, generar informes, ejecutar en paralelo y reintentar fallos; es completo y listo para usar.

  1. Playwright Test es unframework de pruebas integrado, sin dependencias adicionales.
  2. El archivo de configuración puede establecertiempos de espera, reintentos, informes, proyectos de navegadoretc.
  3. Los casos de prueba admitenagrupación, hooks, data-driven。
  4. Ofreceejecución paralela, informes HTML, reintentos de fallosy otras capacidades avanzadas.

Resumen del framework de pruebas

  • Framework de pruebas integrado: incluye su propio runner de pruebas, sin necesidad de instalar Jest, Mocha.
  • Librería de aserciones integrada: admiteexpectaserciones.
  • Aislamiento de pruebas: cadatestse ejecuta por defecto en un nuevo contexto de navegador, sin interferirse entre sí.
  • Funciones enriquecidas: ejecución paralela, reintentos, capturas de pantalla, grabación, informes HTML, etc.

Instalación:

npm init playwright@latest

Genera automáticamente la estructura del proyecto, incluido el archivo de configuraciónplaywright.config.js。

1. Detalles del archivo de configuración

Playwright Test utilizaplaywright.config.js(o.ts) como punto de entrada de configuración.

// playwright.config.js
import { defineConfig } from '@playwright/test';

export default defineConfig({
  testDir: './tests',         // 测试目录
  timeout: 30 * 1000,         // 单个测试超时时间
  retries: 2,                 // 失败重试次数
  reporter: [['html'], ['list']], // 测试报告类型
  use: {
    headless: true,           // 是否无头模式
    screenshot: 'only-on-failure', // 失败时截图
    video: 'retain-on-failure',    // 失败时保留视频
    baseURL: 'https://example.com', // 基础 URL
  },
  projects: [
    { name: 'Chromium', use: { browserName: 'chromium' } },
    { name: 'Firefox',  use: { browserName: 'firefox' } },
    { name: 'WebKit',   use: { browserName: 'webkit' } },
  ],
});

2. Estructura del script de pruebas

Los scripts de Playwright Test normalmente incluyen:

1. Importar la librería de pruebas

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

2. Escribir casos de prueba

test('示例测试', async ({ page }) => {
  await page.goto('https://example.com');
  await expect(page).toHaveTitle('Example Domain');
});

3. Agrupación y hooks

  • Usardescribeorganizar pruebas
  • UsarbeforeEach / afterEachpara el manejo de preparación y limpieza

Escribir casos de prueba

1. test()Uso de funciones

test('页面标题验证', async ({ page }) => {
  await page.goto('https://playwright.dev');
  await expect(page).toHaveTitle(/Playwright/);
});

2. describe()Agrupación

test.describe('用户登录模块', () => {
  test('输入正确账号密码', async ({ page }) => {
    // 登录逻辑...
  });

  test('输入错误密码', async ({ page }) => {
    // 验证错误提示...
  });
});

3. Hooks de prueba

test.describe('购物车模块', () => {
  test.beforeEach(async ({ page }) => {
    await page.goto('https://example.com/cart');
  });

  test.afterEach(async ({ page }) => {
    await page.screenshot({ path: 'cart.png' });
  });

  test('添加商品', async ({ page }) => {
    await page.click('#add-item');
    await expect(page.locator('#cart-count')).toHaveText('1');
  });
});

4. Preparación de datos de prueba

Admite pruebas parametrizadas:

const users = [
  { name: 'admin', password: '123456' },
  { name: 'guest', password: 'guest' },
];

for (const user of users) {
  test(`用户 ${user.name} 登录`, async ({ page }) => {
    await page.goto('https://example.com/login');
    await page.fill('#username', user.name);
    await page.fill('#password', user.password);
    await page.click('#submit');
    await expect(page.locator('.welcome')).toBeVisible();
  });
}

Ejecución e informes

1. Comandos de ejecución de pruebas

npx playwright test          # 运行全部测试
npx playwright test login.spec.js   # 运行单个文件
npx playwright test -g "登录"       # 运行指定用例

2. Pruebas en paralelo

Playwright por defectoejecuta en paralelo por archivo, también se puede especificar el número de workers en el archivo de configuración:

npx playwright test --workers=4

3. Generación de informes de pruebas

Después de la ejecución se generainforme HTML:

npx playwright show-report

4. Mecanismo de reintento en caso de fallo

En el archivo de configuraciónplaywright.config.jsse establece:

retries: 2

Cuando una prueba falla, se reintenta automáticamente, adecuado para manejar errores esporádicos.

  1. Playwright Test es unframework de pruebas integrado, sin dependencias adicionales.
  2. El archivo de configuración puede establecertiempos de espera, reintentos, informes, proyectos de navegadoretc.
  3. Los casos de prueba admitenagrupación, hooks, data-driven。
  4. Proporcionaejecución paralela, informes HTML, reintentos de fallosy otras capacidades avanzadas.

Ejemplo de suite de pruebas completa

1. Estructura del proyecto

playwright-demo/
├─ playwright.config.ts           # 全局配置(多项目、多浏览器、报告、重试…)
├─ package.json
├─ tests/
│  ├─ auth.setup.ts               # 一次性登录,生成 storageState
│  ├─ smoke/
│  │  └─ home.spec.ts             # 冒烟用例:标题/URL/截图对比
│  └─ e2e/
│     └─ cart.spec.ts             # 端到端:添加购物车、断言、附件、步骤
├─ fixtures/
│  ├─ pages.ts                    # 页面对象(PO)
│  └─ test.extend.ts              # 自定义 fixtures
└─ snapshots/                     # 视觉基线(自动生成)

2. Archivo de configuración (playwright.config.ts)

Ejemplo

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

export default defineConfig({
  testDir: './tests',
  timeout: 30_000,
  retries: 2,
  workers: 4,
  reporter: [['html', { outputFolder: 'report' }], ['list']],
  forbidOnly: !!process.env.CI,

  // Uso predeterminado unificado (se puede sobrescribir a nivel de proyecto o de prueba)
  use: {
    baseURL: 'https://demo.playwright.dev',
    headless: true,
    screenshot: 'only-on-failure',
    video: 'retain-on-failure',
    trace: 'retain-on-failure',
    viewport: { width: 1366, height: 900 },
    locale: 'zh-CN',
  },

  // Múltiples proyectos: diferentes navegadores/dispositivos/estados de sesión
  projects: [
    { name: 'Chromium', use: { ...devices['Desktop Chrome'] } },
    { name: 'Firefox',  use: { ...devices['Desktop Firefox'] } },
    {
      name: 'Mobile Chrome',
      use: { ...devices['Pixel 7'], headless: true },
    },
    // Proyecto con estado de sesión (reutiliza storageState)
    {
      name: 'Chromium Logged-in',
      use: { storageState: 'storageState.json' },
      dependencies: ['setup'], // Depende del proyecto previo para generar el estado de sesión
    },
    // Proyecto previo "setup": se ejecuta una sola vez para generar storageState
    {
      name: 'setup',
      testMatch: /auth\.setup\.ts/,
    },
  ],
});

Puntos clave:projects permite que el mismo conjunto de casos se ejecute en diferentes navegadores/configuraciones; use puede sobrescribirse a nivel global, de proyecto o de prueba; los informes y reintentos se gestionan de forma centralizada en la configuración.

3. Fixtures y objetos de página

fixtures/test.extend.ts (fixture personalizado + encapsulación de pasos comunes)

Ejemplo

// fixtures/test.extend.ts
import { test as base } from '@playwright/test';
import { HomePage, CartPage } from './pages';

type MyFixtures = {
  home: HomePage;
  cart: CartPage;
};

export const test = base.extend<MyFixtures>({
  home: async ({ page }, use) => {
    const home = new HomePage(page);
    await use(home);
  },
  cart: async ({ page }, use) => {
    const cart = new CartPage(page);
    await use(cart);
  },
});

export { expect } from '@playwright/test';

Usando test.extend() se añaden fixtures personalizados, lo que permite inyectar directamente las instancias home y cart en cualquier caso de prueba.

fixtures/pages.ts (objetos de página)

Ejemplo

// fixtures/pages.ts
import { Page, expect } from '@playwright/test';

export class HomePage {
  constructor(private page: Page) {}
  async goto() { await this.page.goto('/'); }
  get tryTodoLink() { return this.page.getByRole('link', { name: /ToDo MVC/i }); }
}

export class CartPage {
  constructor(private page: Page) {}
  async goto() { await this.page.goto('/e2e'); } // Suponiendo que existe una página de ejemplo e2e
  get addFirstItem() { return this.page.getByRole('button', { name: /Add .* #1/i }); }
  get cartCount() { return this.page.locator('[data-test=cart-count]'); }
  async addOne() { await this.addFirstItem.click(); }
  async expectCount(n: number) { await expect(this.cartCount).toHaveText(String(n)); }
}

4. Inicio de sesión previo (generación única de storageState)

tests/auth.setup.ts (se ejecuta solo en el proyecto "setup")

Ejemplo

// tests/auth.setup.ts
import { test, expect } from '@playwright/test';

test('create storageState', async ({ page }) => {
  await page.goto('https://demo.playwright.dev/todomvc');
  // ... reemplaza aquí por tu flujo de inicio de sesión ...
  // Suponiendo que el inicio de sesión fue exitoso
  await expect(page).toHaveURL(/todomvc/);
  await page.context().storageState({ path: 'storageState.json' });
});

5. Smoke tests (título/URL/comparación visual)

tests/smoke/home.spec.ts

Ejemplo

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

test.describe('Smoke - Home', () => {
  test('title & url & visual snapshot', async ({ page }) => {
    await page.goto('https://playwright.dev');
    await expect(page).toHaveTitle(/Playwright/);
    await expect(page).toHaveURL(/playwright\.dev/);

    // Regresión visual (generación/comparación automática de línea base)
    await expect(page).toHaveScreenshot(); // La primera ejecución generará la línea base
  });
});

Para la comparación visual se recomienda usar toHaveScreenshot (en lugar del enfoque manual con page.screenshot() + toMatchSnapshot).

6. Pruebas de extremo a extremo (pasos, adjuntos, aserciones)

tests/e2e/cart.spec.ts

Ejemplo

import { test, expect } from '../../fixtures/test.extend';

test.describe.configure({ mode: 'parallel' });

test.describe('E2E - Cart', () => {
  test.beforeEach(async ({ home }) => {
    await test.step('Ir a la página de inicio', async () => {
      await home.goto();
    });
  });

  test('Añadir producto al carrito (con adjuntos y aserciones)', async ({ page, cart }) => {
    await test.step('Ir a la página del carrito y añadir el producto', async () => {
      await cart.goto();
      await cart.addOne();
      await cart.expectCount(1);
    });

    await test.step('Adjuntar información de depuración al informe', async () => {
      await test.info().attach('state.json', {
        contentType: 'application/json',
        body: Buffer.from(JSON.stringify({ ts: Date.now(), note: 'after add' })),
      });
    });

    // Captura de pantalla a nivel de elemento
    await test.step('Captura de pantalla del elemento', async () => {
      const badge = page.locator('[data-test=cart-count]');
      await expect(badge).toBeVisible();
      await expect(badge).toHaveScreenshot(); // Snapshot del elemento
    });
  });
});

Usa test.step para registrar pasos de forma jerárquica, usa test.info().attach() para adjuntar datos de depuración/capturas al informe, lo que facilita la depuración; en modo paralelo se puede usar describe.configure({ mode: 'parallel' }).

7. Ejecución e informes

Comandos comunes:

npx playwright test                # 运行全部
npx playwright test tests/e2e      # 运行目录
npx playwright test -g "Cart"      # 按标题过滤
npx playwright test --project="Chromium"   # 指定项目
npx playwright show-report         # 打开HTML报告
npx playwright test --update-snapshots     # 更新视觉基线
npx playwright test --debug        # 调试模式(Inspector)

Para el filtrado por CLI, selección de proyectos, visualización de informes y actualización de snapshots, consulte la documentación oficial de CLI/informes/snapshots.


Referencia rápida de API relacionadas comunes (Playwright Test)

1. Pruebas y agrupación

API Descripción
test(name, fn) Definir pruebas
test.describe(title, fn) Agrupación
test.describe.configure({ mode }) parallel / serial
test.beforeAll/afterAll Preparación y limpieza a nivel de grupo
test.beforeEach/afterEach Preparación y limpieza a nivel de caso
test.skip/only/fixme/slow/fail Marcar/controlar casos

2. Fixtures y configuración

API Descripción
test.extend<Fixtures>(defs) Extender fixtures personalizados
test.use(options) Sobrescritura a nivel de pruebauseOpciones (comostorageState、viewport、localeetc.)
defineConfig({...}) Punto de entrada de configuración (testDir、retries、workers、reporter…)
projects ejecución con múltiples proyectos/navegadores/configuraciones diferentes
use: { baseURL, trace, video, screenshot, viewport, locale, timezoneId, storageState } )

Entorno de ejecución y estrategias de capturaPlaywright)

3. Aserciones (expect)

API Descripción
expect(value).toBe / toEqual / toContain ... Aserciones generales
expect(locator).toHaveText/Value/Attribute Aserciones específicas de Web (con espera inteligente)
expect(locator).toBeVisible/Hidden/Enabled/Disabled/Checked Aserción de estado
expect(page).toHaveTitle/URL Aserción de página
`expect(page/locator).toHaveScreenshot([name options])` Comparación de instantáneas visuales (recomendado)

Las prácticas recomendadas para aserciones e instantáneas visuales se detallan en la documentación de Assertions y Snapshots. (Playwright)

4. Pasos y adjuntos

API Función
test.step(name, fn) Dividir la prueba en pasos (visualización en el informe)
`test.info().attach(name, { path body, contentType })` Adjuntar archivos/datos a la prueba o al paso (se muestran en el informe)

Los adjuntos también pueden aplicarse a nivel de paso (consulte TestStep / TestStepInfo). (Playwright)

5. Informes y CLI

Comando/Configuración Función
reporter: [['html', { outputFolder }], ['list']] Configuración del informe
npx playwright test --project="Chromium" Seleccionar proyecto para ejecutar
-g "keyword" / --grep / --grep-invert Filtrar casos de uso
--update-snapshots Actualizar la línea base visual
npx playwright show-report Abrir informe

Consulte la documentación oficial para ver las opciones completas de CLI y Reporter. (Playwright)

Otras extensiones