Playwright 端到端测试实战-Day34

目录

背景与目标

Web 应用越来越复杂,回归测试靠人工点一遍既慢又容易漏。Playwright 是微软开源(Apache-2.0 协议)的端到端测试框架,一套 API 覆盖 Chromium、Firefox、WebKit 三种内核,JavaScript/TypeScript、Python、Java、.NET 四种语言都有官方支持。本文以 TypeScript + @playwright/test 为主线,从安装写起,讲清楚它的核心机制(自动等待、定位器、断言),再用一个真实流程串起来。

快速上手

环境准备

需要 Node.js 18+。在项目里初始化:

bash 复制代码
npm init playwright@latest

按提示选择 TypeScript、是否生成 GitHub Actions 工作流等。或者手动装:

bash 复制代码
npm init -y
npm i -D @playwright/test
npx playwright install

npx playwright install 会下载 Chromium、Firefox、WebKit 三个浏览器内核(也可以只装需要的,如 npx playwright install chromium)。

第一个用例

新建 tests/example.spec.ts

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

test('页面标题正确', async ({ page }) => {
  await page.goto('https://www.codefather.cn/post/1797520541019598849');
  await expect(page).toHaveTitle(/2026 年最新编程学习路线零基础到精通一条龙(万人收藏⭐️) - 编程导航 | 一线开发者编程经验和技术实战分享/);
});

test('点击链接后跳转', async ({ page }) => {
  await page.goto('https://www.codefather.cn/post/1797520541019598849');
  await page.getByRole('link', { name: 'Java 学习路线 | 26 年最新零基础到精通一条龙(万人收藏⭐️)' }).click();
  await expect(page).toHaveURL(/1789190431398928386/);
});

运行:

bash 复制代码
npx playwright test

默认无头模式(headless)跑,浏览器不弹出来;想看过程加 --headed。跑完 npx playwright show-report 打开 HTML 报告。

常用命令

bash 复制代码
npx playwright test              # 跑全部用例
npx playwright test tests/login  # 跑指定目录
npx playwright test -g "登录"     # 按标题过滤
npx playwright test --headed     # 有头模式
npx playwright codegen example.com  # 录制用例(自动生成选择器)
npx playwright show-report       # 打开 HTML 报告

核心机制:为什么它不怎么"飘"

端到端测试最常见的痛点是不稳定(flaky)------明明功能正常,用例却偶发失败,多半是竞态:元素还没渲染出来就去点了。Playwright 用三层设计解决这个问题。

1. 自动等待(Auto-waiting)

每个操作(click、fill 等)执行前,Playwright 会自动等待元素达到可操作状态(actionability) :可见、稳定(不抖动)、接收事件、未被遮挡。你不需要写 sleep(1000)waitForElementVisible 这类手动等待。

2. Web 优先断言(Web-first assertions)

断言是异步的、会自动重试 直到满足条件或超时(默认 5 秒)。比如 await expect(page.getByText('保存成功')).toBeVisible() 会一直等到这个文本出现,而不是只查一次。这条和自动等待配合,把"等一个稳定状态"这件事彻底交给框架。

3. 弹性定位器(Resilient locators)

官方推荐用用户可见的方式定位,而不是脆弱的 CSS/XPath:

typescript 复制代码
// 推荐:按角色+名称定位,贴近用户怎么找元素
await page.getByRole('button', { name: '提交' }).click();
await page.getByLabel('用户名').fill('tester');
await page.getByText('保存成功').toBeVisible();

// 不推荐:容易因样式/结构变化而失效
await page.locator('#root > div > div > button.submit-btn').click();

getByRolegetByLabelgetByPlaceholdergetByTestId 这些定位器是实时解析的------页面变了,下次执行时重新查找,天然抗重构。

测试隔离:每个用例都是"干净的新浏览器"

Playwright Test 里每个用例都拿到一个全新的 BrowserContext(相当于一个全新的浏览器配置文件,独立 cookie、localStorage、缓存)。这样用例之间互不污染:

typescript 复制代码
test('用例A:未登录状态', async ({ page }) => {
  // page 属于隔离的 context,cookie 是空的
  await page.goto('/');
  await expect(page.getByRole('button', { name: '登录' })).toBeVisible();
});

test('用例B:已登录状态', async ({ page }) => {
  // 这里不会继承用例A的任何状态
});

登录态可以在 playwright.config.ts 里用 globalSetup 提前登录一次、保存 storageState,后续用例复用,避免每个用例都走一遍登录流程。

进阶用法:真实流程里的三件事

拦截网络请求(Mock / 造数据)

前后端联调时不想依赖真实后端,用 page.route 拦截:

typescript 复制代码
await page.route('**/api/user', route => {
  route.fulfill({
    status: 200,
    contentType: 'application/json',
    body: JSON.stringify({ name: '测试用户', level: 'vip' }),
  });
});
await page.goto('/profile');
await expect(page.getByText('测试用户')).toBeVisible();

响应式与多浏览器

配置里声明 projects,一份代码跑多套浏览器和多套视口:

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

export default defineConfig({
  projects: [
    { name: 'chromium', use: { ...devices['Desktop Chrome'] } },
    { name: 'firefox', use: { ...devices['Desktop Firefox'] } },
    { name: 'mobile', use: { ...devices['iPhone 13'] } },
  ],
});

