Playwright 问题整理

0 阅读11分钟

Playwright 问题整理

1. 什么是 Playwright?

答法: Playwright 是微软推出的一个现代化 Web 自动化测试框架,用来做端到端测试、UI 自动化、跨浏览器测试,也支持接口测试。 它可以驱动 Chromium、Firefox、WebKit,支持多标签页、iframe、网络拦截、截图、录屏、Trace 等能力,比较适合现代前端项目。


2. Playwright 和 Selenium 有什么区别?

答法:

Playwright 优势

  • 原生支持多浏览器
  • 自动等待机制更强
  • API 更现代,开发体验更好
  • 对 SPA、动态页面支持更友好
  • 自带 Trace、Mock、并发、多上下文等功能

Selenium 特点

  • 生态更老、更广
  • 历史包袱更重
  • 某些传统测试体系里还很多

一句话总结

如果是现代前端项目,Playwright 一般更高效、更稳定。


3. Playwright 支持哪些浏览器?

答法: 支持三大浏览器引擎:

  • Chromium
  • Firefox
  • WebKit

其中 Chromium 也覆盖 Chrome 和 Edge 这类 Chromium 内核浏览器。


4. Playwright 的核心对象有哪些?

答法:

  • browser:浏览器实例
  • context:浏览器上下文,类似一个独立会话
  • page:具体页面,一个 tab
  • locator:元素定位器
  • test:测试定义
  • expect:断言工具

一般测试最常接触的是 pagelocatorexpect


5. Browser、Context、Page 的区别是什么?

答法:

  • browser:整个浏览器
  • context:浏览器里的独立环境,类似无痕窗口,可隔离 cookie / localStorage
  • page:上下文中的一个页面标签

举例

一个浏览器里可以开多个 context, 每个 context 里又可以开多个 page。

这在多用户登录、隔离测试场景很有用。


6. Playwright 为什么比别的工具稳定?

答法: 一个重要原因是它的自动等待机制。 比如点击、输入、断言时,Playwright 会自动等待元素满足可见、可交互、稳定等条件,而不是立刻执行。

这减少了很多因为页面加载慢、元素未渲染完成导致的偶发失败。


7. 什么是 Locator?为什么推荐 Locator?

答法: Locator 是 Playwright 推荐的元素定位方式。 它不是一次性抓 DOM,而是带有自动重试和自动等待能力的定位对象。

为什么推荐

  • 更稳定
  • 支持链式操作
  • 配合断言更自然
  • 比直接 querySelector 思路更适合测试场景

8. 常见定位方式有哪些?推荐顺序是什么?

答法:

常见方式:

  • getByRole
  • getByLabel
  • getByPlaceholder
  • getByText
  • getByTestId
  • locator(css)
  • xpath

推荐顺序

  1. getByRole
  2. getByLabel
  3. getByPlaceholder
  4. getByTestId
  5. CSS
  6. XPath

原因

越语义化,越稳定,越贴近用户真实操作。


9. 为什么不推荐大量使用 XPath?

答法: XPath 通常可读性差、维护成本高,而且容易和页面结构强耦合。 页面层级稍微改一下,XPath 就可能失效。 除非特殊场景,否则更推荐语义化定位或者稳定的 testId。


10. Playwright 中常见断言有哪些?

答法:

  • toHaveTitle
  • toHaveURL
  • toBeVisible
  • toBeHidden
  • toHaveText
  • toContainText
  • toHaveValue
  • toHaveCount
  • toBeChecked
  • toBeEnabled

这些断言本身也带自动等待。


11. page.locator()page.getByRole() 有什么区别?

答法:

  • locator() 更通用,可以写 CSS/XPath/复杂选择器
  • getByRole() 更语义化,更贴近无障碍标准,更推荐优先使用

如果页面本身语义做得好,getByRole() 往往更稳定,也更能体现从用户视角操作页面。


12. Playwright 中等待机制有哪些?

答法:

常见等待方式:

  • 自动等待
  • expect(...).toBeVisible() 这种断言等待
  • locator.waitFor()
  • page.waitForURL()
  • page.waitForResponse()
  • page.waitForRequest()

不推荐

  • waitForTimeout()

因为它是固定死等,慢且不稳定。


13. 为什么不推荐 waitForTimeout()

答法: 因为它是拍脑袋等待。

问题有两个:

  1. 等短了,页面没准备好,测试失败
  2. 等长了,测试变慢

更好的方式是等待明确条件,比如元素可见、URL 变化、接口响应成功。


14. Playwright 如何处理 iframe?

答法: 通过 frameLocator()

const frame = page.frameLocator('#my-frame');
await frame.getByRole('button', { name: '提交' }).click();

