playwright-e2e-testing

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Playwright E2E Testing (TypeScript)

Playwright 端到端测试(TypeScript)

Comprehensive toolkit for end-to-end testing of web applications using Playwright with TypeScript. Enables robust UI testing, API validation, and responsive design verification following best practices.
Activation: This skill is triggered when working with Playwright tests, browser automation, E2E testing, API testing with Playwright, or test infrastructure setup.
这是一套使用Playwright与TypeScript进行Web应用端到端测试的综合工具集,可遵循最佳实践实现可靠的UI测试、API验证及响应式设计验证。
激活条件: 当处理Playwright测试、浏览器自动化、端到端测试、基于Playwright的API测试或测试基础设施搭建时,将触发本技能。

When to Use This Skill

何时使用本技能

  • Write E2E tests for user flows, forms, navigation, and authentication
  • API testing via
    request
    fixture or network interception during UI tests
  • Responsive testing across mobile, tablet, and desktop viewports
  • Debug flaky tests using traces, screenshots, videos, and Playwright Inspector
  • Setup test infrastructure with Page Object Model and fixtures
  • Mock/intercept APIs for isolated, deterministic testing
  • Visual regression testing with screenshot comparisons
  • 编写端到端测试:针对用户流程、表单、导航及身份验证
  • API测试:通过
    request
    测试夹具或UI测试中的网络拦截实现
  • 响应式测试:覆盖移动端、平板及桌面端视口
  • 调试不稳定测试:使用追踪记录、截图、视频及Playwright Inspector
  • 搭建测试基础设施:基于Page Object Model和测试夹具
  • 模拟/拦截API:实现隔离、可预测的测试
  • 视觉回归测试:通过截图对比实现

Prerequisites

前置要求

RequirementDetails
Node.jsv18+ recommended
Package Managernpm, yarn, or pnpm
Playwright
@playwright/test
package
TypeScript
typescript
+
ts-node
(optional but recommended)
BrowsersInstalled via
npx playwright install
要求详情
Node.js推荐v18及以上版本
包管理器npm、yarn或pnpm
Playwright
@playwright/test
TypeScript
typescript
+
ts-node
(可选但推荐)
浏览器通过
npx playwright install
安装

Quick Setup

快速搭建

bash
undefined
bash
undefined

Initialize new project

Initialize new project

npm init playwright@latest
npm init playwright@latest

Or add to existing project

Or add to existing project

npm install -D @playwright/test npx playwright install
undefined
npm install -D @playwright/test npx playwright install
undefined

First Questions to Ask

需先确认的问题

Before writing tests, clarify:
  1. App URL: Local dev server command + port, or staging URL?
  2. Critical flows: Which user journeys must be covered (happy path + error states)?
  3. Browsers/devices: Chrome, Firefox, Safari? Mobile viewports?
  4. API strategy: Real backend, mocked responses, or hybrid?
  5. Test data: Seed data available? Reset/cleanup strategy?

编写测试前,请明确:
  1. 应用URL:本地开发服务器命令+端口,或预发布环境URL?
  2. 核心流程:必须覆盖哪些用户旅程(主流程+异常场景)?
  3. 浏览器/设备:Chrome、Firefox、Safari?移动端视口?
  4. API策略:使用真实后端、模拟响应还是混合方式?
  5. 测试数据:是否有预置数据?重置/清理策略是什么?

Core Principles

核心原则

1. Test Runner & TypeScript

1. 测试运行器与TypeScript

Always use
@playwright/test
with TypeScript for type safety and better IDE support.
typescript
import { test, expect } from '@playwright/test';

test('user can login', async ({ page }) => {
  await page.goto('/login');
  await page.getByLabel('Email').fill('user@test.com');
  await page.getByLabel('Password').fill('password123');
  await page.getByRole('button', { name: 'Sign in' }).click();
  await expect(page).toHaveURL(/.*dashboard/);
});
始终结合使用
@playwright/test
与TypeScript,以获得类型安全及更好的IDE支持。
typescript
import { test, expect } from '@playwright/test';

test('user can login', async ({ page }) => {
  await page.goto('/login');
  await page.getByLabel('Email').fill('user@test.com');
  await page.getByLabel('Password').fill('password123');
  await page.getByRole('button', { name: 'Sign in' }).click();
  await expect(page).toHaveURL(/.*dashboard/);
});

2. Locator Strategy (Priority Order)

2. 定位器策略(优先级顺序)

PriorityLocatorExample
1Role + accessible name
getByRole('button', { name: 'Submit' })
2Label
getByLabel('Email')
3Placeholder
getByPlaceholder('Enter email')
4Text
getByText('Welcome')
5Test ID
getByTestId('submit-btn')
6CSS (avoid)
locator('.btn-primary')
See Locator Strategies Guide for detailed patterns.
优先级定位器示例
1角色+可访问名称
getByRole('button', { name: 'Submit' })
2标签
getByLabel('Email')
3占位符
getByPlaceholder('Enter email')
4文本
getByText('Welcome')
5测试ID
getByTestId('submit-btn')
6CSS(避免使用)
locator('.btn-primary')
查看定位器策略指南获取详细模式。

