公司动态

Playwright 端到端测试实战-Day34

📅 2026/9/2 7:37:12
Playwright 端到端测试实战-Day34
目录背景与目标快速上手环境准备第一个用例常用命令核心机制为什么它不怎么飘1. 自动等待Auto-waiting2. Web 优先断言Web-first assertions3. 弹性定位器Resilient locators测试隔离每个用例都是干净的新浏览器进阶用法真实流程里的三件事拦截网络请求Mock / 造数据响应式与多浏览器追踪与截图失败现场可回放踩过的坑坑 1waitForTimeout 用了就回不去了坑 2XPath 选择器一重构就挂坑 3CI 里偶发失败本地却过坑 4多个 iframe / 新标签页找不到元素与 Selenium / Cypress 的取舍总结与后续参考链接背景与目标Web 应用越来越复杂回归测试靠人工点一遍既慢又容易漏。Playwright 是微软开源Apache-2.0 协议的端到端测试框架一套 API 覆盖 Chromium、Firefox、WebKit 三种内核JavaScript/TypeScript、Python、Java、.NET 四种语言都有官方支持。本文以TypeScript playwright/test为主线从安装写起讲清楚它的核心机制自动等待、定位器、断言再用一个真实流程串起来。快速上手环境准备需要 Node.js 18。在项目里初始化npminit playwrightlatest按提示选择 TypeScript、是否生成 GitHub Actions 工作流等。或者手动装npminit-ynpmi-Dplaywright/test npx playwrightinstallnpx playwright install会下载 Chromium、Firefox、WebKit 三个浏览器内核也可以只装需要的如npx playwright install chromium。第一个用例新建tests/example.spec.tsimport{test,expect}fromplaywright/test;test(页面标题正确,async({page}){awaitpage.goto(https://www.codefather.cn/post/1797520541019598849);awaitexpect(page).toHaveTitle(/2026 年最新编程学习路线零基础到精通一条龙万人收藏⭐️ - 编程导航 | 一线开发者编程经验和技术实战分享/);});test(点击链接后跳转,async({page}){awaitpage.goto(https://www.codefather.cn/post/1797520541019598849);awaitpage.getByRole(link,{name:Java 学习路线 | 26 年最新零基础到精通一条龙万人收藏⭐️}).click();awaitexpect(page).toHaveURL(/1789190431398928386/);});运行npx playwrighttest默认无头模式headless跑浏览器不弹出来想看过程加--headed。跑完npx playwright show-report打开 HTML 报告。常用命令npx playwrighttest# 跑全部用例npx playwrighttesttests/login# 跑指定目录npx playwrighttest-g登录# 按标题过滤npx playwrighttest--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// 推荐按角色名称定位贴近用户怎么找元素awaitpage.getByRole(button,{name:提交}).click();awaitpage.getByLabel(用户名).fill(tester);awaitpage.getByText(保存成功).toBeVisible();// 不推荐容易因样式/结构变化而失效awaitpage.locator(#root div div button.submit-btn).click();getByRole、getByLabel、getByPlaceholder、getByTestId这些定位器是实时解析的——页面变了下次执行时重新查找天然抗重构。测试隔离每个用例都是干净的新浏览器Playwright Test 里每个用例都拿到一个全新的BrowserContext相当于一个全新的浏览器配置文件独立 cookie、localStorage、缓存。这样用例之间互不污染test(用例A未登录状态,async({page}){// page 属于隔离的 contextcookie 是空的awaitpage.goto(/);awaitexpect(page.getByRole(button,{name:登录})).toBeVisible();});test(用例B已登录状态,async({page}){// 这里不会继承用例A的任何状态});登录态可以在playwright.config.ts里用globalSetup提前登录一次、保存 storageState后续用例复用避免每个用例都走一遍登录流程。进阶用法真实流程里的三件事拦截网络请求Mock / 造数据前后端联调时不想依赖真实后端用page.route拦截awaitpage.route(**/api/user,route{route.fulfill({status:200,contentType:application/json,body:JSON.stringify({name:测试用户,level:vip}),});});awaitpage.goto(/profile);awaitexpect(page.getByText(测试用户)).toBeVisible();响应式与多浏览器配置里声明 projects一份代码跑多套浏览器和多套视口import{defineConfig,devices}fromplaywright/test;exportdefaultdefineConfig({projects:[{name:chromium,use:{...devices[Desktop Chrome]}},{name:firefox,use:{...devices[Desktop Firefox]}},{name:mobile,use:{...devices[iPhone 13]}},],});追踪与截图失败现场可回放配置开启 trace用例失败时自动保留完整轨迹DOM 快照、网络、控制台、每一步截图在 Trace Viewer 里回放排查exportdefaultdefineConfig({use:{trace:on-first-retry,// 首次重试时记录screenshot:only-on-failure,},});踩过的坑坑 1waitForTimeout用了就回不去了早期习惯写await page.waitForTimeout(3000)等加载完成。它治标不治本还拖慢套件。正确做法是等一个业务信号文本出现、按钮可点// 不要await page.waitForTimeout(3000);// 要等待真实状态awaitexpect(page.getByText(加载完成)).toBeVisible();坑 2XPath 选择器一重构就挂从别的框架迁移来的代码常带一长串#app div:nth-child(2)。UI 微调就全红。换getByRole/getByTestId后选择器跟用户找元素的方式绑定重构影响小得多。给关键测试元素加data-testid是团队里性价比最高的约定。坑 3CI 里偶发失败本地却过多半是环境差异CI 机器慢、字体没装导致截图对比失败、时区/语言不同。排查顺序先看 trace 里失败那一步的截图 → 确认是不是断言超时 → 把默认timeout从 5s 调到 10s或针对慢操作单独加{ timeout: 15000 }。截图对比toHaveScreenshot在 CI 上先--update-snapshots重新生成基线。坑 4多个 iframe / 新标签页找不到元素Playwright 对 iframe 和弹窗支持很直接但要用对 API// iframe用 frameLocator而不是在 page 里硬找constframepage.frameLocator(#payment-frame);awaitframe.getByRole(button,{name:确认支付}).click();// 新标签页监听 context 的 page 事件const[newPage]awaitPromise.all([page.context().waitForEvent(page),page.getByRole(link,{name:打开新窗口}).click(),]);awaitnewPage.waitForLoadState();与 Selenium / Cypress 的取舍维度PlaywrightSeleniumCypress浏览器支持Chromium、Firefox、WebKit 原生支持全浏览器需驱动适配仅 Chromium 系语言JS/TS、Python、Java、.NETJava/Python/JS/C#/Ruby 等 7仅 JS/TS自动等待内置自动等待 断言重试需手动处理显式等待内置自动重试并行执行内置 worker 并行依赖 Grid配置复杂免费版有限云服务付费网络拦截内置page.route依赖第三方库内置有限多标签页/iframe原生体验好需 context 切换繁琐支持一般移动端内置设备模拟需集成 Appium不支持真机什么时候选 Playwright需要多浏览器覆盖、多语言团队、要内置并行和网络拦截的新项目——目前是新项目的常见默认选择。什么时候考虑其他团队已深度绑定 Java/Selenium 生态且浏览器覆盖面要求极广或只做简单单页应用、且必须用 JS/TS 且预算有限选 Cypress 也有道理。客观说Playwright 的生态和资料比 Selenium 少复杂需求有时要自己查源码。总结与后续Playwright 把端到端测试最头疼的不稳定问题通过自动等待 Web 优先断言 弹性定位器三层机制基本解决测试隔离和内置并行又降低了维护成本。建议新项目直接用它把给关键元素加>参考链接Playwright 官方文档中文编写测试 — 操作与断言定位器 API版本说明v1.62Playwright GitHub 仓库