这样可以在 iframe 内继续使用 Playwright 的定位和断言能力。


15. 如何处理新窗口或新标签页?

答法:

const [newPage] = await Promise.all([
  page.waitForEvent('popup'),
  page.getByText('打开').click(),
]);

然后对 newPage 做操作和断言。


16. 如何处理文件上传和下载?

答法:

上传

setInputFiles()

await page.locator('input[type="file"]').setInputFiles('./a.png');

下载

监听 download 事件:

const downloadPromise = page.waitForEvent('download');
await page.getByText('下载').click();
const download = await downloadPromise;
await download.saveAs('./downloads/a.xlsx');

17. 如何处理弹窗 alert / confirm / prompt?

答法: 通过监听页面的 dialog 事件:

page.on('dialog', async dialog => {
  console.log(dialog.message());
  await dialog.accept();
});

如果要取消,就用 dismiss()


18. Playwright 中如何做接口 Mock?

答法: 通过 page.route() 拦截请求,再用 route.fulfill() 返回假数据。

await page.route('**/api/user', async route => {
  await route.fulfill({
    status: 200,
    contentType: 'application/json',
    body: JSON.stringify({ name: '张三' }),
  });
});

这在前后端并行开发、异常场景测试、边界测试里很常用。


19. 如何监听接口请求或响应?

答法:

监听响应:

await page.waitForResponse(resp =>
  resp.url().includes('/api/user') && resp.status() === 200
);

监听请求:

await page.waitForRequest('**/api/login');

20. Playwright 如何复用登录状态?

答法: 通过 storageState 保存 cookie 和本地存储状态。

保存

await page.context().storageState({ path: 'playwright/.auth/user.json' });

使用

在配置中:

use: {
  storageState: 'playwright/.auth/user.json',
}

这样可以避免每条用例都重复登录,提高执行效率。


21. 什么是 Page Object Model(POM)?

答法: POM 是页面对象模型,把页面元素和页面操作封装成类,提高复用性和可维护性。

优点

  • 减少重复代码
  • 页面改动时更容易统一维护
  • 测试代码更清晰

适用场景

当项目页面多、流程复杂时,POM 很有价值。


22. POM 有什么缺点?

答法: 如果封装过度,会造成:

  • 层级过深
  • 维护成本上升
  • 简单测试反而变复杂

所以我一般会适度封装,只把高复用页面和公共流程抽出去,不会为了封装而封装。

这个回答面试官通常会觉得你比较实战,不是只会背概念。


23. Playwright 如何做跨浏览器测试?

答法:playwright.config.ts 里配置多个 projects

projects: [
  { name: 'chromium', use: { ...devices['Desktop Chrome'] } },
  { name: 'firefox', use: { ...devices['Desktop Firefox'] } },
  { name: 'webkit', use: { ...devices['Desktop Safari'] } },
]

运行时就可以并行在不同浏览器上执行。


24. Playwright 如何调试失败用例?

答法:

常用方法:

  • --debug
  • page.pause()
  • --headed
  • 看截图
  • 看视频
  • 看 Trace

其中 Trace 最有价值,因为它能完整回放测试过程,包括点击、网络、DOM 快照、控制台信息。


25. 什么是 Trace?为什么有用?

答法: Trace 是 Playwright 的执行追踪能力。 失败后可以回看测试执行的完整上下文,比如:

  • 每一步操作
  • 页面快照
  • 请求响应
  • 控制台日志
  • 错误信息

这比单纯看报错日志更容易定位问题。


26. Playwright 如何做 API 测试?

答法: Playwright 除了页面测试,也支持接口测试,可以用 request fixture 发送 HTTP 请求。

test('api test', async ({ request }) => {
  const resp = await request.get('/api/user');
  expect(resp.ok()).toBeTruthy();
});

适合把 UI 测试和部分接口验证放到同一套框架里。


27. E2E 测试和 UI 自动化测试的区别是什么?

答法:

  • UI 自动化测试 更偏页面层面,比如按钮、表单、页面展示
  • E2E 测试 更强调完整业务链路,从前端到后端到数据库的一整条流程

Playwright 常用于 E2E,也可以做单纯的 UI 自动化。


28. Playwright 适合做什么,不适合做什么?

答法:

适合

  • Web E2E 测试
  • 回归测试
  • 多浏览器兼容测试
  • UI 自动化
  • 一部分 API 测试

不太适合

  • 非浏览器桌面应用自动化
  • 极重度性能压测
  • 完全替代后端接口测试体系

29. 如何让 Playwright 测试更稳定?

答法:

我的做法一般有这几条:

  1. 优先用稳定定位方式,比如 getByRolegetByTestId
  2. 少用固定等待,多用显式条件等待
  3. 保证测试数据独立
  4. 公共流程适度封装
  5. 对失败场景保留截图、视频、Trace
  6. 控制测试之间依赖
  7. 尽量避免一条用例验证太多事情

30. 如何设计高质量自动化测试用例?

答法: 我会关注这几件事:

  • 用例目标明确,一个 case 验证一个核心点
  • 可重复执行,不依赖前序状态
  • 数据可控,方便回归
  • 优先覆盖核心业务路径
  • 正常场景 + 异常场景都要有
  • 保证断言是有效断言,不只是“点了一遍没报错”

31. 自动化测试里最容易踩的坑是什么?

答法:

常见坑有:

  • 定位不稳定
  • 依赖固定等待
  • 用例之间相互依赖
  • 测试环境数据污染
  • 一个 case 写太长
  • 失败后缺少证据,难排查

如果我来落地项目,我会优先从“定位规范、等待策略、测试数据隔离、失败证据”这几个方面先定规则。


32. Playwright 和 Cypress 有什么区别?

答法:

Playwright 优势

  • 浏览器支持更完整,含 WebKit
  • 多页面、多标签支持更自然
  • 自动化能力更强
  • API 测试、Mock、权限、下载上传等更灵活

Cypress 特点

  • 上手也快
  • 前端圈有一定普及
  • 但某些复杂浏览器场景不如 Playwright 灵活

如果是新项目,我一般更倾向 Playwright。


33. 你在项目中怎么落地 Playwright?

这个很高频,建议这样答。

参考答法:

我一般会这样落地:

  1. 先确定自动化范围,优先覆盖核心主流程
  2. 设计目录结构,比如页面对象、测试用例、公共方法、测试数据分层
  3. 建立定位规范,优先 getByRole / getByTestId
  4. 封装登录、公共导航、数据准备等高频动作
  5. 配好失败截图、视频、Trace
  6. 接入 CI,让主干分支自动跑回归
  7. 后续根据缺陷和变更持续补充回归用例

这样能保证自动化不是“写了一堆脚本”,而是真能服务质量保障。


34. 如果测试很慢,你怎么优化?

答法:

我会从几方面优化:

  • 复用登录态,减少重复登录
  • 并行执行测试
  • 减少不必要的 UI 操作
  • 用 API 准备测试数据
  • 只在失败时保留重型证据
  • 拆分冒烟、回归、全量测试分层执行

35. 如果某条用例偶发失败,你怎么排查?

答法: 我会按这个顺序排查:

  1. 看报错点
  2. 看截图 / 视频 / Trace
  3. 判断是环境问题、数据问题还是脚本问题
  4. 检查定位是否稳定
  5. 检查是不是等待条件写得不对
  6. 看接口响应是否异常
  7. 如果是偶发,就分析是否存在异步加载、动画、弹窗遮挡、脏数据等问题

重点不是“重跑过了就算了”,而是定位 flakiness 的根因。


36. 你觉得 Playwright 的最佳实践有哪些?

答法:

  • 语义化定位优先
  • 少 sleep,多等条件
  • 测试独立
  • 公共流程适度封装
  • 核心流程优先自动化
  • 失败证据完整
  • CI 持续执行
  • 测试代码也要像生产代码一样维护质量

面试加分回答模板

如果面试官问:

“你为什么选 Playwright?”

你可以这样答:

因为它对现代 Web 应用支持比较好,自动等待和跨浏览器能力都很强,而且调试工具完善,像 Trace、Mock、下载上传、多标签页这些场景都支持得比较成熟。对于前端项目的 E2E 和回归测试,落地效率很高。


“你在项目里怎么保证脚本可维护?”

你可以这样答:

我会先统一定位策略和目录结构,然后把高复用流程做适度封装,比如登录、导航、数据准备,同时避免过度封装。测试用例保持目标单一、相互独立,失败时保留 Trace 和截图,这样维护成本会低很多。


“Playwright 稳定性怎么保证?”

你可以这样答:

关键是定位策略、等待策略和数据隔离。优先用稳定定位方式,避免固定等待;测试数据尽量独立;同时保留失败现场,这样既能减少 flaky case,也能快速定位问题。


最后给你一个面试建议

如果你真要拿它去面试,最值得准备的是这 4 类:

  1. 基础概念:browser / context / page / locator
  2. 稳定性:自动等待、少 sleep、定位规范
  3. 工程化:POM、目录结构、CI、登录态复用
  4. 实战排错:Trace、Mock、偶发失败怎么查

这几类答顺了,基本就不像“只看过文档的人”。