3. Auto-Waiting & Web-First Assertions

3. 自动等待与Web优先断言

Playwright auto-waits for elements. Never use
sleep()
or arbitrary timeouts.
typescript
// ✅ Web-first assertions (auto-retry)
await expect(page.getByRole('alert')).toBeVisible();
await expect(page).toHaveURL(/dashboard/);
await expect(page.getByTestId('status')).toHaveText('Success!');

// ❌ Avoid manual waits
await page.waitForTimeout(2000); // Bad practice
Playwright会自动等待元素加载完成。切勿使用
sleep()
或任意超时设置。
typescript
// ✅ Web-first assertions (auto-retry)
await expect(page.getByRole('alert')).toBeVisible();
await expect(page).toHaveURL(/dashboard/);
await expect(page.getByTestId('status')).toHaveText('Success!');

// ❌ Avoid manual waits
await page.waitForTimeout(2000); // Bad practice

4. Test Structure with Steps

4. 带步骤的测试结构

Use
test.step()
for readable reports and failure localization:
typescript
test('checkout flow', async ({ page }) => {
  await test.step('Add item to cart', async () => {
    await page.goto('/products/1');
    await page.getByRole('button', { name: 'Add to Cart' }).click();
  });

  await test.step('Complete checkout', async () => {
    await page.goto('/checkout');
    await page.getByRole('button', { name: 'Pay Now' }).click();
  });

  await test.step('Verify confirmation', async () => {
    await expect(page.getByRole('heading')).toContainText('Order Confirmed');
  });
});

使用
test.step()
提升报告可读性并定位失败点:
typescript
test('checkout flow', async ({ page }) => {
  await test.step('Add item to cart', async () => {
    await page.goto('/products/1');
    await page.getByRole('button', { name: 'Add to Cart' }).click();
  });

  await test.step('Complete checkout', async () => {
    await page.goto('/checkout');
    await page.getByRole('button', { name: 'Pay Now' }).click();
  });

  await test.step('Verify confirmation', async () => {
    await expect(page.getByRole('heading')).toContainText('Order Confirmed');
  });
});

Key Workflows

关键工作流

Forms & Navigation

表单与导航

typescript
// Form submit and wait for navigation (auto-waiting)
await page.getByRole('button', { name: 'Login' }).click();
await expect(page).toHaveURL(/.*dashboard/);

// Form with API response validation
const responsePromise = page.waitForResponse(
  r => r.url().includes('/api/login') && r.status() === 200
);
await page.getByRole('button', { name: 'Login' }).click();
const response = await responsePromise;
typescript
// Form submit and wait for navigation (auto-waiting)
await page.getByRole('button', { name: 'Login' }).click();
await expect(page).toHaveURL(/.*dashboard/);

// Form with API response validation
const responsePromise = page.waitForResponse(
  r => r.url().includes('/api/login') && r.status() === 200
);
await page.getByRole('button', { name: 'Login' }).click();
const response = await responsePromise;

API Testing (Request Fixture)

API测试(Request夹具)

typescript
test('API health check', async ({ request }) => {
  const response = await request.get('/api/health');
  expect(response.ok()).toBeTruthy();
  expect(await response.json()).toMatchObject({ status: 'ok' });
});
typescript
test('API health check', async ({ request }) => {
  const response = await request.get('/api/health');
  expect(response.ok()).toBeTruthy();
  expect(await response.json()).toMatchObject({ status: 'ok' });
});

API Mocking & Interception

API模拟与拦截

typescript
test('handles API error', async ({ page }) => {
  await page.route('**/api/users', route =>
    route.fulfill({ status: 500, body: JSON.stringify({ error: 'Server error' }) })
  );
  await page.goto('/users');
  await expect(page.getByRole('alert')).toContainText('Something went wrong');
});
typescript
test('handles API error', async ({ page }) => {
  await page.route('**/api/users', route =>
    route.fulfill({ status: 500, body: JSON.stringify({ error: 'Server error' }) })
  );
  await page.goto('/users');
  await expect(page.getByRole('alert')).toContainText('Something went wrong');
});

Responsive Testing

响应式测试

typescript
const viewports = [
  { width: 375, height: 667, name: 'mobile' },
  { width: 768, height: 1024, name: 'tablet' },
  { width: 1280, height: 720, name: 'desktop' },
];

for (const vp of viewports) {
  test(`navigation works on ${vp.name}`, async ({ page }) => {
    await page.setViewportSize(vp);
    await page.goto('/');
    // Mobile: hamburger menu
    if (vp.width < 768) {
      await page.getByRole('button', { name: /menu/i }).click();
    }
    await page.getByRole('link', { name: 'About' }).click();
    await expect(page).toHaveURL(/about/);
  });
}

typescript
const viewports = [
  { width: 375, height: 667, name: 'mobile' },
  { width: 768, height: 1024, name: 'tablet' },
  { width: 1280, height: 720, name: 'desktop' },
];

