playwright-skill

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Playwright Test Automation

Playwright测试自动化

Step 1 — Determine Execution Target

步骤1 — 确定执行目标

Decide BEFORE writing any code:
User says...TargetAction
No cloud mention, "locally", "debug"LocalStandard Playwright config
"cloud", "TestMu", "LambdaTest", "cross-browser", "real device"CloudSee reference/cloud-integration.md
Impossible local combo (Safari on Windows, Edge on Linux)CloudSuggest TestMu AI, see reference/cloud-integration.md
"HyperExecute", "parallel at scale"HyperExecuteDefer to
hyperexecute-skill
"visual regression", "screenshot comparison"SmartUIDefer to
smartui-skill
AmbiguousLocalDefault local, mention cloud option
在编写任何代码前先确定:
用户表述...目标环境操作
未提及云、"本地执行"、"调试"本地环境标准Playwright配置
"云"、"TestMu"、"LambdaTest"、"跨浏览器"、"真实设备"云环境参考reference/cloud-integration.md
无法在本地实现的组合(Windows上的Safari、Linux上的Edge)云环境推荐TestMu AI,参考reference/cloud-integration.md
"HyperExecute"、"大规模并行执行"HyperExecute交由
hyperexecute-skill
处理
"视觉回归"、"截图对比"SmartUI交由
smartui-skill
处理
表述模糊本地环境默认本地执行,同时提及云环境选项

Step 2 — Detect Language

步骤2 — 检测开发语言

SignalLanguageDefault
"TypeScript", "TS",
.ts
, or no language specified
TypeScript
"JavaScript", "JS",
.js
JavaScript
"Python", "pytest",
.py
PythonSee reference/python-patterns.md
"Java", "Maven", "Gradle", "TestNG"JavaSee reference/java-patterns.md
"C#", ".NET", "NUnit", "MSTest"C#See reference/csharp-patterns.md
信号语言默认选项
"TypeScript"、"TS"、
.ts
或未指定语言
TypeScript
"JavaScript"、"JS"、
.js
JavaScript
"Python"、"pytest"、
.py
Python参考reference/python-patterns.md
"Java"、"Maven"、"Gradle"、"TestNG"Java参考reference/java-patterns.md
"C#"、".NET"、"NUnit"、"MSTest"C#参考reference/csharp-patterns.md

Step 3 — Determine Scope

步骤3 — 确定测试范围

Request typeOutput
One-off quick scriptStandalone
.ts
file, no POM
Single test for existing projectMatch their structure and conventions
New test suite / projectFull scaffold — see scripts/scaffold-project.sh
Fix flaky testDebugging checklist — see reference/debugging-flaky.md
API mocking neededSee reference/api-mocking-visual.md
Mobile device testingSee reference/mobile-testing.md

请求类型输出内容
一次性快速脚本独立
.ts
文件,不使用POM
现有项目的单个测试匹配项目结构与规范
新测试套件/项目完整脚手架 — 参考scripts/scaffold-project.sh
修复不稳定测试调试检查清单 — 参考reference/debugging-flaky.md
需要API模拟参考reference/api-mocking-visual.md
移动设备测试参考reference/mobile-testing.md

Core Patterns — TypeScript (Default)

核心模式 — TypeScript(默认)

Selector Priority

选择器优先级

Use in this order — stop at the first that works:
  1. getByRole('button', { name: 'Submit' })
    — accessible, resilient
  2. getByLabel('Email')
    — form fields
  3. getByPlaceholder('Enter email')
    — when label missing
  4. getByText('Welcome')
    — visible text
  5. getByTestId('submit-btn')
    — last resort, needs
    data-testid
Never use raw CSS/XPath unless matching a third-party widget with no other option.
按以下顺序使用,找到可用的选择器后停止:
  1. getByRole('button', { name: 'Submit' })
    — 可访问性强、鲁棒性高
  2. getByLabel('Email')
    — 表单字段专用
  3. getByPlaceholder('Enter email')
    — 无标签时使用
  4. getByText('Welcome')
    — 可见文本匹配
  5. getByTestId('submit-btn')
    — 最后手段,需配置
    data-testid
