作为前端你还不会 Playwright 进行单元测试吗?


Playwright 测试配置与使用指南

Playwright 是一个现代化的 Web 应用端到端测试框架,支持 Chromium、WebKit 和 Firefox,可以在 Windows、Linux 和 macOS 上运行。

安装

初始化项目

kotlin 复制代码
npm init playwright@latest

安装过程中会询问:

  • TypeScript 或 JavaScript(默认:TypeScript)
  • 测试文件夹名称(默认:tests,如果 tests 已存在则用 e2e)
  • 是否添加 GitHub Actions 工作流(推荐)
  • 是否安装 Playwright 浏览器(默认:是)

系统要求

  • Node.js:最新 20.x、22.x 或 24.x
  • macOS 14 (Ventura) 或更高版本
  • Debian 12/13,Ubuntu 22.04/24.04

项目结构

安装后生成以下结构:

csharp 复制代码
playwright.config.ts    # 测试配置
package.json
package-lock.json
tests/
  example.spec.ts      # 示例测试

编写测试

基础测试示例

javascript 复制代码
import { test, expect } from '@playwright/test';

test('基础测试', async ({ page }) => {
  await page.goto('https://example.com');
  await expect(page).toHaveTitle(/Example Domain/);
});

使用 Locators

rust 复制代码
test('表单提交测试', async ({ page }) => {
  await page.goto('https://example.com/form');
  
  // 填写表单
  await page.fill('input[name="email"]', 'test@example.com');
  await page.fill('input[name="password"]', 'password123');
  
  // 点击提交按钮
  await page.click('button[type="submit"]');
  
  // 验证成功跳转
  await expect(page).toHaveURL(/.*dashboard/);
});

断言

Playwright 提供了丰富的断言方法:

scss 复制代码
// 页面状态断言
await expect(page).toHaveTitle(/Page Title/);
await expect(page).toHaveURL('https://example.com');

// 元素可见性断言
await expect(page.locator('.header')).toBeVisible();
await expect(page.locator('.loading')).toBeHidden();

// 文本内容断言
await expect(page.locator('h1')).toHaveText('Welcome');
await expect(page.locator('.count')).toContainText('5');

// 属性断言
await expect(page.locator('input')).toHaveAttribute('type', 'email');

运行测试

运行所有测试

bash 复制代码
npx playwright test

运行单个测试文件

bash 复制代码
npx playwright test tests/example.spec.ts

有头模式运行(显示浏览器窗口)

bash 复制代码
npx playwright test --headed

运行特定浏览器

ini 复制代码
npx playwright test --project=chromium
npx playwright test --project=webkit

UI 模式

UI 模式提供监视模式、实时步骤视图、时间旅行调试等:

bash 复制代码
npx playwright test --ui

HTML 测试报告

测试运行后,HTML Reporter 提供可过滤的仪表板,按浏览器、通过、失败、跳过、不稳定等分类:

sql 复制代码
npx playwright show-report

配置文件

playwright.config.ts 基础配置

php 复制代码
import { defineConfig, devices } from '@playwright/test';

export default defineConfig({
  // 测试文件夹
  testDir: './tests',
  
  // 完全并行运行测试
  fullyParallel: true,
  
  // CI 中失败时重试
  forbidOnly: !!process.env.CI,
  
  // CI 中重试次数
  retries: process.env.CI ? 2 : 0,
  
  // 并行工作进程数
  workers: process.env.CI ? 1 : undefined,
  
  // 报告器
  reporter: 'html',
  
  use: {
    // 基础 URL
    baseURL: 'http://localhost:3000',
    
    // 追踪重试失败的测试
    trace: 'on-first-retry',
  },

  // 配置不同浏览器
  projects: [
    {
      name: 'chromium',
      use: { ...devices['Desktop Chrome'] },
    },
    {
      name: 'firefox',
      use: { ...devices['Desktop Firefox'] },
    },
    {
      name: 'webkit',
      use: { ...devices['Desktop Safari'] },
    },
  ],
});

高级功能

测试夹具(Fixtures)

csharp 复制代码
import { test as base } from '@playwright/test';

// 自定义 fixture
type MyFixtures = {
  authenticatedPage: Page;
};

const test = base.extend<MyFixtures>({
  authenticatedPage: async ({ page }, use) => {
    // 登录
    await page.goto('/login');
    await page.fill('input[name="email"]', 'test@example.com');
    await page.fill('input[name="password"]', 'password');
    await page.click('button[type="submit"]');
    
    // 使用已认证的页面
    await use(page);
  },
});

test('使用自定义 fixture', async ({ authenticatedPage }) => {
  await authenticatedPage.goto('/dashboard');
  await expect(authenticatedPage).toHaveURL(/.*dashboard/);
});

代码生成(Codegen)

Playwright Codegen 可以通过录制用户操作生成测试代码:

arduino 复制代码
npx playwright codegen https://example.com

追踪查看器

查看测试失败的详细追踪:

python 复制代码
npx playwright show-trace trace.zip

更新 Playwright

sql 复制代码
npm install -D @playwright/test@latest
npx playwright install --with-deps

检查版本:

css 复制代码
npx playwright --version

最佳实践

  1. 使用 Locators 而不是 Selectors

    javascript 复制代码
    // ✅ 推荐
    await page.locator('button').click();
    
    // ❌ 不推荐
    await page.$('button').click();
  2. 使用 Playwright 的等待机制

    csharp 复制代码
    // 自动等待元素可交互
    await page.click('button');
    
    // 显式等待
    await page.waitForSelector('.loaded');
  3. 使用页面对象模式(Page Object Model)

    typescript 复制代码
    class LoginPage {
      constructor(private page: Page) {}
      
      async login(email: string, password: string) {
        await this.page.fill('input[name="email"]', email);
        await this.page.fill('input[name="password"]', password);
        await this.page.click('button[type="submit"]');
      }
    }
  4. 隔离测试数据

    dart 复制代码
    test.use({ storageState: 'auth.json' });
    
    test('需要登录的测试', async ({ page }) => {
      // 测试逻辑
    });

参考资料

相关推荐
Autumn_ing9 小时前
Design.md生成UI怎么验收?举例运营后台的颜色、状态和数据核对
前端·ui·ai·设计系统·paico·ai生成ui·design.md
keyipatience10 小时前
JavaScript学习(1)书写位置,变量、数据类型、运算符
开发语言·前端·javascript·css·学习
朱涛的自习室10 小时前
我给 Gemini 4 和 DeepSeek 搞了套「末位淘汰」,AI 干活会更猛吗?(Day 3)
android·前端·后端
冬奇Lab12 小时前
LLM 驱动的自动化测试系列(14):落地与工程化——为什么测试场景的 Token 账单,反而是这个系列里最便宜的
人工智能·测试
java1234_小锋13 小时前
【技术专题】HTML5 网页技术 - HTML5简介 & HTML5 文档结构
前端·html·html5
鶴哥只手遮天13 小时前
Vue 3 核心源码深度剖析系列(v3.5.44)-第 1 章 项目全景:monorepo 架构与工程化体系
前端·vue.js·开源
技术管理手帐13 小时前
车联APP UI自动化框架的工程化实践
测试
流星。。方13 小时前
小团队官网SEO落地:前端语义化与静态生成的工程实践
前端·状态模式
用户5304297657913 小时前
盘点危化品搬运诊断的6类工具与自处理边界判断
前端
curtain13 小时前
从古法编程到 Agent:我入行这两年,AI 改变了什么
前端·openai