导航
Playwright 可以导航到 URL 并处理由页面交互引起的导航。本指南涵盖了等待页面导航和加载完成的常见场景。
导航生命周期
Playwright 将在页面中显示新文档的过程分为 导航 和 加载。
导航开始 于更改页面 URL 或与页面交互(例如,点击链接)。导航意图可能会被取消,例如,在点击未解析的 DNS 地址时,或转换为文件下载。
当响应头已被解析且会话历史记录已更新时,导航已提交。只有在导航成功(已提交)后,页面才开始 加载 文档。
加载 涵盖通过网络获取剩余的响应体、解析、执行脚本和触发加载事件:
- page.url() 设置为新的 url
- 文档内容通过网络加载并解析
- page.on('domcontentloaded') 事件被触发
- 页面执行一些脚本并加载样式表和图像等资源
- page.on('load') 事件被触发
- 页面执行动态加载的脚本
- 当 500 毫秒内没有新的网络请求时,触发
networkidle
由浏览器 UI 发起的场景
导航可以通过更改 URL 栏、重新加载页面或在会话历史记录中后退或前进引发。
自动等待
导航到 URL 会自动等待页面触发 load 事件。如果页面在 load 之前进行客户端重定向,page.goto(url[, options]) 将自动等待重定向页面触发 load 事件。
// 导航页面
await page.goto('https://example.com');
自定义等待
覆盖默认行为以等待特定事件,如 networkidle。
// 导航并等待直到网络空闲
await page.goto('https://example.com', { waitUntil: 'networkidle' });
等待元素
在延迟加载的页面中,使用 locator.waitFor([options]) 等待元素可见可能很有用。或者,像 page.click(selector[, options]) 这样的页面交互会自动等待元素。
// 导航并等待元素
await page.goto('https://example.com');
await page.getByText('Example Domain').waitFor();
// 导航并点击元素
// 点击会自动等待元素
await page.goto('https://example.com');
await page.getByText('Example Domain').click();
由页面交互发起的场景
在以下场景中,locator.click([options]) 启动导航,然后等待导航完成。
自动等待
默认情况下,locator.click([options]) 将等待导航步骤完成。这可以与导航页面上的页面交互结合使用,该交互将自动等待元素。
// 点击将自动等待导航完成
await page.getByText('Login').click();
// 填充将自动等待导航页面上的元素
await page.getByLabel('User Name').fill('John Doe');
自定义等待
locator.click 可以与 page.waitForLoadState([state, options]) 结合使用以等待加载事件。
await page.getByRole('button').click(); // 点击触发导航
await page.waitForLoadState('networkidle'); // 这将在 'networkidle' 后解析
等待元素
在延迟加载的页面中,使用 locator.waitFor([options]) 等待元素可见可能很有用。或者,像 locator.click([options]) 这样的页面交互会自动等待元素。
// 点击将自动等待元素并触发导航
await page.getByText('Login').click();
// 等待元素
await page.getByLabel('User Name').waitFor();
// 点击触发导航
await page.getByText('Login').click();
// 填充将自动等待元素
await page.getByLabel('User Name').fill('John Doe');
异步导航
点击元素可能会在启动导航之前触发异步处理。在这些情况下,建议显式调用 page.waitForNavigation([options])。例如:
- 导航由
setTimeout触发 - 页面在导航前等待网络请求
// 请注意,Promise.all 防止了点击和等待导航之间的竞争条件。
// 点击和等待导航之间的竞争条件。
await Promise.all([
// 等待下一次导航。
// 重要的是在点击之前调用 waitForNavigation 以设置等待。
page.waitForNavigation(),
// 超时后触发导航。
page.locator('div.delayed-navigation').click(),
]);
多次导航
点击元素可能会触发多次导航。在这些情况下,建议显式 page.waitForNavigation([options]) 到特定 url。例如:
load事件后发出的客户端重定向- 多次推送到历史状态
// 请注意,Promise.all 防止了点击和等待导航之间的竞争条件。
// 点击和等待导航之间的竞争条件。
await Promise.all([
// 重要的是在点击之前调用 waitForNavigation 以设置等待。
page.waitForNavigation({ url: '**/login' }),
// 使用脚本重定向触发导航。
page.getByText('Click me').click(),
]);
加载弹出窗口
当弹出窗口打开时,显式调用 page.waitForLoadState([state, options]) 可确保弹出窗口加载到所需状态。
// 请注意,Promise.all 防止了点击和等待弹出窗口之间的竞争条件。
// 点击和等待弹出窗口之间的竞争条件。
const [ popup ] = await Promise.all([
// 重要的是在点击之前调用 waitForEvent 以设置等待。
page.waitForEvent('popup'),
// 打开弹出窗口。
page.locator('a[target="_blank"]').click(),
]);
await popup.waitForLoadState('load');
高级模式
对于具有复杂加载模式的页面,page.waitForFunction(pageFunction[, arg, options]) 是定义自定义等待条件的强大且可扩展的方法。
await page.goto('http://example.com');
await page.waitForFunction(() => window.amILoadedYet());
// 根据页面本身,准备截图。
await page.screenshot();