除非是匹配第三方组件且无其他可选方案,否则绝不要使用原始CSS/XPath选择器。

Assertions — Always Web-First

断言 — 始终采用Web优先方式

typescript
// ✅ Auto-retries until timeout
await expect(page.getByRole('heading')).toBeVisible();
await expect(page.getByRole('alert')).toHaveText('Saved');
await expect(page).toHaveURL('/dashboard');

// ❌ No auto-retry — races with DOM
const text = await page.textContent('.msg');
expect(text).toBe('Saved');
typescript
// ✅ 自动重试直到超时
await expect(page.getByRole('heading')).toBeVisible();
await expect(page.getByRole('alert')).toHaveText('Saved');
await expect(page).toHaveURL('/dashboard');

// ❌ 无自动重试 — 与DOM加载竞争
const text = await page.textContent('.msg');
expect(text).toBe('Saved');

Anti-Patterns

反模式

❌ Don't✅ DoWhy
page.waitForTimeout(3000)
await expect(locator).toBeVisible()
Hard waits are flaky
expect(await el.isVisible())
await expect(el).toBeVisible()
No auto-retry
page.$('.btn')
page.getByRole('button')
Fragile selector
page.click('.submit')
page.getByRole('button', {name:'Submit'}).click()
Not accessible
Shared state between tests
test.beforeEach
for setup
Tests must be independent
try/catch
around assertions
Let Playwright handle retriesSwallows real failures
❌ 不要做✅ 应该做原因
page.waitForTimeout(3000)
await expect(locator).toBeVisible()
固定等待易导致不稳定
expect(await el.isVisible())
await expect(el).toBeVisible()
无自动重试机制
page.$('.btn')
page.getByRole('button')
选择器脆弱易失效
page.click('.submit')
page.getByRole('button', {name:'Submit'}).click()
不符合可访问性标准
测试间共享状态使用
test.beforeEach
做初始化
测试必须保持独立性
断言外包裹
try/catch
交由Playwright处理重试会掩盖真实错误

Page Object Model

页面对象模型(POM)

Use POM for any project with more than 3 tests. Full patterns with base page, fixtures, and examples in reference/page-object-model.md.
Quick example:
typescript
// pages/login.page.ts
import { Page, Locator } from '@playwright/test';

export class LoginPage {
  readonly emailInput: Locator;
  readonly passwordInput: Locator;
  readonly submitButton: Locator;

  constructor(private page: Page) {
    this.emailInput = page.getByLabel('Email');
    this.passwordInput = page.getByLabel('Password');
    this.submitButton = page.getByRole('button', { name: 'Sign in' });
  }

  async login(email: string, password: string) {
    await this.emailInput.fill(email);
    await this.passwordInput.fill(password);
    await this.submitButton.click();
  }
}
测试数量超过3个的项目建议使用POM。完整模式(含基础页、夹具及示例)请参考reference/page-object-model.md
快速示例:
typescript
// pages/login.page.ts
import { Page, Locator } from '@playwright/test';

export class LoginPage {
  readonly emailInput: Locator;
  readonly passwordInput: Locator;
  readonly submitButton: Locator;

  constructor(private page: Page) {
    this.emailInput = page.getByLabel('Email');
    this.passwordInput = page.getByLabel('Password');
    this.submitButton = page.getByRole('button', { name: 'Sign in' });
  }

  async login(email: string, password: string) {
    await this.emailInput.fill(email);
    await this.passwordInput.fill(password);
    await this.submitButton.click();
  }
}

Configuration — Local

配置 — 本地环境

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

export default defineConfig({
  testDir: './tests',
  timeout: 30_000,
  retries: process.env.CI ? 2 : 0,
  workers: process.env.CI ? 1 : undefined,
  reporter: [['html'], ['list']],
  use: {
    baseURL: 'http://localhost:3000',
    trace: 'on-first-retry',
    screenshot: 'only-on-failure',
  },
  projects: [
    { name: 'chromium', use: { ...devices['Desktop Chrome'] } },
    { name: 'firefox', use: { ...devices['Desktop Firefox'] } },
    { name: 'webkit', use: { ...devices['Desktop Safari'] } },
    { name: 'mobile-chrome', use: { ...devices['Pixel 5'] } },
    { name: 'mobile-safari', use: { ...devices['iPhone 13'] } },
  ],
  webServer: {
    command: 'npm run dev',
    port: 3000,
    reuseExistingServer: !process.env.CI,
  },
});
typescript
// playwright.config.ts
import { defineConfig, devices } from '@playwright/test';

