
最近帮几个粉丝做模拟面试,发现一个很普遍的问题:
简历上写了 Playwright 项目,但一问细节就卡壳——比如 page.route() 是干啥的?为什么不用 sleep()?怎么处理登录态?”。
工具不难,难的是理解它为什么这么设计,以及怎么用它解决真实问题。
我结合近半年字节、腾讯、美团等大厂的真实校招/初级岗面试题,整理出这份 《Playwright 面试》,按难度分五块: ✅ 基础概念 → ✅ 元素操作 → ✅ 网络控制 → ✅ 工程实践 → ✅ 未来方向每道题都告诉你:
建议收藏,面试前通读一遍,比盲目刷题高效得多。
这些题看似简单,但答不好,直接挂——因为面试官怀疑你根本没写过代码。
❌ 别只说“Playwright 更快”。 ✅ 正确答法:
💡 给新人的建议:哪怕你只用过 Selenium,也要去官网跑一遍 Playwright 官方 demo(10分钟就能跑通),感受“自动等待”的爽。
const browser = await chromium.launch({ headless: false });💡 什么时候用?
📌 小技巧:本地开发用 headless: false,CI 里一定用 true(省资源)。
但有些页面是“动态加载数据”的(比如商品列表),这时候要用:
await page.goto('/product');
await page.waitForLoadState('networkidle'); // 等待网络空闲
// 或者更精准的等待
await page.waitForSelector('.product-list', { state: 'visible' });💡 新手误区:以为页面出来就完事了,其实 API 数据还没回来,导致断言失败。
page.on('dialog', async dialog => {
console.log('弹窗内容:', dialog.message());
await dialog.accept(); // 点确定
});⚠️ 关键点:必须在触发弹窗之前注册监听!否则脚本会卡死。
截图:
await page.screenshot({ path: 'result.png' })录视频(需在创建 context 时开启):
const context = await browser.newContext({
recordVideo: { dir: 'videos/' }
});💡 实战建议:在 CI 失败时自动保存视频,排查效率提升 10 倍!
// playwright.config.ts
export default defineConfig({
use: {
// 所有测试都录屏(CI上会很耗资源)
video: 'on-first-retry', // 推荐:只在第一次重试时录屏
// 或 'retain-on-failure' // 只在失败时保留
},
});✅ 不强制,但强烈建议学。 原因:
🎯 行动建议:哪怕你只会 JS,也试着把 .js 改成 .ts,装个 VS Code 插件,慢慢适应。
补充:
# 常见安装问题及解决方案
# 1. 网络问题导致下载失败
# 解决方案:设置国内镜像
npm config set registry https://registry.npmmirror.com
PLAYWRIGHT_DOWNLOAD_HOST=https://npmmirror.com/mirrors/playwright npx playwright install
# 2. 权限问题
# 在Linux/Mac上可能需要sudo
# 或使用--user当前用户安装
# 3. 版本兼容性
# 确保package.json中的版本一致// 给新人的最小可运行示例
import { test, expect } from '@playwright/test';
test('我的第一个测试', async ({ page }) => {
// 1. 导航到页面
await page.goto('https://demo.playwright.dev/todomvc');
// 2. 执行操作
await page.fill('.new-todo', '学习Playwright');
await page.press('.new-todo', 'Enter');
// 3. 验证结果
await expect(page.locator('.todo-list li')).toHaveText('学习Playwright');
// 4. 添加等待(如果需要)
await page.waitForTimeout(1000); // 仅用于调试,生产环境避免使用
});很多新人习惯用 XPath/CSS 选择器,结果页面一改就全崩。
✅ 推荐顺序(越靠前越稳):
// "尽量避免复杂的XPath,因为:
// 1. 可读性差,维护困难
// 2. 前端改动一点就可能失效
// 3. 容易写出低效的选择器
// 但如果不得不使用CSS/XPath,也要学会正确使用:
// ✅ 相对稳定的CSS选择器
await page.locator('[data-testid="submit-btn"]').click();
await page.locator('form.login-form > button[type="submit"]').click();
// ❌ 避免使用的XPath
// await page.locator('//div[3]/span[2]').click(); // 脆弱!
// await page.locator('//*[@id="app"]/div[2]/button').click(); // 更脆弱!💡 给新人的忠告:推动前端加 data-testid,这是测开的基本话语权。
✅ 最佳方案:让前端加 data-testid="submit-btn" 🛠 你可以这么做:
次选方案:用文本定位 + 向上找父级
await page.getByText('立即下单').locator('..').click();await page.getByText('提交订单').scrollIntoViewIfNeeded();
await page.getByText('提交订单').click();💡 注意:某些框架(如 Vue)需要先确保元素已渲染,可加 waitFor。
const fileInput = page.locator('input[type="file"]');
await fileInput.setInputFiles('./test.pdf');
✅ 支持传数组:setInputFiles(['a.pdf', 'b.jpg'])// Windows/Linux
await page.keyboard.press('Control+C');
// macOS
await page.keyboard.press('Meta+A');能 Mock API 的测开,工资至少高 30%。
await page.route('**/api/user/info', route => {
route.fulfill({ json: { name: '测试用户', role: 'admin' } });
});💡 应用场景:
✅ 一句话总结:
const [response] = await Promise.all([
page.waitForResponse(resp => resp.url().includes('/order')),
page.click('text=提交订单')
]);
expect(response.status()).toBe(200);✅ 这是高频面试题!务必掌握。
await page.route('**/api/*', route => {
// 模拟断网
route.abort();
// 或模拟慢速(5秒后返回)
// setTimeout(() => route.continue(), 5000);
});page.on('requestfinished', req => {
const timing = req.timing();
console.log('TTFB:', timing.responseStart - timing.requestStart);
});💡 建议:把关键页面的 TTFB 加到冒烟测试里,超过阈值就报警。
面试官看你的代码结构,就知道你有没有工程思维。
✅ 推荐结构:
// 更适合新人的目录结构
src/
├── pages/ // 页面对象
│ ├── BasePage.ts // 基础页面类
│ ├── LoginPage.ts
│ ├── HomePage.ts
│ └── components/ // 可复用的组件
│ └── Header.ts
├── tests/
│ ├── specs/ // 测试用例
│ │ ├── login.spec.ts
│ │ └── checkout.spec.ts
│ ├── fixtures/ // 测试夹具
│ │ └── test-data.ts
│ └── utils/ // 工具函数
│ ├── helpers.ts
│ └── assertions.ts
└── playwright.config.ts
// 示例:BasePage.ts - 新人可以从这里开始
export class BasePage {
constructor(protected page: Page) {}
// 常用方法的封装
async waitAndClick(selector: string) {
await this.page.waitForSelector(selector);
await this.page.click(selector);
}
async typeAndEnter(selector: string, text: string) {
await this.page.fill(selector, text);
await this.page.press(selector, 'Enter');
}
}示例:
// LoginPage.ts
export class LoginPage {
constructor(private page: Page) {}
async login(username: string, password: string) {
await this.page.fill('#user', username);
await this.page.fill('#pwd', password);
await this.page.click('#submit');
}
}在 playwright.config.ts 里配置:
projects: [
{ name: 'Chrome', use: { ...devices['Desktop Chrome'] } },
{ name: 'Firefox', use: { ...devices['Desktop Firefox'] } }
]✅ 三大策略:
✅ 官方提供 Docker 镜像,一行搞定:
//yaml
container: mcr.microsoft.com/playwright:v1.40.0-focal💡 加分项:失败时自动上传视频到 artifacts。
✅ 用 Factory 模式:
function createUser(role: 'admin' | 'user') {
return { email: `test_${role}@xx.com`, role };
}好处:易维护、可复用、不泄露真实数据。
maxDiffPixelRatio: 0.01,
mask: [page.getByText(new Date().toLocaleDateString())] // 忽略日期
});⚠️ 前提:固定 viewport、字体、时间等变量!
这些题不一定考,但你能聊,面试官会觉得你“有潜力”。
✅ 可以!关键点:
✅ 可以!试试这样问 GPT:
“根据这个 UI 截图,生成 Playwright 登录测试代码,使用 getByTestId”
🚀 行动建议:用 AI 生成初稿,你负责优化和维护——效率翻倍。
✅ 可以!模拟 iPhone:
const { devices } = require('@playwright/test');
const context = await browser.newContext(devices['iPhone 14 Pro']);⚠️ 注意:只能测 H5/PWA,不能测原生 App。
💡 建议准备一个真实故事,比如:
“有一次测试总失败,后来发现是 CSP 策略阻止了 route 拦截,最后通过注入 script 解决,并写了文档分享给团队。”
面试官爱听这种:发现问题 → 分析 → 解决 → 复盘。
✅ 高阶答法:
Playwright 是个好工具,但它只是解决问题的手段。真正拉开差距的,是你对业务的理解、对稳定性的追求、对工程化的思考。 如果你正在准备面试,不妨对照这29问,动手写几段代码、跑几个 mock 场景。理解胜过记忆,比起背答案,亲手跑一遍印象更深。
祝你面试顺利,早日拿下心仪 offer!
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。