Playwright Frame 与新窗口
本章介绍如何处理 iframe、弹窗对话框、新标签页以及 Playwright 的事件系统。
iframe 操作
Playwright 通过 frameLocator() 来定位和操作 iframe 内的元素。
page.frameLocator() 定位 iframe
实例
test('操作 iframe 中的元素', async ({ page }) => {
await page.goto('https://www.runoob.com/iframe-demo');
// 定位 iframe,然后在其中定位元素
const iframe = page.frameLocator('#my-iframe');
// 在 iframe 内操作元素
await iframe.getByRole('button', { name: '提交' }).click();
await iframe.getByLabel('用户名').fill('runoob_user');
// 在 iframe 内断言
await expect(iframe.getByText('操作成功')).toBeVisible();
});
await page.goto('https://www.runoob.com/iframe-demo');
// 定位 iframe,然后在其中定位元素
const iframe = page.frameLocator('#my-iframe');
// 在 iframe 内操作元素
await iframe.getByRole('button', { name: '提交' }).click();
await iframe.getByLabel('用户名').fill('runoob_user');
// 在 iframe 内断言
await expect(iframe.getByText('操作成功')).toBeVisible();
});
获取所有 Frame
实例
// 获取页面中所有 frame(包括主 frame 和 iframe)
const frames = page.frames();
console.log('页面共', frames.length, '个 frame');
frames.forEach(frame => {
console.log('Frame:', frame.name(), frame.url());
});
const frames = page.frames();
console.log('页面共', frames.length, '个 frame');
frames.forEach(frame => {
console.log('Frame:', frame.name(), frame.url());
});
嵌套 iframe
Playwright 的 frameLocator() 支持链式调用,可以深入嵌套的 iframe。
实例
// 嵌套 iframe:外层 → 内层 → 元素
const innerButton = page
.frameLocator('#outer-frame')
.frameLocator('#inner-frame')
.getByRole('button', { name: '确认' });
await innerButton.click();
const innerButton = page
.frameLocator('#outer-frame')
.frameLocator('#inner-frame')
.getByRole('button', { name: '确认' });
await innerButton.click();
弹窗处理(Dialogs)
Playwright 对浏览器原生弹窗(alert、confirm、prompt)有默认处理策略。
默认行为
Playwright 默认自动关闭所有弹窗:
| 弹窗类型 | 默认行为 |
|---|---|
alert() | 自动确认(关闭) |
confirm() | 自动确认(返回 true) |
prompt() | 自动确认(返回空字符串) |
自定义弹窗处理
通过 page.on('dialog') 可以拦截并自定义处理弹窗。
实例
test('自定义处理弹窗', async ({ page }) => {
// 在触发弹窗之前注册监听器
page.on('dialog', async dialog => {
console.log('弹窗类型:', dialog.type());
console.log('弹窗消息:', dialog.message());
if (dialog.type() === 'confirm') {
// 取消确认框
await dialog.dismiss();
} else if (dialog.type() === 'prompt') {
// 输入自定义内容
await dialog.accept('RUNOOB 输入的内容');
} else {
// 其他类型直接确认
await dialog.accept();
}
});
// 触发弹窗的操作
await page.getByRole('button', { name: '删除' }).click();
});
// 在触发弹窗之前注册监听器
page.on('dialog', async dialog => {
console.log('弹窗类型:', dialog.type());
console.log('弹窗消息:', dialog.message());
if (dialog.type() === 'confirm') {
// 取消确认框
await dialog.dismiss();
} else if (dialog.type() === 'prompt') {
// 输入自定义内容
await dialog.accept('RUNOOB 输入的内容');
} else {
// 其他类型直接确认
await dialog.accept();
}
});
// 触发弹窗的操作
await page.getByRole('button', { name: '删除' }).click();
});
Dialog 对象方法
| 方法 | 说明 |
|---|---|
dialog.accept(promptText?) | 确认弹窗(prompt 时可传入输入文本) |
dialog.dismiss() | 取消弹窗 |
dialog.message() | 获取弹窗的提示消息 |
dialog.type() | 获取弹窗类型:'alert' | 'confirm' | 'prompt' | 'beforeunload' |
新窗口与新标签页
当点击链接或按钮打开新标签页时,Playwright 提供了多种方式来获取新页面。
page.waitForEvent('popup') 等待弹窗
实例
test('处理新标签页', async ({ page }) => {
// 在点击之前先准备等待新页面事件
const popupPromise = page.waitForEvent('popup');
// 点击打开新窗口的链接
await page.getByRole('link', { name: '新窗口打开' }).click();
// 获取新打开的页面
const popup = await popupPromise;
// 在新页面上操作
await expect(popup).toHaveTitle(/RUNOOB/);
await popup.getByRole('button', { name: '确定' }).click();
// 关闭新页面
await popup.close();
});
// 在点击之前先准备等待新页面事件
const popupPromise = page.waitForEvent('popup');
// 点击打开新窗口的链接
await page.getByRole('link', { name: '新窗口打开' }).click();
// 获取新打开的页面
const popup = await popupPromise;
// 在新页面上操作
await expect(popup).toHaveTitle(/RUNOOB/);
await popup.getByRole('button', { name: '确定' }).click();
// 关闭新页面
await popup.close();
});
context.on('page') 监听新页面
实例
test('监听 Context 中所有新页面', async ({ context, page }) => {
// 监听整个 Context 中的新页面创建
context.on('page', async newPage => {
console.log('新页面打开了:', newPage.url());
// 等待新页面加载完成
await newPage.waitForLoadState();
// 在新页面上操作
});
await page.goto('https://www.runoob.com/');
// 后续打开新窗口的操作会自动触发上述监听器
});
// 监听整个 Context 中的新页面创建
context.on('page', async newPage => {
console.log('新页面打开了:', newPage.url());
// 等待新页面加载完成
await newPage.waitForLoadState();
// 在新页面上操作
});
await page.goto('https://www.runoob.com/');
// 后续打开新窗口的操作会自动触发上述监听器
});
Playwright 事件系统
Playwright 的 Page 和 Context 对象都是事件发射器,你可以监听各种事件。
常用页面事件
| 事件 | 触发时机 |
|---|---|
request | 页面发起网络请求时 |
response | 收到网络响应时 |
dialog | 出现 alert/confirm/prompt 弹窗时 |
download | 开始下载文件时 |
popup | 新页面(弹窗/新标签页)打开时 |
console | 页面输出 console 消息时 |
pageerror | 页面出现未捕获的 JavaScript 错误时 |
load | 页面加载完成时 |
close | 页面关闭时 |
事件监听方法
实例
// 持续监听
page.on('request', request => {
console.log('请求:', request.method(), request.url());
});
// 单次监听(触发一次后自动移除)
page.once('dialog', dialog => {
dialog.accept();
});
// 移除监听
const handler = (request) => { /* ... */ };
page.on('request', handler);
page.off('request', handler);
page.on('request', request => {
console.log('请求:', request.method(), request.url());
});
// 单次监听(触发一次后自动移除)
page.once('dialog', dialog => {
dialog.accept();
});
// 移除监听
const handler = (request) => { /* ... */ };
page.on('request', handler);
page.off('request', handler);