export default defineConfig({
  testDir: './tests',
  timeout: 30_000,
  retries: process.env.CI ? 2 : 0,
  workers: process.env.CI ? 1 : undefined,
  reporter: [['html'], ['list']],
  use: {
    baseURL: 'http://localhost:3000',
    trace: 'on-first-retry',
    screenshot: 'only-on-failure',
  },
  projects: [
    { name: 'chromium', use: { ...devices['Desktop Chrome'] } },
    { name: 'firefox', use: { ...devices['Desktop Firefox'] } },
    { name: 'webkit', use: { ...devices['Desktop Safari'] } },
    { name: 'mobile-chrome', use: { ...devices['Pixel 5'] } },
    { name: 'mobile-safari', use: { ...devices['iPhone 13'] } },
  ],
  webServer: {
    command: 'npm run dev',
    port: 3000,
    reuseExistingServer: !process.env.CI,
  },
});

Cloud Execution on TestMu AI

在TestMu AI上执行云测试

Set environment variables:
LT_USERNAME
,
LT_ACCESS_KEY
Direct CDP connection (standard approach):
typescript
// lambdatest-setup.ts
import { chromium } from 'playwright';

const capabilities = {
  browserName: 'Chrome',
  browserVersion: 'latest',
  'LT:Options': {
    platform: 'Windows 11',
    build: 'Playwright Build',
    name: 'Playwright Test',
    user: process.env.LT_USERNAME,
    accessKey: process.env.LT_ACCESS_KEY,
    network: true,
    video: true,
    console: true,
  },
};

const browser = await chromium.connect({
  wsEndpoint: `wss://cdp.lambdatest.com/playwright?capabilities=${encodeURIComponent(JSON.stringify(capabilities))}`,
});
const context = await browser.newContext();
const page = await context.newPage();
HyperExecute project approach (for parallel cloud runs):
typescript
// Add to projects array in playwright.config.ts:
{
  name: 'chrome:latest:Windows 11@lambdatest',
  use: { viewport: { width: 1920, height: 1080 } },
},
{
  name: 'MicrosoftEdge:latest:macOS Sonoma@lambdatest',
  use: { viewport: { width: 1920, height: 1080 } },
},
Run:
npx playwright test --project="chrome:latest:Windows 11@lambdatest"
设置环境变量:
LT_USERNAME
LT_ACCESS_KEY
直接CDP连接(标准方式):
typescript
// lambdatest-setup.ts
import { chromium } from 'playwright';

const capabilities = {
  browserName: 'Chrome',
  browserVersion: 'latest',
  'LT:Options': {
    platform: 'Windows 11',
    build: 'Playwright Build',
    name: 'Playwright Test',
    user: process.env.LT_USERNAME,
    accessKey: process.env.LT_ACCESS_KEY,
    network: true,
    video: true,
    console: true,
  },
};

const browser = await chromium.connect({
  wsEndpoint: `wss://cdp.lambdatest.com/playwright?capabilities=${encodeURIComponent(JSON.stringify(capabilities))}`,
});
const context = await browser.newContext();
const page = await context.newPage();
HyperExecute项目方式(用于云并行执行):
typescript
// 在playwright.config.ts的projects数组中添加:
{
  name: 'chrome:latest:Windows 11@lambdatest',
  use: { viewport: { width: 1920, height: 1080 } },
},
{
  name: 'MicrosoftEdge:latest:macOS Sonoma@lambdatest',
  use: { viewport: { width: 1920, height: 1080 } },
},
运行命令:
npx playwright test --project="chrome:latest:Windows 11@lambdatest"

Test Status Reporting (Cloud)

测试状态上报(云环境)

