Playwright 高级页面操作
本章节我们将介绍 Playwright 高级页面操作,这部分会更贴近真实测试需求,覆盖 等待机制、表单处理、弹窗对话框 等高级功能。
等待机制
Playwright 最大的优势之一就是 智能等待(auto-waiting):大部分操作(如 click
, fill
)会自动等待元素可见且可操作。但在复杂场景中,仍需要手动控制等待。
1. 隐式等待(Auto-waiting)
Playwright 内置的等待机制:
- 元素可见
- 可点击 / 可交互
- 页面加载完成
实例
await page.click('#submit'); // 自动等待按钮可见并可点击
2. 显式等待
显式调用等待方法,例如等待某个选择器、文本或请求。
实例
await page.waitForSelector('#result', { state: 'visible' });
常见 state
值:
'attached'
→ 元素出现在 DOM 中'visible'
→ 元素在页面可见'hidden'
→ 元素隐藏'detached'
→ 元素被移除
3. 等待元素出现 / 消失
// 等待元素出现 await page.waitForSelector('#loading', { state: 'visible' }); // 等待元素消失 await page.waitForSelector('#loading', { state: 'hidden' });
4. 等待网络请求完成
等待某个请求完成,常用于 AJAX 请求或 API 调用。
// 等待指定 URL 的请求完成 await page.waitForResponse(response => response.url().includes('/api/login') && response.status() === 200 );
5. 自定义等待条件
通过 page.waitForFunction
执行自定义等待逻辑。
// 等待页面上计数器达到 10 await page.waitForFunction(() => { return document.querySelector('#count').innerText === '10'; });
表单处理
表单是测试中最常见的交互场景。Playwright 提供了丰富的 API 来操作表单控件。
1. 输入框操作
await page.fill('#username', 'admin'); // 清空并输入 await page.type('#search', 'Playwright', { delay: 100 }); // 模拟逐字输入
2. 下拉菜单选择
// 通过 value await page.selectOption('#country', 'china'); // 通过标签文本 await page.selectOption('#country', { label: 'United States' }); // 通过 index await page.selectOption('#country', { index: 2 });
3. 复选框和单选框
// 勾选复选框 await page.check('#agree'); // 取消勾选 await page.uncheck('#subscribe'); // 点击单选框 await page.check('input[type="radio"][value="male"]');
4. 文件上传
// 直接上传文件 await page.setInputFiles('#upload', 'example.png'); // 上传多个文件 await page.setInputFiles('#upload', ['a.png', 'b.png']); // 清空文件 await page.setInputFiles('#upload', []);
5. 表单提交
提交表单有两种方式:
- 点击提交按钮
- 直接触发表单提交事件
await page.click('button[type="submit"]'); // 或者 await page.press('#form input[name="email"]', 'Enter');
弹窗和对话框
Playwright 可以捕获并处理 浏览器原生弹窗(alert, confirm, prompt),以及自定义模态框。
1. Alert 处理
page.once('dialog', async dialog => { console.log(dialog.message()); // 打印弹窗内容 await dialog.accept(); // 点击 "确定" }); await page.click('#show-alert');
2. Confirm 处理
page.once('dialog', async dialog => { console.log(dialog.message()); await dialog.dismiss(); // 点击 "取消" }); await page.click('#show-confirm');
3. Prompt 处理
page.once('dialog', async dialog => { console.log(dialog.message()); await dialog.accept('Playwright'); // 输入内容并确认 }); await page.click('#show-prompt');
4. 自定义模态框
自定义模态框(如 Bootstrap / Ant Design)其实就是普通 DOM 元素,可以直接用 定位 + 交互 的方式关闭或输入。
await page.click('#open-modal'); await page.fill('.modal input[name="name"]', 'Test User'); await page.click('.modal button.confirm');
实战案例 —— 注册表单自动化测试
下面的示例会综合使用 等待机制、表单操作、文件上传、对话框处理。
实例
// register-test.js
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch({ headless: false, slowMo: 500 });
const context = await browser.newContext();
const page = await context.newPage();
// 1. 打开注册页面
await page.goto('https://example.com/register', { waitUntil: 'domcontentloaded' });
// 2. 等待表单出现
await page.waitForSelector('#register-form', { state: 'visible' });
// 3. 输入基本信息
await page.fill('#username', 'testuser');
await page.fill('#email', 'test@example.com');
await page.fill('#password', 'Password123');
// 4. 下拉选择国家
await page.selectOption('#country', { label: 'China' });
// 5. 勾选条款
await page.check('#agree');
// 6. 上传头像
await page.setInputFiles('#avatar', 'avatar.png');
// 7. 点击提交
page.once('dialog', async dialog => {
console.log('弹窗内容:', dialog.message());
await dialog.accept(); // 点击确定
});
await page.click('button[type="submit"]');
// 8. 等待提交完成后的跳转
await page.waitForLoadState('networkidle');
// 9. 断言结果(是否包含欢迎文字)
const successText = await page.textContent('.welcome-message');
console.log('注册结果:', successText);
// 10. 截图保存
await page.screenshot({ path: 'register-success.png' });
await browser.close();
})();
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch({ headless: false, slowMo: 500 });
const context = await browser.newContext();
const page = await context.newPage();
// 1. 打开注册页面
await page.goto('https://example.com/register', { waitUntil: 'domcontentloaded' });
// 2. 等待表单出现
await page.waitForSelector('#register-form', { state: 'visible' });
// 3. 输入基本信息
await page.fill('#username', 'testuser');
await page.fill('#email', 'test@example.com');
await page.fill('#password', 'Password123');
// 4. 下拉选择国家
await page.selectOption('#country', { label: 'China' });
// 5. 勾选条款
await page.check('#agree');
// 6. 上传头像
await page.setInputFiles('#avatar', 'avatar.png');
// 7. 点击提交
page.once('dialog', async dialog => {
console.log('弹窗内容:', dialog.message());
await dialog.accept(); // 点击确定
});
await page.click('button[type="submit"]');
// 8. 等待提交完成后的跳转
await page.waitForLoadState('networkidle');
// 9. 断言结果(是否包含欢迎文字)
const successText = await page.textContent('.welcome-message');
console.log('注册结果:', successText);
// 10. 截图保存
await page.screenshot({ path: 'register-success.png' });
await browser.close();
})();
运行后效果:
- 自动填写表单、选择国家、上传头像
- 自动处理弹窗
- 提交后截图并验证欢迎信息
完整 API
以下整理了 页面导航、等待、表单、交互、弹窗 的常用 API:
分类 | 方法 / 属性 | 说明 |
---|---|---|
页面导航 | page.goto(url[, options]) |
打开页面 |
page.reload([options]) |
刷新页面 | |
page.goBack([options]) |
后退 | |
page.goForward([options]) |
前进 | |
page.waitForLoadState([state, options]) |
等待加载完成 | |
等待机制 | page.waitForSelector(selector[, options]) |
等待元素出现/消失 |
page.waitForResponse(fn[, options]) |
等待指定请求响应 | |
page.waitForFunction(pageFn[, arg, options]) |
自定义等待条件 | |
元素定位 | page.locator(selector) |
通用定位器 |
page.getByRole(role, options) |
根据角色定位 | |
page.getByText(text) |
根据文本定位 | |
page.getByPlaceholder(text) |
输入框 placeholder | |
page.getByLabel(text) |
表单 label | |
表单操作 | page.fill(selector, value) |
输入框(清空后填入) |
page.type(selector, text[, options]) |
模拟逐字输入 | |
page.press(selector, key) |
在元素上按键 | |
page.selectOption(selector, values) |
下拉菜单选择 | |
page.check(selector[, options]) |
勾选复选框/单选框 | |
page.uncheck(selector[, options]) |
取消勾选 | |
page.setInputFiles(selector, files) |
文件上传 | |
基础交互 | page.click(selector[, options]) |
点击元素 |
page.dblclick(selector[, options]) |
双击 | |
page.hover(selector[, options]) |
悬停 | |
page.mouse.move(x, y) |
鼠标移动 | |
page.mouse.click(x, y[, options]) |
鼠标点击 | |
page.dragAndDrop(src, dest[, options]) |
拖拽元素 | |
弹窗处理 | page.on('dialog', handler) |
监听对话框事件 |
dialog.message() |
获取弹窗文本 | |
dialog.accept([promptText]) |
确认(可输入内容) | |
dialog.dismiss() |
取消 | |
截图与断言 | page.screenshot({ path }) |
截图保存 |
page.textContent(selector) |
获取文本内容 | |
expect(locator).toHaveText(text) |
断言文本(需用 @playwright/test) |
点我分享笔记