追踪与截图:失败现场可回放

配置开启 trace,用例失败时自动保留完整轨迹(DOM 快照、网络、控制台、每一步截图),在 Trace Viewer 里回放排查:

typescript 复制代码
export default defineConfig({
  use: {
    trace: 'on-first-retry', // 首次重试时记录
    screenshot: 'only-on-failure',
  },
});

踩过的坑

坑 1:waitForTimeout 用了就回不去了

早期习惯写 await page.waitForTimeout(3000) 等加载完成。它治标不治本,还拖慢套件。正确做法是等一个业务信号(文本出现、按钮可点):

typescript 复制代码
// 不要:await page.waitForTimeout(3000);
// 要:等待真实状态
await expect(page.getByText('加载完成')).toBeVisible();

坑 2:XPath 选择器一重构就挂

从别的框架迁移来的代码常带一长串 #app > div:nth-child(2)。UI 微调就全红。换 getByRole / getByTestId 后,选择器跟"用户找元素的方式"绑定,重构影响小得多。给关键测试元素加 data-testid 是团队里性价比最高的约定。

坑 3:CI 里偶发失败,本地却过

多半是环境差异:CI 机器慢、字体没装导致截图对比失败、时区/语言不同。排查顺序:先看 trace 里失败那一步的截图 → 确认是不是断言超时 → 把默认 timeout 从 5s 调到 10s,或针对慢操作单独加 { timeout: 15000 }。截图对比(toHaveScreenshot)在 CI 上先 --update-snapshots 重新生成基线。

坑 4:多个 iframe / 新标签页找不到元素

Playwright 对 iframe 和弹窗支持很直接,但要用对 API:

typescript 复制代码
// iframe:用 frameLocator,而不是在 page 里硬找
const frame = page.frameLocator('#payment-frame');
await frame.getByRole('button', { name: '确认支付' }).click();

// 新标签页:监听 context 的 'page' 事件
const [newPage] = await Promise.all([
  page.context().waitForEvent('page'),
  page.getByRole('link', { name: '打开新窗口' }).click(),
]);
await newPage.waitForLoadState();

与 Selenium / Cypress 的取舍

维度 Playwright Selenium Cypress
浏览器支持 Chromium、Firefox、WebKit 原生支持 全浏览器(需驱动适配) 仅 Chromium 系
语言 JS/TS、Python、Java、.NET Java/Python/JS/C#/Ruby 等 7+ 仅 JS/TS
自动等待 内置(自动等待 + 断言重试) 需手动处理显式等待 内置自动重试
并行执行 内置 worker 并行 依赖 Grid,配置复杂 免费版有限,云服务付费
网络拦截 内置 page.route 依赖第三方库 内置有限
多标签页/iframe 原生体验好 需 context 切换,繁琐 支持一般
移动端 内置设备模拟 需集成 Appium 不支持真机

什么时候选 Playwright :需要多浏览器覆盖、多语言团队、要内置并行和网络拦截的新项目------目前是新项目的常见默认选择。什么时候考虑其他:团队已深度绑定 Java/Selenium 生态且浏览器覆盖面要求极广;或只做简单单页应用、且必须用 JS/TS 且预算有限选 Cypress 也有道理。客观说,Playwright 的生态和资料比 Selenium 少,复杂需求有时要自己查源码。

总结与后续

Playwright 把端到端测试最头疼的"不稳定"问题,通过自动等待 + Web 优先断言 + 弹性定位器三层机制基本解决;测试隔离和内置并行又降低了维护成本。建议新项目直接用它,把"给关键元素加 data-testid、断言只等业务信号、失败必开 trace"当成团队约定,稳定性和排查效率都能明显提升。

下一步可以看:Codegen 录制、UI Mode 交互调试、GitHub Actions CI 集成、视觉回归(toHaveScreenshot)。进阶可以用 Playwright 的 MCP 能力结合 AI 生成用例(v1.60+ 起官方捆绑 Playwright MCP 服务)。

参考链接

相关推荐
hao xiao zi4 天前
UI调试平台Web UI自动化项目框架设计
自动化测试·自动化·web自动化测试·playwright
阿图灵12 天前
猫眼票房监控系统实战:z3 约束求解破解字体混淆反爬
爬虫·playwright·反爬·z3·猫眼票房
wuhuhuan22 天前
Day18_参数化实战
playwright
久久学姐1 个月前
Python+Playwright+Pytest+BDD,用FSM打造高效测试框架
python·pytest·bdd·playwright·fsm
ji_shuke1 个月前
从零深入:基于 Playwright + Pytest + Allure 的企业级 Web 端到端自动化测试框架实战
前端·自动化测试·docker·jenkins·pytest·allure·playwright
ji_shuke1 个月前
Playwright 从零到 CI 实战:基于 TypeScript 的端到端测试完整指南
javascript·ci/cd·typescript·playwright
水中加点糖1 个月前
Java中使用远程PlayWright进行网页接口测试(附Docker部署方式)
java·docker·web测试·devtools·playwright·ai自动化测试
wuhuhuan1 个月前
Day 10:数据驱动测试
playwright
wuhuhuan2 个月前
Day 5:元素操作进阶
playwright