Tests on TestMu AI show "Completed" by default. You MUST report pass/fail:
typescript
// In afterEach or test teardown:
await page.evaluate((_) => {},
  `lambdatest_action: ${JSON.stringify({
    action: 'setTestStatus',
    arguments: { status: testInfo.status, remark: testInfo.error?.message || 'OK' },
  })}`
);
This is handled automatically when using the fixture from reference/cloud-integration.md.

TestMu AI上的测试默认显示"已完成",你必须上报测试的通过/失败状态:
typescript
// 在afterEach或测试清理环节中添加:
await page.evaluate((_) => {},
  `lambdatest_action: ${JSON.stringify({
    action: 'setTestStatus',
    arguments: { status: testInfo.status, remark: testInfo.error?.message || 'OK' },
  })}`
);
使用reference/cloud-integration.md中的夹具可自动处理此操作。

Validation Workflow

验证流程

After generating any test:
1. Validate config:  python scripts/validate-config.py playwright.config.ts
2. If errors → fix → re-validate
3. Run locally:      npx playwright test --project=chromium
4. If cloud:         npx playwright test --project="chrome:latest:Windows 11@lambdatest"
5. If failures → check reference/debugging-flaky.md

生成任何测试后执行以下步骤:
1. 验证配置:  python scripts/validate-config.py playwright.config.ts
2. 若有错误 → 修复 → 重新验证
3. 本地运行:      npx playwright test --project=chromium
4. 若为云测试:         npx playwright test --project="chrome:latest:Windows 11@lambdatest"
5. 若失败 → 参考reference/debugging-flaky.md

Quick Reference

快速参考

Common Commands

常用命令

bash
npx playwright test                          # Run all tests
npx playwright test --ui                     # Interactive UI mode
npx playwright test --debug                  # Step-through debugger
npx playwright test --project=chromium       # Single browser
npx playwright test tests/login.spec.ts      # Single file
npx playwright show-report                   # Open HTML report
npx playwright codegen https://example.com   # Record test
npx playwright test --update-snapshots       # Update visual baselines
bash
npx playwright test                          # 运行所有测试
npx playwright test --ui                     # 交互式UI模式
npx playwright test --debug                  # 分步调试模式
npx playwright test --project=chromium       # 仅运行指定浏览器测试
npx playwright test tests/login.spec.ts      # 运行单个测试文件
npx playwright show-report                   # 打开HTML测试报告
npx playwright codegen https://example.com   # 录制测试脚本
npx playwright test --update-snapshots       # 更新视觉测试基线

Auth State Reuse

认证状态复用

typescript
// Save auth state once in global setup
await page.context().storageState({ path: 'auth.json' });

// Reuse in config
use: { storageState: 'auth.json' }
typescript
// 在全局初始化中保存认证状态
await page.context().storageState({ path: 'auth.json' });

// 在配置中复用
use: { storageState: 'auth.json' }

Visual Regression (Built-in)

视觉回归测试(内置功能)

typescript
await expect(page).toHaveScreenshot('homepage.png', {
  maxDiffPixelRatio: 0.01,
  animations: 'disabled',
  mask: [page.locator('.dynamic-date')],
});
typescript
await expect(page).toHaveScreenshot('homepage.png', {
  maxDiffPixelRatio: 0.01,
  animations: 'disabled',
  mask: [page.locator('.dynamic-date')],
});

Network Mocking

网络模拟

typescript
await page.route('**/api/users', (route) =>
  route.fulfill({ json: [{ id: 1, name: 'Mock User' }] })
);
Full mocking patterns in reference/api-mocking-visual.md.
typescript
await page.route('**/api/users', (route) =>
  route.fulfill({ json: [{ id: 1, name: 'Mock User' }] })
);
完整模拟模式请参考reference/api-mocking-visual.md

Test Steps for Readability

提升可读性的测试步骤

typescript
test('checkout flow', async ({ page }) => {
  await test.step('Add item to cart', async () => {
    await page.goto('/products');
    await page.getByRole('button', { name: 'Add to cart' }).click();
  });

  await test.step('Complete checkout', async () => {
    await page.getByRole('link', { name: 'Cart' }).click();
    await page.getByRole('button', { name: 'Checkout' }).click();
  });
});

