作为前端你还不会 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 }) => {
      // 测试逻辑
    });

参考资料

相关推荐
yuanyxh7 小时前
Mac 软件推荐
前端·javascript·程序员
万少7 小时前
AtomCode开发微信小程序《谁去呀》 全流程
前端·javascript·后端
某人辛木7 小时前
Web自动化测试
前端·python·pycharm·pytest
Kagol8 小时前
Superpowers GSD gstack AgentSkills深度测评
前端·人工智能
excel9 小时前
JavaScript 字符串与模板字面量:从表象到本质理解
前端
京东云开发者9 小时前
当AI成为导演-如何用AI创作动漫短剧
前端
李白的天不白9 小时前
使用 SmartAdmin 进行前后端开发
java·前端
乘风gg10 小时前
🤡PUA AI Coding 工具 的 10 条终极语录
前端·ai编程·claude
学Linux的语莫10 小时前
Vue 3 入门教程
前端·javascript·vue.js
怕浪猫10 小时前
第一章、Chrome DevTools Protocol (CDP) 详解
前端·javascript·chrome