playwright

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Playwright - 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
$SKILL_DIR
with the actual discovered path.
Common 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:
  1. 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
  2. Write scripts to /tmp - NEVER write test files to skill directory; always use
    /tmp/playwright-test-*.js
  3. Use visible browser by default - Always use
    headless: false
    unless user specifically requests headless mode
  4. Parameterize URLs - Always make URLs configurable via constant at top of script
  5. Execute via run.js - Always run:
    cd $SKILL_DIR && node run.js /tmp/playwright-test-*.js
执行浏览器自动化任务时:
  1. 自动检测开发服务器 - 针对本地主机测试,务必先运行服务器检测:
    bash
    cd $SKILL_DIR && node -e "require('./lib/helpers').detectDevServers().then(servers => console.log(JSON.stringify(servers)))"
    • 如果发现1个服务器:自动使用该服务器,并告知用户
    • 如果发现多个服务器:询问用户要测试哪一个
    • 如果未发现服务器:询问用户提供URL,或提供启动开发服务器的帮助
  2. 将脚本写入/tmp目录 - 切勿将测试文件写入技能目录;始终使用
    /tmp/playwright-test-*.js
  3. 默认使用可见浏览器 - 除非用户明确请求无头模式,否则始终使用
    headless: false
  4. 参数化URL - 始终将URL配置为脚本顶部的常量
  5. 通过run.js执行 - 始终运行:
    cd $SKILL_DIR && node run.js /tmp/playwright-test-*.js

Quick Start

快速开始

First-Time Setup

首次设置

bash
undefined
bash
undefined

Navigate 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
undefined
bash
undefined

Using 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
undefined
npm init playwright@latest
undefined

Configuration

配置

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

工作原理

  1. You describe what you want to test/automate
  2. I auto-detect running dev servers (or ask for URL)
  3. I write custom Playwright code in
    /tmp/playwright-test-*.js
  4. I execute it via:
    cd $SKILL_DIR && node run.js /tmp/playwright-test-*.js
  5. Results displayed in real-time, browser window visible
  1. 您描述想要测试/自动化的内容
  2. 我自动检测运行中的开发服务器(或询问用户提供URL)
  3. 我在
    /tmp/playwright-test-*.js
    中编写自定义Playwright代码
  4. 我通过以下命令执行:
    cd $SKILL_DIR && node run.js /tmp/playwright-test-*.js
  5. 实时显示结果,浏览器窗口可见

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.js
javascript
// /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.js

Test 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
undefined
bash
undefined

Run 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
undefined
bunx playwright show-report
undefined

Writing 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.js
:
javascript
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.js
中的可选实用工具函数:
javascript
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
undefined

Single header (common case)

单个请求头(常见场景)

PW_HEADER_NAME=X-Automated-By PW_HEADER_VALUE=playwright-skill
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

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

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

使用`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
    detectDevServers()
    before writing test code
  • Use /tmp for test files - Write to
    /tmp/playwright-test-*.js
    , never to skill directory
  • Parameterize URLs - Put detected/provided URL in
    TARGET_URL
    constant
  • DEFAULT: Visible browser - Always use
    headless: false
    unless explicitly requested
  • 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
    slowMo: 100
    to make actions visible
  • Wait strategies: Use
    waitForURL
    ,
    waitForSelector
    ,
    waitForLoadState
    instead of fixed timeouts
  • Error handling: Always use try-catch for robust automation
  • Console output: Use
    console.log()
    to track progress
  • 放慢速度:使用
    slowMo: 100
    让操作可见
  • 等待策略:使用
    waitForURL
    waitForSelector
    waitForLoadState
    替代固定超时
  • 错误处理:始终使用try-catch实现健壮的自动化
  • 控制台输出:使用
    console.log()
    跟踪进度

Troubleshooting

故障排除

Playwright not installed:
bash
cd $SKILL_DIR && bun run setup
Module not found: Ensure running from skill directory via
run.js
wrapper
Browser doesn't open: Check
headless: false
and ensure display available
Element 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

另请参阅

  • vitest-testing
    - Unit and integration testing
  • api-testing
    - HTTP API testing
  • test-quality-analysis
    - Test quality patterns
  • vitest-testing
    - 单元与集成测试
  • api-testing
    - HTTP API测试
  • test-quality-analysis
    - 测试质量模式

When to Load References

何时加载参考文档

Load
references/API_REFERENCE.md
when you need:
  • 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进行可访问性测试
  • 数据驱动与参数化测试
  • 页面对象模型高级模式
  • 并行执行策略