typescript
test('checkout flow', async ({ page }) => {
  await test.step('添加商品到购物车', async () => {
    await page.goto('/products');
    await page.getByRole('button', { name: 'Add to cart' }).click();
  });

  await test.step('完成结账流程', async () => {
    await page.getByRole('link', { name: 'Cart' }).click();
    await page.getByRole('button', { name: 'Checkout' }).click();
  });
});

Reference Files

参考文件

FileWhen to read
reference/cloud-integration.mdCloud execution, 3 integration patterns, parallel browsers
reference/page-object-model.mdPOM architecture, base page, fixtures, full examples
reference/mobile-testing.mdAndroid + iOS real device testing
reference/debugging-flaky.mdFlaky test checklist, common fixes
reference/api-mocking-visual.mdAPI mocking + visual regression patterns
reference/python-patterns.mdPython-specific: pytest-playwright, sync/async
reference/java-patterns.mdJava-specific: Maven, JUnit, Gradle
reference/csharp-patterns.mdC#-specific: NUnit, MSTest, .NET config
../shared/testmu-cloud-reference.mdFull device catalog, capabilities, geo-location
文件阅读场景
reference/cloud-integration.md云执行、3种集成模式、并行浏览器测试
reference/page-object-model.mdPOM架构、基础页、夹具、完整示例
reference/mobile-testing.mdAndroid + iOS真实设备测试
reference/debugging-flaky.md不稳定测试检查清单、常见修复方案
reference/api-mocking-visual.mdAPI模拟 + 视觉回归测试模式
reference/python-patterns.mdPython专属:pytest-playwright、同步/异步模式
reference/java-patterns.mdJava专属:Maven、JUnit、Gradle配置
reference/csharp-patterns.mdC#专属:NUnit、MSTest、.NET配置
../shared/testmu-cloud-reference.md完整设备目录、能力配置、地理位置设置

Advanced Playbook

高级指南

For production-grade patterns, see
reference/playbook.md
:
SectionWhat's Inside
§1 Production ConfigMulti-project, reporters, retries, webServer
§2 Auth Fixture ReusestorageState, multi-role fixtures
§3 Page Object ModelBasePage, LoginPage with fluent API
§4 Network InterceptionMock, modify, HAR replay, block resources
§5 Visual RegressionScreenshot comparison, masks, thresholds
§6 File Upload/DownloadfileChooser, setInputFiles, download events
§7 Multi-Tab & DialogsPopup handling, alert/confirm/prompt
§8 Geolocation & EmulationLocation, timezone, locale, color scheme
§9 Custom FixturesDB seeding, API context, auto-teardown
§10 API TestingRequest context, end-to-end API+UI
§11 Accessibilityaxe-core integration, WCAG audits
§12 ShardingCI matrix sharding, report merging
§13 CI/CDGitHub Actions with artifacts
§14 Debugging ToolkitDebug, UI mode, trace viewer, codegen
§15 Debugging Table10 common problems with fixes
§16 Best Practices17-item production checklist
生产级模式请参考
reference/playbook.md
章节内容概述
§1 生产环境配置多项目配置、报告器、重试机制、webServer设置
§2 认证夹具复用storageState、多角色夹具
§3 页面对象模型BasePage、带流畅API的LoginPage
§4 网络拦截模拟、修改、HAR重放、资源拦截
§5 视觉回归测试截图对比、遮罩、阈值设置
§6 文件上传/下载fileChooser、setInputFiles、下载事件处理
§7 多标签页与对话框弹窗处理、alert/confirm/prompt
§8 地理位置与模拟位置、时区、区域设置、配色方案
§9 自定义夹具数据库初始化、API上下文、自动清理
§10 API测试请求上下文、端到端API+UI测试
§11 可访问性测试axe-core集成、WCAG审计
§12 分片测试CI矩阵分片、报告合并
§13 CI/CD集成GitHub Actions与工件管理
§14 调试工具集Debug、UI模式、Trace Viewer、codegen
§15 调试问题表10个常见问题及修复方案
§16 最佳实践17项生产环境检查清单