for (const vp of viewports) {
  test(`navigation works on ${vp.name}`, async ({ page }) => {
    await page.setViewportSize(vp);
    await page.goto('/');
    // Mobile: hamburger menu
    if (vp.width < 768) {
      await page.getByRole('button', { name: /menu/i }).click();
    }
    await page.getByRole('link', { name: 'About' }).click();
    await expect(page).toHaveURL(/about/);
  });
}

Configuration

配置

Use
playwright.config.ts
for project-wide settings:
typescript
import { defineConfig, devices } from '@playwright/test';

export default defineConfig({
  testDir: './tests',
  retries: process.env.CI ? 2 : 0,
  reporter: [['html'], ['junit', { outputFile: 'results.xml' }]],
  use: {
    baseURL: 'http://localhost:3000',
    trace: 'on-first-retry',
    screenshot: 'only-on-failure',
    video: 'retain-on-failure',
  },
  projects: [
    { name: 'chromium', use: devices['Desktop Chrome'] },
    { name: 'mobile', use: devices['Pixel 5'] },
  ],
  webServer: {
    command: 'npm run dev',
    url: 'http://localhost:3000',
    reuseExistingServer: !process.env.CI,
  },
});

使用
playwright.config.ts
进行项目级设置:
typescript
import { defineConfig, devices } from '@playwright/test';

export default defineConfig({
  testDir: './tests',
  retries: process.env.CI ? 2 : 0,
  reporter: [['html'], ['junit', { outputFile: 'results.xml' }]],
  use: {
    baseURL: 'http://localhost:3000',
    trace: 'on-first-retry',
    screenshot: 'only-on-failure',
    video: 'retain-on-failure',
  },
  projects: [
    { name: 'chromium', use: devices['Desktop Chrome'] },
    { name: 'mobile', use: devices['Pixel 5'] },
  ],
  webServer: {
    command: 'npm run dev',
    url: 'http://localhost:3000',
    reuseExistingServer: !process.env.CI,
  },
});

Troubleshooting

故障排查

ProblemCauseSolution
Element not foundWrong locator or not renderedUse
PWDEBUG=1
to inspect, verify with
getByRole
Timeout waitingElement hidden or slow loadCheck for overlays, increase timeout, use
waitFor()
Flaky testsRace conditions, animationsAdd
test.step()
, use proper waits, disable animations
Strict mode violationMultiple elements matchUse
.first()
,
.filter()
, or more specific locator
Screenshots differDynamic contentMask dynamic areas, use deterministic data
CI fails, local passesEnvironment differencesCheck
baseURL
, timeouts,
webServer
config
API mock not workingRoute pattern mismatchUse
**/api/...
glob, verify with
page.on('request')

问题原因解决方案
元素未找到定位器错误或元素未渲染使用
PWDEBUG=1
进行检查,优先使用
getByRole
等待超时元素隐藏或加载缓慢检查是否有遮罩层,增加超时时间,使用
waitFor()
测试不稳定竞态条件、动画添加
test.step()
,使用正确的等待方式,禁用动画
严格模式违规多个元素匹配定位器使用
.first()
.filter()
或更具体的定位器
截图不一致动态内容遮盖动态区域,使用可预测的测试数据
CI环境失败,本地正常环境差异检查
baseURL
、超时设置、
webServer
配置
API模拟不生效路由模式不匹配使用
**/api/...
通配符,通过
page.on('request')
验证

CLI Quick Reference

CLI快速参考

CommandDescription
npx playwright test
Run all tests headless
npx playwright test --ui
Open UI mode (interactive)
npx playwright test --headed
Run with visible browser
npx playwright test --debug
Run with Playwright Inspector
npx playwright test -g "login"
Run tests matching pattern
npx playwright test --project=chromium
Run specific project
npx playwright show-report
Open HTML report
npx playwright codegen
Generate tests by recording
PWDEBUG=1 npx playwright test
Debug with Inspector
DEBUG=pw:api npx playwright test
Verbose API logging

命令说明
npx playwright test
以无头模式运行所有测试
npx playwright test --ui
打开UI模式(交互式)
npx playwright test --headed
以可见浏览器模式运行测试
npx playwright test --debug
通过Playwright Inspector运行测试
npx playwright test -g "login"
运行匹配指定模式的测试
npx playwright test --project=chromium
运行指定项目的测试
npx playwright show-report
打开HTML测试报告
npx playwright codegen
通过录制生成测试代码
PWDEBUG=1 npx playwright test
使用Inspector调试测试
DEBUG=pw:api npx playwright test
启用详细API日志

References

参考文档

DocumentContent
SnippetsReady-to-use code patterns
Locator StrategiesComplete locator guide
Page Object ModelPOM implementation patterns
Debugging GuideTroubleshooting & debugging techniques
文档内容
Snippets可直接使用的代码模板
Locator Strategies完整的定位器指南
Page Object ModelPage Object Model实现模式
Debugging Guide故障排查与调试技巧