playwright
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChinesePlaywright - Browser Automation & E2E Testing
Playwright - 浏览器自动化与端到端(E2E)测试
Expert knowledge for browser automation and end-to-end testing with Playwright - a modern cross-browser testing framework.
IMPORTANT - Path Resolution:
This skill can be installed in different locations. Before executing commands, determine the skill directory based on where you loaded this SKILL.md file, and use that path in all commands. Replace with the actual discovered path.
$SKILL_DIRCommon installation paths:
- Plugin system:
~/.claude/plugins/*/playwright/skills/playwright - Manual global:
~/.claude/skills/playwright - Project-specific:
<project>/.claude/skills/playwright
本内容提供关于Playwright(一款现代跨浏览器测试框架)的浏览器自动化与端到端测试专业知识。
重要提示 - 路径解析:
本技能可安装在不同位置。执行命令前,请根据加载本SKILL.md文件的位置确定技能目录,并在所有命令中使用该路径。将替换为实际找到的路径。
$SKILL_DIR常见安装路径:
- 插件系统:
~/.claude/plugins/*/playwright/skills/playwright - 手动全局安装:
~/.claude/skills/playwright - 项目专属:
<project>/.claude/skills/playwright
CRITICAL WORKFLOW - Follow These Steps
关键工作流程 - 请遵循以下步骤
When automating browser tasks:
-
Auto-detect dev servers - For localhost testing, ALWAYS run server detection FIRST:bash
cd $SKILL_DIR && node -e "require('./lib/helpers').detectDevServers().then(servers => console.log(JSON.stringify(servers)))"- If 1 server found: Use it automatically, inform user
- If multiple servers found: Ask user which one to test
- If no servers found: Ask for URL or offer to help start dev server
-
Write scripts to /tmp - NEVER write test files to skill directory; always use
/tmp/playwright-test-*.js -
Use visible browser by default - Always useunless user specifically requests headless mode
headless: false -
Parameterize URLs - Always make URLs configurable via constant at top of script
-
Execute via run.js - Always run:
cd $SKILL_DIR && node run.js /tmp/playwright-test-*.js
执行浏览器自动化任务时:
-
自动检测开发服务器 - 针对本地主机测试,务必先运行服务器检测:bash
cd $SKILL_DIR && node -e "require('./lib/helpers').detectDevServers().then(servers => console.log(JSON.stringify(servers)))"- 如果发现1个服务器:自动使用该服务器,并告知用户
- 如果发现多个服务器:询问用户要测试哪一个
- 如果未发现服务器:询问用户提供URL,或提供启动开发服务器的帮助
-
将脚本写入/tmp目录 - 切勿将测试文件写入技能目录;始终使用
/tmp/playwright-test-*.js -
默认使用可见浏览器 - 除非用户明确请求无头模式,否则始终使用
headless: false -
参数化URL - 始终将URL配置为脚本顶部的常量
-
通过run.js执行 - 始终运行:
cd $SKILL_DIR && node run.js /tmp/playwright-test-*.js
Quick Start
快速开始
First-Time Setup
首次设置
bash
undefinedbash
undefinedNavigate to skill directory
导航到技能目录
cd $SKILL_DIR
cd $SKILL_DIR
Install using bun (preferred)
使用bun安装(推荐)
bun run setup
bun run setup
Or using npm
或使用npm安装
npm run setup:npm
This installs Playwright and Chromium browser. Only needed once.npm run setup:npm
此操作将安装Playwright和Chromium浏览器,仅需执行一次。Installation (For E2E Testing Projects)
安装(针对E2E测试项目)
bash
undefinedbash
undefinedUsing Bun (preferred)
使用Bun(推荐)
bun add -d @playwright/test
bunx playwright install
bun add -d @playwright/test
bunx playwright install
Using npm
使用npm
npm init playwright@latest
undefinednpm init playwright@latest
undefinedConfiguration
配置
typescript
// playwright.config.ts
import { defineConfig, devices } from '@playwright/test'
export default defineConfig({
testDir: './tests',
fullyParallel: true,
reporter: 'html',
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'] } },
],
webServer: {
command: 'bun run dev',
url: 'http://localhost:3000',
},
})typescript
// playwright.config.ts
import { defineConfig, devices } from '@playwright/test'
export default defineConfig({
testDir: './tests',
fullyParallel: true,
reporter: 'html',
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'] } },
],
webServer: {
command: 'bun run dev',
url: 'http://localhost:3000',
},
})Browser Automation Patterns
浏览器自动化模式
How It Works
工作原理
- You describe what you want to test/automate
- I auto-detect running dev servers (or ask for URL)
- I write custom Playwright code in
/tmp/playwright-test-*.js - I execute it via:
cd $SKILL_DIR && node run.js /tmp/playwright-test-*.js - Results displayed in real-time, browser window visible
- 您描述想要测试/自动化的内容
- 我自动检测运行中的开发服务器(或询问用户提供URL)
- 我在中编写自定义Playwright代码
/tmp/playwright-test-*.js - 我通过以下命令执行:
cd $SKILL_DIR && node run.js /tmp/playwright-test-*.js - 实时显示结果,浏览器窗口可见
Test a Page (Multiple Viewports)
测试页面(多视口)
javascript
// /tmp/playwright-test-responsive.js
const { chromium } = require('playwright');
const TARGET_URL = 'http://localhost:3001'; // Auto-detected
(async () => {
const browser = await chromium.launch({ headless: false, slowMo: 100 });
const page = await browser.newPage();
// Desktop test
await page.setViewportSize({ width: 1920, height: 1080 });
await page.goto(TARGET_URL);
console.log('Desktop - Title:', await page.title());
await page.screenshot({ path: '/tmp/desktop.png', fullPage: true });
// Mobile test
await page.setViewportSize({ width: 375, height: 667 });
await page.screenshot({ path: '/tmp/mobile.png', fullPage: true });
await browser.close();
})();Execute:
cd $SKILL_DIR && node run.js /tmp/playwright-test-responsive.jsjavascript
// /tmp/playwright-test-responsive.js
const { chromium } = require('playwright');
const TARGET_URL = 'http://localhost:3001'; // 自动检测
(async () => {
const browser = await chromium.launch({ headless: false, slowMo: 100 });
const page = await browser.newPage();
// 桌面端测试
await page.setViewportSize({ width: 1920, height: 1080 });
await page.goto(TARGET_URL);
console.log('桌面端 - 标题:', await page.title());
await page.screenshot({ path: '/tmp/desktop.png', fullPage: true });
// 移动端测试
await page.setViewportSize({ width: 375, height: 667 });
await page.screenshot({ path: '/tmp/mobile.png', fullPage: true });
await browser.close();
})();执行:
cd $SKILL_DIR && node run.js /tmp/playwright-test-responsive.jsTest Login Flow
测试登录流程
javascript
// /tmp/playwright-test-login.js
const { chromium } = require('playwright');
const TARGET_URL = 'http://localhost:3001'; // Auto-detected
(async () => {
const browser = await chromium.launch({ headless: false });
const page = await browser.newPage();
await page.goto(`${TARGET_URL}/login`);
await page.fill('input[name="email"]', 'test@example.com');
await page.fill('input[name="password"]', 'password123');
await page.click('button[type="submit"]');
await page.waitForURL('**/dashboard');
console.log('✅ Login successful, redirected to dashboard');
await browser.close();
})();javascript
// /tmp/playwright-test-login.js
const { chromium } = require('playwright');
const TARGET_URL = 'http://localhost:3001'; // 自动检测
(async () => {
const browser = await chromium.launch({ headless: false });
const page = await browser.newPage();
await page.goto(`${TARGET_URL}/login`);
await page.fill('input[name="email"]', 'test@example.com');
await page.fill('input[name="password"]', 'password123');
await page.click('button[type="submit"]');
await page.waitForURL('**/dashboard');
console.log('✅ 登录成功,已重定向到仪表盘');
await browser.close();
})();Check for Broken Links
检查失效链接
javascript
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch({ headless: false });
const page = await browser.newPage();
await page.goto('http://localhost:3000');
const links = await page.locator('a[href^="http"]').all();
const results = { working: 0, broken: [] };
for (const link of links) {
const href = await link.getAttribute('href');
try {
const response = await page.request.head(href);
if (response.ok()) {
results.working++;
} else {
results.broken.push({ url: href, status: response.status() });
}
} catch (e) {
results.broken.push({ url: href, error: e.message });
}
}
console.log(`✅ Working links: ${results.working}`);
console.log(`❌ Broken links:`, results.broken);
await browser.close();
})();javascript
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch({ headless: false });
const page = await browser.newPage();
await page.goto('http://localhost:3000');
const links = await page.locator('a[href^="http"]').all();
const results = { working: 0, broken: [] };
for (const link of links) {
const href = await link.getAttribute('href');
try {
const response = await page.request.head(href);
if (response.ok()) {
results.working++;
} else {
results.broken.push({ url: href, status: response.status() });
}
} catch (e) {
results.broken.push({ url: href, error: e.message });
}
}
console.log(`✅ 可用链接:${results.working}`);
console.log(`❌ 失效链接:`, results.broken);
await browser.close();
})();E2E Testing Patterns
E2E测试模式
Running Tests
运行测试
bash
undefinedbash
undefinedRun all tests
运行所有测试
bunx playwright test
bunx playwright test
Headed mode (see browser)
有头模式(可见浏览器)
bunx playwright test --headed
bunx playwright test --headed
Specific file
运行特定文件
bunx playwright test tests/login.spec.ts
bunx playwright test tests/login.spec.ts
Debug mode
调试模式
bunx playwright test --debug
bunx playwright test --debug
UI mode (interactive)
UI模式(交互式)
bunx playwright test --ui
bunx playwright test --ui
Specific browser
特定浏览器
bunx playwright test --project=chromium
bunx playwright test --project=chromium
Generate report
生成报告
bunx playwright show-report
undefinedbunx playwright show-report
undefinedWriting Tests
编写测试
typescript
import { test, expect } from '@playwright/test'
test.describe('Login flow', () => {
test('successful login', async ({ page }) => {
await page.goto('/')
await page.getByRole('link', { name: 'Login' }).click()
await page.getByLabel('Email').fill('user@example.com')
await page.getByLabel('Password').fill('password123')
await page.getByRole('button', { name: 'Sign in' }).click()
await expect(page.getByRole('heading', { name: 'Dashboard' })).toBeVisible()
})
test('shows error for invalid credentials', async ({ page }) => {
await page.goto('/login')
await page.getByLabel('Email').fill('wrong@example.com')
await page.getByLabel('Password').fill('wrongpassword')
await page.getByRole('button', { name: 'Sign in' }).click()
await expect(page.getByText('Invalid credentials')).toBeVisible()
})
})typescript
import { test, expect } from '@playwright/test'
test.describe('登录流程', () => {
test('成功登录', async ({ page }) => {
await page.goto('/')
await page.getByRole('link', { name: 'Login' }).click()
await page.getByLabel('Email').fill('user@example.com')
await page.getByLabel('Password').fill('password123')
await page.getByRole('button', { name: 'Sign in' }).click()
await expect(page.getByRole('heading', { name: 'Dashboard' })).toBeVisible()
})
test('无效凭证时显示错误', async ({ page }) => {
await page.goto('/login')
await page.getByLabel('Email').fill('wrong@example.com')
await page.getByLabel('Password').fill('wrongpassword')
await page.getByRole('button', { name: 'Sign in' }).click()
await expect(page.getByText('Invalid credentials')).toBeVisible()
})
})Selectors (Best Practices)
选择器(最佳实践)
typescript
// ✅ Role-based (recommended)
await page.getByRole('button', { name: 'Submit' })
await page.getByRole('link', { name: 'Home' })
// ✅ Text/Label
await page.getByText('Hello World')
await page.getByLabel('Email')
// ✅ Test ID (fallback)
await page.getByTestId('submit-button')
// ❌ Avoid CSS selectors (brittle)
await page.locator('.btn-primary')typescript
// ✅ 基于角色(推荐)
await page.getByRole('button', { name: 'Submit' })
await page.getByRole('link', { name: 'Home' })
// ✅ 文本/标签
await page.getByText('Hello World')
await page.getByLabel('Email')
// ✅ 测试ID(备选)
await page.getByTestId('submit-button')
// ❌ 避免CSS选择器(易失效)
await page.locator('.btn-primary')Assertions
断言
typescript
// Visibility
await expect(page.getByText('Success')).toBeVisible()
await expect(page.getByRole('button')).toBeEnabled()
// Text
await expect(page.getByRole('heading')).toHaveText('Welcome')
await expect(page.getByRole('alert')).toContainText('error')
// Attributes
await expect(page.getByRole('link')).toHaveAttribute('href', '/home')
// URL/Title
await expect(page).toHaveURL('/dashboard')
await expect(page).toHaveTitle('Dashboard')
// Count
await expect(page.getByRole('listitem')).toHaveCount(5)typescript
// 可见性
await expect(page.getByText('Success')).toBeVisible()
await expect(page.getByRole('button')).toBeEnabled()
// 文本
await expect(page.getByRole('heading')).toHaveText('Welcome')
await expect(page.getByRole('alert')).toContainText('error')
// 属性
await expect(page.getByRole('link')).toHaveAttribute('href', '/home')
// URL/标题
await expect(page).toHaveURL('/dashboard')
await expect(page).toHaveTitle('Dashboard')
// 数量
await expect(page.getByRole('listitem')).toHaveCount(5)Actions
操作
typescript
// Clicking
await page.getByRole('button').click()
await page.getByText('File').dblclick()
// Typing
await page.getByLabel('Email').fill('user@example.com')
await page.getByLabel('Search').press('Enter')
// Selecting
await page.getByLabel('Country').selectOption('us')
// File Upload
await page.getByLabel('Upload').setInputFiles('path/to/file.pdf')typescript
// 点击
await page.getByRole('button').click()
await page.getByText('File').dblclick()
// 输入
await page.getByLabel('Email').fill('user@example.com')
await page.getByLabel('Search').press('Enter')
// 选择
await page.getByLabel('Country').selectOption('us')
// 文件上传
await page.getByLabel('Upload').setInputFiles('path/to/file.pdf')Network Mocking
网络模拟
typescript
test('mocks API response', async ({ page }) => {
await page.route('**/api/users', async route => {
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify([{ id: 1, name: 'Test User' }]),
})
})
await page.goto('/users')
await expect(page.getByText('Test User')).toBeVisible()
})typescript
test('模拟API响应', async ({ page }) => {
await page.route('**/api/users', async route => {
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify([{ id: 1, name: 'Test User' }]),
})
})
await page.goto('/users')
await expect(page.getByText('Test User')).toBeVisible()
})Visual Testing
视觉测试
typescript
test('captures screenshot', async ({ page }) => {
await page.goto('/')
await page.screenshot({ path: 'screenshot.png', fullPage: true })
await expect(page).toHaveScreenshot('homepage.png')
})typescript
test('捕获截图', async ({ page }) => {
await page.goto('/')
await page.screenshot({ path: 'screenshot.png', fullPage: true })
await expect(page).toHaveScreenshot('homepage.png')
})Authentication State
认证状态
typescript
// Save state after login
setup('authenticate', async ({ page }) => {
await page.goto('/login')
await page.getByLabel('Email').fill('user@example.com')
await page.getByLabel('Password').fill('password123')
await page.getByRole('button', { name: 'Sign in' }).click()
await page.context().storageState({ path: 'auth.json' })
})
// Reuse in config
use: { storageState: 'auth.json' }typescript
// 登录后保存状态
setup('认证', async ({ page }) => {
await page.goto('/login')
await page.getByLabel('Email').fill('user@example.com')
await page.getByLabel('Password').fill('password123')
await page.getByRole('button', { name: 'Sign in' }).click()
await page.context().storageState({ path: 'auth.json' })
})
// 在配置中复用
use: { storageState: 'auth.json' }Page Object Model
页面对象模型
typescript
// pages/LoginPage.ts
import { Page, Locator } from '@playwright/test'
export class LoginPage {
readonly emailInput: Locator
readonly passwordInput: Locator
readonly submitButton: Locator
constructor(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()
}
}
// Usage
const loginPage = new LoginPage(page)
await loginPage.login('user@example.com', 'password123')typescript
// pages/LoginPage.ts
import { Page, Locator } from '@playwright/test'
export class LoginPage {
readonly emailInput: Locator
readonly passwordInput: Locator
readonly submitButton: Locator
constructor(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()
}
}
// 使用示例
const loginPage = new LoginPage(page)
await loginPage.login('user@example.com', 'password123')Available Helpers
可用工具函数
Optional utility functions in :
lib/helpers.jsjavascript
const helpers = require('./lib/helpers');
// Detect running dev servers (CRITICAL - use this first!)
const servers = await helpers.detectDevServers();
console.log('Found servers:', servers);
// Safe click with retry
await helpers.safeClick(page, 'button.submit', { retries: 3 });
// Safe type with clear
await helpers.safeType(page, '#username', 'testuser');
// Take timestamped screenshot
await helpers.takeScreenshot(page, 'test-result');
// Handle cookie banners
await helpers.handleCookieBanner(page);
// Extract table data
const data = await helpers.extractTableData(page, 'table.results');
// Create context with custom headers
const context = await helpers.createContext(browser);lib/helpers.jsjavascript
const helpers = require('./lib/helpers');
// 检测运行中的开发服务器(关键 - 请首先使用!)
const servers = await helpers.detectDevServers();
console.log('发现服务器:', servers);
// 带重试的安全点击
await helpers.safeClick(page, 'button.submit', { retries: 3 });
// 带清空的安全输入
await helpers.safeType(page, '#username', 'testuser');
// 生成带时间戳的截图
await helpers.takeScreenshot(page, 'test-result');
// 处理Cookie横幅
await helpers.handleCookieBanner(page);
// 提取表格数据
const data = await helpers.extractTableData(page, 'table.results');
// 创建带自定义请求头的上下文
const context = await helpers.createContext(browser);Custom HTTP Headers
自定义HTTP请求头
Configure custom headers for all HTTP requests via environment variables:
bash
undefined通过环境变量为所有HTTP请求配置自定义请求头:
bash
undefinedSingle header (common case)
单个请求头(常见场景)
PW_HEADER_NAME=X-Automated-By PW_HEADER_VALUE=playwright-skill
cd $SKILL_DIR && node run.js /tmp/my-script.js
cd $SKILL_DIR && node run.js /tmp/my-script.js
PW_HEADER_NAME=X-Automated-By PW_HEADER_VALUE=playwright-skill
cd $SKILL_DIR && node run.js /tmp/my-script.js
cd $SKILL_DIR && node run.js /tmp/my-script.js
Multiple headers (JSON format)
多个请求头(JSON格式)
PW_EXTRA_HEADERS='{"X-Automated-By":"playwright-skill","X-Debug":"true"}'
cd $SKILL_DIR && node run.js /tmp/my-script.js
cd $SKILL_DIR && node run.js /tmp/my-script.js
Headers are automatically applied when using `helpers.createContext()`.PW_EXTRA_HEADERS='{"X-Automated-By":"playwright-skill","X-Debug":"true"}'
cd $SKILL_DIR && node run.js /tmp/my-script.js
cd $SKILL_DIR && node run.js /tmp/my-script.js
使用`helpers.createContext()`时会自动应用这些请求头。Inline Execution (Simple Tasks)
内联执行(简单任务)
For quick one-off tasks:
bash
cd $SKILL_DIR && node run.js "
const browser = await chromium.launch({ headless: false });
const page = await browser.newPage();
await page.goto('http://localhost:3001');
await page.screenshot({ path: '/tmp/quick-screenshot.png', fullPage: true });
console.log('Screenshot saved');
await browser.close();
"When to use:
- Inline: Quick one-off tasks (screenshot, element check)
- Files: Complex tests, reusable automation
针对快速一次性任务:
bash
cd $SKILL_DIR && node run.js "
const browser = await chromium.launch({ headless: false });
const page = await browser.newPage();
await page.goto('http://localhost:3001');
await page.screenshot({ path: '/tmp/quick-screenshot.png', fullPage: true });
console.log('截图已保存');
await browser.close();
"适用场景:
- 内联执行:快速一次性任务(截图、元素检查)
- 文件执行:复杂测试、可复用自动化脚本
Best Practices
最佳实践
- CRITICAL: Detect servers FIRST - Always run before writing test code
detectDevServers() - Use /tmp for test files - Write to , never to skill directory
/tmp/playwright-test-*.js - Parameterize URLs - Put detected/provided URL in constant
TARGET_URL - DEFAULT: Visible browser - Always use unless explicitly requested
headless: false - Prefer role-based selectors - More stable than CSS selectors
- Trust auto-waiting - No manual sleeps needed
- Each test gets fresh context - Automatic isolation
- Run tests in parallel - Default behavior
- Mock external dependencies - Use
page.route() - Use trace viewer - Time-travel debugging
- 关键提示:先检测服务器 - 编写测试代码前务必运行
detectDevServers() - 使用/tmp存储测试文件 - 写入,切勿写入技能目录
/tmp/playwright-test-*.js - 参数化URL - 将检测到的/用户提供的URL放入常量
TARGET_URL - 默认使用可见浏览器 - 除非明确要求,否则始终使用
headless: false - 优先使用基于角色的选择器 - 比CSS选择器更稳定
- 信任自动等待机制 - 无需手动添加等待
- 每个测试使用全新上下文 - 自动隔离环境
- 并行运行测试 - 默认行为
- 模拟外部依赖 - 使用
page.route() - 使用追踪查看器 - 时间旅行调试
Tips
技巧
- Slow down: Use to make actions visible
slowMo: 100 - Wait strategies: Use ,
waitForURL,waitForSelectorinstead of fixed timeoutswaitForLoadState - Error handling: Always use try-catch for robust automation
- Console output: Use to track progress
console.log()
- 放慢速度:使用让操作可见
slowMo: 100 - 等待策略:使用、
waitForURL、waitForSelector替代固定超时waitForLoadState - 错误处理:始终使用try-catch实现健壮的自动化
- 控制台输出:使用跟踪进度
console.log()
Troubleshooting
故障排除
Playwright not installed:
bash
cd $SKILL_DIR && bun run setupModule not found:
Ensure running from skill directory via wrapper
run.jsBrowser doesn't open:
Check and ensure display available
headless: falseElement not found:
Add wait:
await page.waitForSelector('.element', { timeout: 10000 })Playwright未安装:
bash
cd $SKILL_DIR && bun run setup模块未找到:
确保通过包装器从技能目录运行
run.js浏览器无法打开:
检查配置,并确保显示可用
headless: false未找到元素:
添加等待:
await page.waitForSelector('.element', { timeout: 10000 })See Also
另请参阅
- - Unit and integration testing
vitest-testing - - HTTP API testing
api-testing - - Test quality patterns
test-quality-analysis
- - 单元与集成测试
vitest-testing - - HTTP API测试
api-testing - - 测试质量模式
test-quality-analysis
When to Load References
何时加载参考文档
Load when you need:
references/API_REFERENCE.md- Advanced selector patterns and locator strategies
- Network interception and request/response mocking
- Authentication patterns and session management
- Visual regression testing setup
- Mobile device emulation configurations
- Performance testing and metrics
- Debugging techniques (trace viewer, inspector)
- CI/CD pipeline integration
- Accessibility testing with axe-core
- Data-driven and parameterized testing
- Page Object Model advanced patterns
- Parallel execution strategies
当您需要以下内容时,请加载:
references/API_REFERENCE.md- 高级选择器模式与定位策略
- 网络拦截与请求/响应模拟
- 认证模式与会话管理
- 视觉回归测试设置
- 移动设备仿真配置
- 性能测试与指标
- 调试技巧(追踪查看器、检查器)
- CI/CD流水线集成
- 使用axe-core进行可访问性测试
- 数据驱动与参数化测试
- 页面对象模型高级模式
- 并行执行策略