web-testing-playwright-e2e
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChinesePlaywright E2E Testing Patterns
Playwright E2E Testing Patterns
Quick Guide: Use Playwright for end-to-end tests that verify complete user workflows through the real browser. Focus on critical user journeys, use accessibility-based locators (), and leverage auto-waiting assertions -- never use manual sleeps. Isolate each test with its own browser context. Mock external APIs via route interception for reliability.getByRole
<critical_requirements>
快速指南:使用Playwright进行端到端测试,通过真实浏览器验证完整的用户工作流。聚焦关键用户旅程,使用基于可访问性的定位器(),并利用自动等待断言——切勿使用手动休眠。为每个测试分配独立的浏览器上下文。通过路由拦截模拟外部API以确保测试可靠性。getByRole
<critical_requirements>
CRITICAL: Before Using This Skill
重要提示:使用此技能前须知
All code must follow project conventions in CLAUDE.md (kebab-case, named exports, import ordering,, named constants)import type
(You MUST use getByRole() as your primary locator strategy - it mirrors how users interact with the page)
(You MUST test complete user workflows end-to-end - login flows, checkout processes, form submissions)
(You MUST use web-first assertions that auto-wait - toBeVisible(), toHaveText(), not manual sleeps)
(You MUST isolate tests - each test runs independently with its own browser context)
(You MUST use named constants for test data - no magic strings or numbers in test files)
</critical_requirements>
Auto-detection: Playwright, E2E testing, end-to-end testing, browser automation, page.goto, test.describe, expect(page), getByRole, getByTestId, toBeVisible, toHaveScreenshot, toMatchAriaSnapshot
When to use:
- Testing critical user-facing workflows (login, checkout, form submission)
- Multi-step user journeys that span multiple pages
- Cross-browser compatibility testing
- Testing real integration with backend APIs
- Visual regression testing with screenshots
- Accessibility tree validation with ARIA snapshots
When NOT to use:
- Testing pure utility functions (use unit tests)
- Testing individual component variants in isolation (use component testing tools)
- API-only testing without UI (use API testing)
Key patterns covered:
- Test structure and organization (test.describe, test, hooks)
- Page Object Model pattern for maintainability
- Locator strategies prioritizing accessibility (getByRole, getByLabel, chaining, operators)
- Web-first assertions with auto-waiting (toBeVisible, toHaveText, soft assertions)
- Network mocking and interception (route.fulfill, route.abort, response modification)
- Visual regression testing (toHaveScreenshot, masking, thresholds)
- Custom and worker-scoped fixtures
- Clock API for time-dependent testing (v1.45+)
- ARIA snapshot testing for accessibility (v1.49+)
- Accessibility assertions (v1.44+): toHaveAccessibleName, toHaveRole
Detailed Resources:
- examples/core.md - User flows, page objects, network mocking, config, auth fixtures
- examples/page-objects.md - Base page inheritance, hierarchy
- examples/api-mocking.md - Response interception and modification
- examples/visual-testing.md - Screenshot comparison, component visual testing
- examples/fixtures.md - Combined fixtures, database seeding, IndexedDB state
- examples/advanced-features.md - Clock API, ARIA snapshots, worker fixtures, polling assertions, accessibility assertions
- reference.md - Decision frameworks, locator/assertion tables, anti-patterns, CLI commands, configuration reference
<philosophy>
所有代码必须遵循CLAUDE.md中的项目约定(短横线命名法、命名导出、导入顺序、、命名常量)import type
(必须将getByRole()作为主要定位器策略——它模拟用户与页面的交互方式)
(必须端到端测试完整的用户工作流——登录流程、结账流程、表单提交)
(必须使用支持自动等待的Web优先断言——toBeVisible()、toHaveText(),而非手动休眠)
(必须隔离测试——每个测试在独立的浏览器上下文中运行)
(必须为测试数据使用命名常量——测试文件中不得存在魔法字符串或数字)
</critical_requirements>
自动检测关键词:Playwright, E2E testing, end-to-end testing, browser automation, page.goto, test.describe, expect(page), getByRole, getByTestId, toBeVisible, toHaveScreenshot, toMatchAriaSnapshot
适用场景:
- 测试关键用户面向的工作流(登录、结账、表单提交)
- 跨多个页面的多步骤用户旅程
- 跨浏览器兼容性测试
- 测试与后端API的真实集成
- 结合截图的视觉回归测试
- 通过ARIA快照验证可访问性树
不适用场景:
- 测试纯工具函数(应使用单元测试)
- 孤立测试单个组件变体(应使用组件测试工具)
- 无UI的纯API测试(应使用API测试)
涵盖的核心模式:
- 测试结构与组织(test.describe、test、钩子函数)
- 提升可维护性的页面对象模型模式
- 优先考虑可访问性的定位器策略(getByRole、getByLabel、链式调用、操作符)
- 支持自动等待的Web优先断言(toBeVisible、toHaveText、软断言)
- 网络模拟与拦截(route.fulfill、route.abort、响应修改)
- 视觉回归测试(toHaveScreenshot、遮罩、阈值)
- 自定义与工作器作用域的测试夹具(fixtures)
- 用于时间相关测试的Clock API(v1.45+)
- 用于可访问性的ARIA快照测试(v1.49+)
- 可访问性断言(v1.44+):toHaveAccessibleName、toHaveRole
详细资源:
- examples/core.md - 用户流程、页面对象、网络模拟、配置、认证夹具
- examples/page-objects.md - 基础页面继承、层级结构
- examples/api-mocking.md - 响应拦截与修改
- examples/visual-testing.md - 截图对比、组件视觉测试
- examples/fixtures.md - 组合夹具、数据库初始化、IndexedDB状态
- examples/advanced-features.md - Clock API、ARIA快照、工作器夹具、轮询断言、可访问性断言
- reference.md - 决策框架、定位器/断言对照表、反模式、CLI命令、配置参考
<philosophy>
Philosophy
理念
Playwright E2E tests verify that your application works correctly from the user's perspective. They interact with the real browser, navigate through actual pages, and validate user-visible behavior.
Core Principles:
- Test user-visible behavior - Focus on what end users see and interact with, not implementation details
- Use accessibility locators - mirrors how screen readers and users interact with pages
getByRole - Isolate tests completely - Each test has its own browser context, cookies, and storage
- Trust auto-waiting - Playwright automatically waits for elements; no manual sleeps needed
- Mock external dependencies - Use route interception for third-party APIs to ensure reliability
When E2E tests provide the most value:
- Critical business workflows (authentication, payments, core features)
- User journeys spanning multiple pages or components
- Testing real backend integration
- Cross-browser compatibility verification
- Catching integration bugs that unit tests miss
When E2E tests may not be the best choice:
- Testing pure utility functions (unit tests are faster and more precise)
- Testing component styling variants (use visual testing tools)
- Testing every edge case (balance with unit and integration tests)
<patterns>
Playwright E2E测试从用户视角验证应用是否正常工作。它们与真实浏览器交互、导航实际页面,并验证用户可见的行为。
核心原则:
- 测试用户可见行为 - 聚焦终端用户看到和交互的内容,而非实现细节
- 使用可访问性定位器 - 模拟屏幕阅读器和用户与页面的交互方式
getByRole - 完全隔离测试 - 每个测试拥有独立的浏览器上下文、Cookie和存储
- 信任自动等待机制 - Playwright会自动等待元素加载,无需手动休眠
- 模拟外部依赖 - 使用路由拦截处理第三方API,确保测试可靠性
E2E测试价值最大化的场景:
- 关键业务工作流(认证、支付、核心功能)
- 跨多个页面或组件的用户旅程
- 测试真实后端集成
- 跨浏览器兼容性验证
- 捕捉单元测试遗漏的集成bug
E2E测试并非最佳选择的场景:
- 测试纯工具函数(单元测试更快更精准)
- 测试组件样式变体(应使用视觉测试工具)
- 测试每个边缘情况(需与单元测试和集成测试平衡)
<patterns>
Core Patterns
核心模式
Pattern 1: Test Structure and Organization
模式1:测试结构与组织
Group related tests with , use for common navigation, and name constants for all test data.
test.describebeforeEachtypescript
const LOGIN_URL = "/login";
const VALID_EMAIL = "user@example.com";
test.describe("Login Flow", () => {
test.beforeEach(async ({ page }) => {
await page.goto(LOGIN_URL);
});
test("successful login redirects to dashboard", async ({ page }) => {
await page.getByLabel(/email/i).fill(VALID_EMAIL);
// ... fill password, click sign in
await expect(page).toHaveURL("/dashboard");
});
});Why good: Groups related tests logically, maintains isolation, named constants prevent magic strings
beforeEachSee examples/core.md Pattern 1 for complete user flow with error scenarios.
使用分组相关测试,用处理通用导航,为所有测试数据定义命名常量。
test.describebeforeEachtypescript
const LOGIN_URL = "/login";
const VALID_EMAIL = "user@example.com";
test.describe("Login Flow", () => {
test.beforeEach(async ({ page }) => {
await page.goto(LOGIN_URL);
});
test("successful login redirects to dashboard", async ({ page }) => {
await page.getByLabel(/email/i).fill(VALID_EMAIL);
// ... 填写密码,点击登录
await expect(page).toHaveURL("/dashboard");
});
});优势:按逻辑分组相关测试,维持测试隔离,命名常量避免魔法字符串
beforeEach查看examples/core.md模式1获取包含错误场景的完整用户流程示例。
Pattern 2: Page Object Model
模式2:页面对象模型
Encapsulate page structure and interactions in reusable classes. Define locators in the constructor, expose domain-specific methods.
typescript
export class LoginPage {
readonly emailInput: Locator;
readonly signInButton: Locator;
constructor(page: Page) {
this.emailInput = page.getByLabel(/email/i);
this.signInButton = page.getByRole("button", { name: /sign in/i });
}
async login(email: string, password: string) {
await this.emailInput.fill(email);
// ...
}
}Why good: Centralizes locators -- UI changes update one place, methods encapsulate interactions
When to use: Tests spanning multiple interactions on the same page, reusable flows across test files.
When not to use: Simple one-off tests where inline locators are clearer.
See examples/core.md Pattern 2 for full page objects with fixtures, examples/page-objects.md for base page inheritance.
将页面结构和交互封装到可复用类中。在构造函数中定义定位器,暴露领域特定方法。
typescript
export class LoginPage {
readonly emailInput: Locator;
readonly signInButton: Locator;
constructor(page: Page) {
this.emailInput = page.getByLabel(/email/i);
this.signInButton = page.getByRole("button", { name: /sign in/i });
}
async login(email: string, password: string) {
await this.emailInput.fill(email);
// ...
}
}优势:集中管理定位器——UI变更只需更新一处,方法封装交互逻辑
适用场景:同一页面涉及多步交互的测试、跨测试文件的可复用流程。
不适用场景:简单一次性测试,内联定位器更清晰的情况。
查看examples/core.md模式2获取带夹具的完整页面对象,examples/page-objects.md获取基础页面继承示例。
Pattern 3: Locator Strategies
模式3:定位器策略
Prioritize accessibility-based locators that mirror how users interact with the application.
typescript
// BEST: Accessibility-based
await page.getByRole("button", { name: /submit/i });
await page.getByLabel(/email address/i);
await page.getByText(/welcome back/i);
// ACCEPTABLE: Test IDs for complex cases
await page.getByTestId("user-avatar"); // When no semantic role exists
// AVOID: Implementation-dependent
await page.locator("#submit-btn"); // Fragile
await page.locator(".btn-primary"); // CSS class can changeChaining and filtering narrow down to specific elements without fragile selectors:
typescript
await page
.getByRole("listitem")
.filter({ hasText: "Product A" })
.getByRole("button", { name: /add to cart/i })
.click();
// Exclude elements (v1.33+)
await page
.getByRole("listitem")
.filter({ hasNot: page.getByText("Out of stock") })
.first()
.click();
// Combine conditions (v1.33+)
const btn = page.getByRole("button").and(page.getByTitle("Subscribe"));Why good: validates accessibility as a side effect, survives UI refactoring, chaining handles dynamic lists
getByRoleSee reference.md for locator priority table and common ARIA role mappings.
优先使用模拟用户与应用交互方式的基于可访问性的定位器。
typescript
// 最佳选择:基于可访问性
await page.getByRole("button", { name: /submit/i });
await page.getByLabel(/email address/i);
await page.getByText(/welcome back/i);
// 可接受:复杂场景下使用测试ID
await page.getByTestId("user-avatar"); // 当不存在语义化角色时
// 应避免:依赖实现细节
await page.locator("#submit-btn"); // 易失效
await page.locator(".btn-primary"); // CSS类可能变更链式调用与过滤无需脆弱选择器即可缩小到特定元素:
typescript
await page
.getByRole("listitem")
.filter({ hasText: "Product A" })
.getByRole("button", { name: /add to cart/i })
.click();
// 排除元素(v1.33+)
await page
.getByRole("listitem")
.filter({ hasNot: page.getByText("Out of stock") })
.first()
.click();
// 组合条件(v1.33+)
const btn = page.getByRole("button").and(page.getByTitle("Subscribe"));优势:附带验证可访问性的效果,能在UI重构后依然有效,链式调用可处理动态列表
getByRole查看reference.md获取定位器优先级表和常见ARIA角色映射。
Pattern 4: Web-First Assertions
模式4:Web优先断言
Use assertions that automatically wait and retry until the condition is met.
typescript
// Auto-waits for element visibility
await expect(page.getByText("Welcome")).toBeVisible();
// Auto-waits for URL
await expect(page).toHaveURL(/\/dashboard/);
// Negated assertions also auto-wait
await expect(page.getByRole("progressbar")).not.toBeVisible();Why good: Eliminates flaky tests from race conditions, no manual sleeps needed
typescript
// BAD: Manual waiting
await page.waitForTimeout(2000); // Arbitrary sleep!
const text = await page.textContent(".result");
expect(text).toBe("Success"); // Non-waiting assertionWhy bad: Fixed timeouts are either too short (flaky) or too long (slow), doesn't adapt to actual page load time
Soft assertions collect all failures in one run:
typescript
await expect.soft(page.getByTestId("avatar")).toBeVisible();
await expect.soft(page.getByText("Premium")).toBeVisible();
// Test continues, all failures reported at endSee reference.md for complete assertion table, polling assertions, and accessibility assertions (v1.44+).
使用自动等待并重试直到条件满足的断言。
typescript
// 自动等待元素可见
await expect(page.getByText("Welcome")).toBeVisible();
// 自动等待URL变更
await expect(page).toHaveURL(/\/dashboard/);
// 否定断言同样支持自动等待
await expect(page.getByRole("progressbar")).not.toBeVisible();优势:消除竞争条件导致的不稳定测试,无需手动休眠
typescript
// 错误做法:手动等待
await page.waitForTimeout(2000); // 任意休眠!
const text = await page.textContent(".result");
expect(text).toBe("Success"); // 无等待的断言劣势:固定超时要么太短(导致不稳定)要么太长(拖慢测试),无法适应实际页面加载时间
软断言会收集一次运行中的所有失败:
typescript
await expect.soft(page.getByTestId("avatar")).toBeVisible();
await expect.soft(page.getByText("Premium")).toBeVisible();
// 测试继续执行,最终报告所有失败查看reference.md获取完整断言表、轮询断言及可访问性断言(v1.44+)。
Pattern 5: Network Mocking and Interception
模式5:网络模拟与拦截
Mock external APIs for reliable, isolated tests. Use to intercept and fulfill requests.
page.route()typescript
const API_USERS = "**/api/users";
await page.route(API_USERS, (route) =>
route.fulfill({
status: 200,
contentType: "application/json",
body: JSON.stringify({ id: "user-123", name: "John Doe" }),
}),
);
// Error simulation
await page.route(API_USERS, (route) => route.abort("failed")); // Network failureWhy good: Eliminates third-party flakiness, enables testing error states, controls exact data
Modifying real responses (hybrid approach):
typescript
await page.route("**/api/products", async (route) => {
const response = await route.fetch();
const json = await response.json();
json.products = json.products.map((p: { price: number }) => ({
...p,
price: p.price * 0.9,
}));
await route.fulfill({ response, json });
});See examples/core.md Pattern 3 for complete mocking with error states, examples/api-mocking.md for response modification.
模拟外部API以实现可靠、隔离的测试。使用拦截并响应请求。
page.route()typescript
const API_USERS = "**/api/users";
await page.route(API_USERS, (route) =>
route.fulfill({
status: 200,
contentType: "application/json",
body: JSON.stringify({ id: "user-123", name: "John Doe" }),
}),
);
// 模拟错误
await page.route(API_USERS, (route) => route.abort("failed")); // 网络失败优势:消除第三方服务导致的不稳定,支持测试错误状态,可精确控制数据
修改真实响应(混合方式):
typescript
await page.route("**/api/products", async (route) => {
const response = await route.fetch();
const json = await response.json();
json.products = json.products.map((p: { price: number }) => ({
...p,
price: p.price * 0.9,
}));
await route.fulfill({ response, json });
});查看examples/core.md模式3获取包含错误状态的完整模拟示例,examples/api-mocking.md获取响应修改示例。
Pattern 6: Visual Regression Testing
模式6:视觉回归测试
Capture and compare screenshots to detect unintended visual changes.
typescript
await expect(page).toHaveScreenshot("homepage.png");
// Mask dynamic content
await expect(page).toHaveScreenshot("dashboard.png", {
mask: [page.getByTestId("current-time"), page.getByTestId("random-ad")],
});
// Disable animations for deterministic screenshots
await expect(page).toHaveScreenshot("stable.png", { animations: "disabled" });Why good: Catches unintended visual changes, masking prevents false positives from timestamps
See examples/visual-testing.md for component visual testing with state variations.
捕获并对比截图以检测意外的视觉变化。
typescript
await expect(page).toHaveScreenshot("homepage.png");
// 遮罩动态内容
await expect(page).toHaveScreenshot("dashboard.png", {
mask: [page.getByTestId("current-time"), page.getByTestId("random-ad")],
});
// 禁用动画以生成确定性截图
await expect(page).toHaveScreenshot("stable.png", { animations: "disabled" });优势:捕获意外视觉变化,遮罩避免时间戳等内容导致的误报
查看examples/visual-testing.md获取带状态变体的组件视觉测试示例。
Pattern 7: Custom Fixtures
模式7:自定义夹具
Extend the base test with reusable fixtures for page objects, authentication, and shared setup.
typescript
export const test = base.extend<{
loginPage: LoginPage;
authenticatedPage: void;
}>({
loginPage: async ({ page }, use) => {
await use(new LoginPage(page));
},
authenticatedPage: [
async ({ context }, use) => {
await context.addCookies([
{ name: "session", value: "token", domain: "localhost", path: "/" },
]);
await use();
await context.clearCookies();
},
{ auto: true },
],
});Why good: Encapsulates setup + teardown, auto fixtures eliminate repetitive auth, composable
See examples/core.md Pattern 5 for auth fixtures, examples/fixtures.md for combined fixtures and database seeding, examples/advanced-features.md for worker-scoped fixtures.
扩展基础测试,为页面对象、认证和共享初始化添加可复用夹具。
typescript
export const test = base.extend<{
loginPage: LoginPage;
authenticatedPage: void;
}>({
loginPage: async ({ page }, use) => {
await use(new LoginPage(page));
},
authenticatedPage: [
async ({ context }, use) => {
await context.addCookies([
{ name: "session", value: "token", domain: "localhost", path: "/" },
]);
await use();
await context.clearCookies();
},
{ auto: true },
],
});优势:封装初始化+清理逻辑,自动夹具消除重复的认证代码,可组合使用
查看examples/core.md模式5获取认证夹具示例,examples/fixtures.md获取组合夹具和数据库初始化示例,examples/advanced-features.md获取工作器作用域夹具示例。
Pattern 8: Clock API (v1.45+)
模式8:Clock API(v1.45+)
Control time for testing countdowns, session timeouts, and scheduled events.
typescript
await page.clock.install({ time: new Date("2024-02-02T08:00:00") });
await page.goto("/dashboard");
await page.clock.fastForward("25:00"); // Jump 25 minutes
await expect(page.getByText(/session expires/i)).toBeVisible();CRITICAL: MUST be called before any other clock methods.
clock.install()See examples/advanced-features.md for countdown testing and session timeout patterns.
控制时间以测试倒计时、会话超时和定时事件。
typescript
await page.clock.install({ time: new Date("2024-02-02T08:00:00") });
await page.goto("/dashboard");
await page.clock.fastForward("25:00"); // 快进25分钟
await expect(page.getByText(/session expires/i)).toBeVisible();重要提示:必须在任何其他时钟方法之前调用。
clock.install()查看examples/advanced-features.md获取倒计时测试和会话超时模式示例。
Pattern 9: ARIA Snapshot Testing (v1.49+)
模式9:ARIA快照测试(v1.49+)
Validate accessibility tree structure programmatically.
typescript
await expect(page.getByRole("navigation")).toMatchAriaSnapshot(`
- navigation:
- link "Home"
- link "Products"
- link "About"
`);Why good: Catches ARIA issues before production, documents expected accessibility behavior
See examples/advanced-features.md for complex component ARIA snapshots.
</patterns>
<red_flags>
以编程方式验证可访问性树结构。
typescript
await expect(page.getByRole("navigation")).toMatchAriaSnapshot(`
- navigation:
- link "Home"
- link "Products"
- link "About"
`);优势:在生产前发现ARIA问题,记录预期的可访问性行为
查看examples/advanced-features.md获取复杂组件的ARIA快照示例。
</patterns>
<red_flags>
RED FLAGS
风险警示
High Priority Issues:
- Using with fixed delays -- causes flaky or slow tests, use auto-waiting assertions instead
page.waitForTimeout() - Using CSS selectors like or
.btn-primary-- fragile and break on refactoring, use#submit-btngetByRole - Not testing error states -- only happy paths leaves error handling untested
- Tests sharing state or data -- causes flaky failures in parallel execution, isolate each test completely
Medium Priority Issues:
- Using as primary locator -- misses accessibility validation, prioritize
getByTestIdgetByRole - No network mocking for external APIs -- third-party flakiness affects your tests
- Running E2E tests only on one browser -- cross-browser issues go undetected
- Screenshots without masking dynamic content -- timestamps and ads cause false positives
Common Mistakes:
- Hardcoded test data scattered throughout files -- use named constants
- Testing implementation details (e.g., Redux state via ) instead of user behavior
window.__REDUX_STATE__ - Not using for common setup -- leads to duplicated code
beforeEach - Mixing E2E tests with unit tests in the same directory
Gotchas & Edge Cases:
- auto-waits for the element;
toBeVisible()checks DOM presence without visibility -- prefer visibility checks for most casestoBeAttached() - Screenshots vary by OS and browser -- run visual tests in consistent CI environment
- runs once per worker, not once globally -- use
beforeAllin config for true one-time setupglobalSetup - Network routes are global to context -- routes set in override previous; always set up fresh per test
beforeEach - Parallel tests cannot share state -- use fixtures for per-test setup, not shared variables
- throws on non-editable elements (v1.50+) -- verify element type first
toBeEditable() - Glob URL patterns in no longer support
page.route()and?(v1.52+) -- use regex instead[] - cannot override Cookie header (v1.52+) -- use
route.continue()insteadcontext.addCookies() - and
_reactselectors removed (v1.58) -- use data-testid or role-based locators_vue
</red_flags>
<critical_reminders>
高优先级问题:
- 使用设置固定延迟——导致测试不稳定或缓慢,应使用自动等待断言
page.waitForTimeout() - 使用或
.btn-primary等CSS选择器——易失效,UI重构时会中断,应使用#submit-btngetByRole - 未测试错误状态——仅测试正常路径会导致错误处理未被验证
- 测试共享状态或数据——并行执行时会导致不稳定失败,需完全隔离每个测试
中优先级问题:
- 将作为主要定位器——遗漏可访问性验证,应优先使用
getByTestIdgetByRole - 未对外部API进行网络模拟——第三方服务的不稳定会影响测试
- 仅在单个浏览器上运行E2E测试——跨浏览器问题无法被发现
- 截图未遮罩动态内容——时间戳和广告会导致误报
常见错误:
- 测试数据硬编码在多个文件中——应使用命名常量
- 测试实现细节(如通过测试Redux状态)而非用户行为
window.__REDUX_STATE__ - 未使用处理通用初始化——导致代码重复
beforeEach - E2E测试与单元测试混放在同一目录
注意事项与边缘情况:
- 会自动等待元素;
toBeVisible()仅检查DOM存在性不验证可见性——大多数场景优先选择可见性检查toBeAttached() - 截图会因操作系统和浏览器而异——在一致的CI环境中运行视觉测试
- 在每个工作器中运行一次,而非全局一次——如需真正的一次性初始化,使用配置中的
beforeAllglobalSetup - 网络路由对上下文全局生效——中设置的路由会覆盖之前的;需为每个测试重新设置
beforeEach - 并行测试无法共享状态——使用夹具处理每个测试的初始化,而非共享变量
- 在非可编辑元素上会抛出错误(v1.50+)——先验证元素类型
toBeEditable() - 中的Glob URL模式不再支持
page.route()和?(v1.52+)——改用正则表达式[] - 无法覆盖Cookie头(v1.52+)——改用
route.continue()context.addCookies() - 和
_react选择器已移除(v1.58)——使用data-testid或基于角色的定位器_vue
</red_flags>
<critical_reminders>
CRITICAL REMINDERS
重要提醒
All code must follow project conventions in CLAUDE.md
(You MUST use getByRole() as your primary locator strategy - it mirrors how users interact with the page)
(You MUST test complete user workflows end-to-end - login flows, checkout processes, form submissions)
(You MUST use web-first assertions that auto-wait - toBeVisible(), toHaveText(), not manual sleeps)
(You MUST isolate tests - each test runs independently with its own browser context)
(You MUST use named constants for test data - no magic strings or numbers in test files)
Failure to follow these rules will result in flaky tests, false positives, and maintenance nightmares.
</critical_reminders>
所有代码必须遵循CLAUDE.md中的项目约定
(必须将getByRole()作为主要定位器策略——它模拟用户与页面的交互方式)
(必须端到端测试完整的用户工作流——登录流程、结账流程、表单提交)
(必须使用支持自动等待的Web优先断言——toBeVisible()、toHaveText(),而非手动休眠)
(必须隔离测试——每个测试在独立的浏览器上下文中运行)
(必须为测试数据使用命名常量——测试文件中不得存在魔法字符串或数字)
不遵守这些规则会导致测试不稳定、误报和维护噩梦。
</critical_reminders>