Playwright基础使用指南

# Playwright基础使用指南

## 引言

Playwright是微软推出的一款功能强大的端到端测试框架,它支持多种浏览器(Chrome、Firefox、Safari)和多种编程语言(JavaScript、TypeScript、Python、Java、C#)。Playwright的设计目标是提供一个统一、可靠的测试解决方案,让开发者能够更轻松地编写和运行自动化测试。本文将介绍Playwright的基础知识,包括安装、配置、基本操作和最佳实践,帮助你快速上手这个强大的测试工具。

## 核心概念

### 什么是Playwright?

Playwright是一个开源的端到端测试框架,由微软开发和维护。它提供了一套API,允许开发者编写自动化测试脚本,模拟用户在浏览器中的操作,如点击、输入、导航等。Playwright的主要特点包括:

– 跨浏览器支持:支持Chrome、Firefox、Safari等主流浏览器
– 跨平台支持:可在Windows、macOS、Linux上运行
– 多语言支持:支持JavaScript、TypeScript、Python、Java、C#
– 自动等待:智能等待元素加载,无需手动添加等待时间
– 网络拦截:可以模拟网络请求和响应
– 截图和视频录制:支持测试过程中的截图和视频录制
– 移动设备模拟:可以模拟不同设备的屏幕尺寸和分辨率

### Playwright的架构

Playwright采用了一种独特的架构,它使用浏览器自动化协议与浏览器进行通信。这种架构的优势在于:

– 稳定性:通过浏览器自动化协议,Playwright能够更稳定地控制浏览器
– 速度:直接与浏览器通信,减少了中间层的开销
– 功能丰富:能够访问浏览器的所有功能,包括新特性

## 环境搭建

### 安装Playwright

安装Playwright非常简单,只需运行以下命令:

“`bash
# 使用npm安装
npm init playwright@latest

# 或者使用yarn
yarn create playwright

# 或者使用pnpm
pnpm create playwright
“`

安装过程中,Playwright会自动下载所需的浏览器二进制文件。

### 配置项目

安装完成后,Playwright会生成以下文件和目录:

– `playwright.config.ts`:测试配置文件
– `tests/`:测试文件目录
– `tests-examples/`:示例测试文件

你可以根据需要修改`playwright.config.ts`文件,配置测试参数:

“`typescript
import { defineConfig, devices } from ‘@playwright/test’;

export default defineConfig({
testDir: ‘./tests’,
/* Run tests in files in parallel */
fullyParallel: true,
/* Fail the build on CI if you accidentally left test.only in the source code. */
forbidOnly: !!process.env.CI,
/* Retry on CI only */
retries: process.env.CI ? 2 : 0,
/* Opt out of parallel tests on CI. */
workers: process.env.CI ? 1 : undefined,
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
reporter: ‘html’,
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
use: {
/* Base URL to use in actions like `await page.goto(‘/’)`. */
baseURL: ‘http://localhost:3000’,

/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: ‘on-first-retry’,
},

/* Configure projects for major browsers */
projects: [
{
name: ‘chromium’,
use: { …devices[‘Desktop Chrome’] },
},

{
name: ‘firefox’,
use: { …devices[‘Desktop Firefox’] },
},

{
name: ‘webkit’,
use: { …devices[‘Desktop Safari’] },
},
],

/* Run your local dev server before starting the tests */
webServer: {
command: ‘npm run dev’,
url: ‘http://localhost:3000’,
reuseExistingServer: !process.env.CI,
},
});
“`

## 基本操作

### 导航和交互

以下是一些基本的Playwright操作示例:

“`typescript
import { test, expect } from ‘@playwright/test’;

test(‘基本导航和交互’, async ({ page }) => {
// 导航到网页
await page.goto(‘https://example.com’);

// 点击元素
await page.click(‘text=More information’);

// 输入文本
await page.fill(‘input[name=”q”]’, ‘Playwright’);

// 按下回车键
await page.press(‘input[name=”q”]’, ‘Enter’);

// 等待页面加载
await page.waitForLoadState(‘networkidle’);

// 验证页面标题
await expect(page).toHaveTitle(/Playwright/);
});
“`

### 元素定位

Playwright提供了多种元素定位方法:

“`typescript
// 通过CSS选择器定位
await page.locator(‘css=.login-button’).click();

// 通过文本定位
await page.locator(‘text=登录’).click();

// 通过XPath定位
await page.locator(‘xpath=//button[contains(text(), “提交”)]’).click();

// 通过ID定位
await page.locator(‘#username’).fill(‘testuser’);

// 通过属性定位
await page.locator(‘[data-testid=”submit-button”]’).click();
“`

### 断言

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

“`typescript
// 验证元素是否存在
await expect(page.locator(‘.success-message’)).toBeVisible();

// 验证文本内容
await expect(page.locator(‘.title’)).toHaveText(‘Welcome’);

// 验证页面URL
await expect(page).toHaveURL(‘https://example.com/dashboard’);

// 验证元素属性
await expect(page.locator(‘input[name=”email”]’)).toHaveAttribute(‘type’, ’email’);
“`

## 高级功能

### 网络拦截

Playwright可以拦截和修改网络请求:

“`typescript
test(‘网络拦截示例’, async ({ page }) => {
// 拦截API请求并返回模拟数据
await page.route(‘https://api.example.com/data’, async (route) => {
await route.fulfill({
status: 200,
contentType: ‘application/json’,
body: JSON.stringify({ message: ‘Mock data’ }),
});
});

// 导航到页面
await page.goto(‘https://example.com’);

// 验证模拟数据是否显示
await expect(page.locator(‘.data-message’)).toHaveText(‘Mock data’);
});
“`

### 截图和视频

Playwright支持截图和视频录制:

“`typescript
test(‘截图示例’, async ({ page }) => {
await page.goto(‘https://example.com’);

// 截取全页截图
await page.screenshot({ path: ‘screenshots/full-page.png’, fullPage: true });

// 截取元素截图
await page.locator(‘.header’).screenshot({ path: ‘screenshots/header.png’ });
});
“`

### 移动设备模拟

Playwright可以模拟不同的移动设备:

“`typescript
import { test, devices } from ‘@playwright/test’;

test(‘移动设备模拟’, async ({ page }) => {
// 设置为iPhone 12
await page.setViewportSize({ width: 390, height: 844 });
await page.emulate(devices[‘iPhone 12’]);

await page.goto(‘https://example.com’);

// 验证移动版布局
await expect(page.locator(‘.mobile-menu’)).toBeVisible();
});
“`

## 最佳实践

### 1. 测试结构

组织良好的测试结构可以提高测试的可维护性:

“`typescript
import { test, expect } from ‘@playwright/test’;

test.describe(‘用户认证测试’, () => {
test.beforeEach(async ({ page }) => {
// 每个测试前的准备工作
await page.goto(‘https://example.com/login’);
});

test(‘成功登录’, async ({ page }) => {
await page.fill(‘input[name=”username”]’, ‘testuser’);
await page.fill(‘input[name=”password”]’, ‘password123’);
await page.click(‘button[type=”submit”]’);
await expect(page).toHaveURL(‘https://example.com/dashboard’);
});

test(‘登录失败’, async ({ page }) => {
await page.fill(‘input[name=”username”]’, ‘testuser’);
await page.fill(‘input[name=”password”]’, ‘wrongpassword’);
await page.click(‘button[type=”submit”]’);
await expect(page.locator(‘.error-message’)).toBeVisible();
});
});
“`

### 2. 页面对象模式

使用页面对象模式可以减少代码重复:

“`typescript
// pages/login.page.ts
import { Page, Locator } from ‘@playwright/test’;

export class LoginPage {
readonly page: Page;
readonly usernameInput: Locator;
readonly passwordInput: Locator;
readonly submitButton: Locator;
readonly errorMessage: Locator;

constructor(page: Page) {
this.page = page;
this.usernameInput = page.locator(‘input[name=”username”]’);
this.passwordInput = page.locator(‘input[name=”password”]’);
this.submitButton = page.locator(‘button[type=”submit”]’);
this.errorMessage = page.locator(‘.error-message’);
}

async goto() {
await this.page.goto(‘https://example.com/login’);
}

async login(username: string, password: string) {
await this.usernameInput.fill(username);
await this.passwordInput.fill(password);
await this.submitButton.click();
}
}

// tests/login.test.ts
import { test, expect } from ‘@playwright/test’;
import { LoginPage } from ‘../pages/login.page’;

test(‘登录测试’, async ({ page }) => {
const loginPage = new LoginPage(page);
await loginPage.goto();
await loginPage.login(‘testuser’, ‘password123’);
await expect(page).toHaveURL(‘https://example.com/dashboard’);
});
“`

### 3. 并行测试

Playwright支持并行测试,可以提高测试速度:

在`playwright.config.ts`中配置:

“`typescript
export default defineConfig({
// 启用并行测试
fullyParallel: true,
// 设置工作进程数
workers: process.env.CI ? 1 : undefined,
// …
});
“`

### 4. CI/CD集成

将Playwright测试集成到CI/CD流程中:

“`yaml
# .github/workflows/playwright.yml
name: Playwright Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
– uses: actions/checkout@v3
– uses: actions/setup-node@v3
with:
node-version: 16
– name: Install dependencies
run: npm ci
– name: Install Playwright browsers
run: npx playwright install –with-deps
– name: Run Playwright tests
run: npx playwright test
– uses: actions/upload-artifact@v3
if: always()
with:
name: playwright-report
path: playwright-report/
retention-days: 30
“`

## 常见问题与解决方案

### 1. 测试不稳定

**问题**:测试有时通过,有时失败,不稳定。

**解决方案**:
– 使用Playwright的自动等待功能,避免手动添加等待时间
– 使用`page.waitForLoadState()`确保页面完全加载
– 使用`page.waitForSelector()`等待元素出现
– 避免使用固定的等待时间(如`await page.waitForTimeout(1000)`)

### 2. 元素定位失败

**问题**:元素定位器无法找到元素。

**解决方案**:
– 使用更具体的定位器
– 确保元素在DOM中存在
– 使用`page.waitForSelector()`等待元素出现
– 检查是否有iframe或shadow DOM

### 3. 网络请求失败

**问题**:测试中的网络请求失败。

**解决方案**:
– 使用网络拦截模拟API响应
– 确保测试环境可以访问外部资源
– 检查网络连接和防火墙设置

### 4. 跨浏览器测试差异

**问题**:在不同浏览器中测试结果不一致。

**解决方案**:
– 为不同浏览器创建单独的测试配置
– 避免使用浏览器特定的功能
– 使用Playwright的跨浏览器API

## 代码示例

以下是一个完整的Playwright测试示例:

“`typescript
import { test, expect } from ‘@playwright/test’;

test.describe(‘示例测试套件’, () => {
test.beforeEach(async ({ page }) => {
// 导航到测试页面
await page.goto(‘https://example.com’);
});

test(‘验证页面标题’, async ({ page }) => {
// 验证页面标题
await expect(page).toHaveTitle(‘Example Domain’);
});

test(‘验证页面内容’, async ({ page }) => {
// 验证页面包含特定文本
await expect(page.locator(‘h1’)).toHaveText(‘Example Domain’);
await expect(page.locator(‘p’)).toContainText(‘This domain is for use in illustrative examples in documents.’);
});

test(‘导航到更多信息页面’, async ({ page }) => {
// 点击链接
await page.click(‘text=More information’);

// 验证导航
await expect(page).toHaveURL(‘https://www.iana.org/domains/example’);
});
});
“`

## 总结

Playwright是一个功能强大、易用的端到端测试框架,它提供了丰富的API和工具,让开发者能够更轻松地编写和运行自动化测试。通过本文的介绍,我们了解了Playwright的基础知识,包括安装、配置、基本操作和最佳实践。

使用Playwright的优势在于:
– 跨浏览器支持,确保应用在不同浏览器中的一致性
– 自动等待功能,减少测试不稳定因素
– 丰富的API,支持各种测试场景
– 强大的调试工具,便于分析测试失败原因
– 良好的CI/CD集成,支持持续集成和持续部署

通过合理运用Playwright,我们可以构建更加稳定、可靠的应用,提高开发效率和用户体验。

希望本文对您有所帮助,祝您测试愉快!

Scroll to Top