使用Light-Playwright做性能测试遇执行上下文销毁错误,如何获取新页面?
解决Playwright+Lighthouse性能测试中导航导致的执行上下文销毁问题
问题描述
在使用Playwright结合Lighthouse做性能测试时,点击"Find Hotels"按钮触发页面导航后,调用audit方法时报错:
page.evaluate: Execution context was destroyed, most likely because of a navigation
原测试代码如下:
import { expect, test } from '@playwright/test'; import playwright from 'playwright'; import { audit } from '../utils/audit'; test.describe('Top 20 sites', () => { test(`Ligthouse User Journey performance test`, async () => { test.slow(); const browser = await playwright['chromium'].launch({ args: ['--remote-debugging-port=9222'], }); const page = await browser.newPage(); await page.goto('https://www.google.com'); await page.getByRole('button', { name: 'Find Hotels' }).click(); // const context = await browser.newContext(); // Create a new page in a pristine context. const results = await audit(page, 'userFlow') await page.close(); await browser.close(); // expect(results.lhr.categories.performance.score, `${'https://www.marriott.com/default.mi'} fell below the minimum threshold`).toBeGreaterThanOrEqual(.30); }); });
审计方法代码:
export const audit = async (page: Page, reportDir: string) => playAudit({ page: page, config: lighthouseDesktopConfig, thresholds: thresholds, port: 9222, reports: { formats: { html: true, //defaults to false }, name: `ligthouse-${new Date().toISOString()}`, //defaults to `lighthouse-${new Date().getTime()}` directory: `${process.cwd()}/lighthouse/${reportDir}`, //defaults to `${process.cwd()}/lighthouse` }, });
问题原因
点击按钮触发页面导航后,原page对象对应的执行上下文被销毁,此时直接用旧的page实例调用Lighthouse审计,就会触发执行上下文已销毁的错误。
解决方案
场景1:点击后在当前页面导航
如果点击按钮后是在当前页面跳转(未打开新标签),需要同时执行点击操作和等待导航完成,确保页面执行上下文稳定后再启动审计:
修改测试代码中的点击逻辑:
// 同时执行点击和等待导航完成,可按需调整waitUntil参数 await Promise.all([ page.waitForNavigation({ waitUntil: 'networkidle' }), page.getByRole('button', { name: 'Find Hotels' }).click() ]);
场景2:点击后打开新页面/新标签
如果点击按钮后打开了新标签页,需要捕获新创建的页面实例,用新页面执行审计:
// 等待新页面创建,同时执行点击操作 const [newPage] = await Promise.all([ browser.waitForEvent('page'), page.getByRole('button', { name: 'Find Hotels' }).click() ]); // 等待新页面加载完成 await newPage.waitForLoadState('networkidle'); // 使用新页面执行审计 const results = await audit(newPage, 'userFlow'); // 记得关闭新页面 await newPage.close();
完整修改后的测试代码(当前页面导航场景)
import { expect, test } from '@playwright/test'; import playwright from 'playwright'; import { audit } from '../utils/audit'; test.describe('Top 20 sites', () => { test(`Lighthouse User Journey performance test`, async () => { test.slow(); const browser = await playwright['chromium'].launch({ args: ['--remote-debugging-port=9222'], }); const page = await browser.newPage(); await page.goto('https://www.google.com'); // 同步执行点击与导航等待 await Promise.all([ page.waitForNavigation({ waitUntil: 'networkidle' }), page.getByRole('button', { name: 'Find Hotels' }).click() ]); // 执行性能审计 const results = await audit(page, 'userFlow'); await page.close(); await browser.close(); // expect(results.lhr.categories.performance.score, `${'https://www.marriott.com/default.mi'} fell below the minimum threshold`).toBeGreaterThanOrEqual(.30); }); });
注意事项
waitForNavigation的waitUntil参数可按需调整:'load':等待页面所有资源加载完成'domcontentloaded':等待DOM加载完成'networkidle':等待网络空闲(500ms内没有请求)
- 如果使用Playwright Test的默认上下文管理,可省略手动
launch browser的步骤,通过test.use配置远程调试端口,代码会更简洁。
内容的提问来源于stack exchange,提问作者D.Hodges
相关产品推荐
相关产品推荐

