Playwright页面引用未初始化至页面构造器问题求助
Playwright测试Chrome扩展时出现“目标已关闭”错误排查
问题背景
从Java技术栈转TypeScript,使用Playwright进行Chrome扩展测试时遇到报错,核心需求是启动Chrome扩展后台页面并完成测试。
实现方式
- 所有页面(登录页、管理页)采用页面对象模型(POM)
- 调用带有Chrome扩展URL的持久化上下文浏览器,将Page引用传递给各页面构造器
- 在测试中使用Page实例调用对应页面操作
错误详情
能正常启动持久化上下文浏览器并导航至Chrome扩展URL,但将Page引用传递给目标页面后执行操作时,抛出“目标已关闭”错误,控制台显示“Action was interrupted”,错误出现在SearchPage类的search方法中(代码行:console.log(this.browserPage.title());)。
注:本文以谷歌搜索为例演示,实际业务场景逻辑一致。
测试文件:chromeextensionstest.spec.ts
import { BrowserContext, chromium, expect, Page, test } from "@playwright/test"; import path from "path"; import { SearchPage } from "../pages/admin/search.spec"; var browserContext: BrowserContext; var browserPage: Page; var basePath = require("path").resolve(__dirname, ".."); test.describe("test", async () => { test.beforeAll(async ({ browser }) => { browserContext = await chromium.launchPersistentContext("", { headless: false, channel: "chrome", acceptDownloads: true, recordVideo: { dir: "videos", size: { width: 640, height: 480 }, }, slowMo: 500, strictSelectors: false, //args: [ // `--disable-extensions-except=${extensionDir},${widgetDir}`, // `--load-extension=${extensionDir},${widgetDir}`, //], }); browserContext.grantPermissions([ "notifications", "clipboard-read", "clipboard-write", ]); browserPage = await browserContext.newPage(); }); test("Navigate to Google", async () => { let extensionUrl = 'https://google.com'; await browserPage.goto(extensionUrl); let searchPage = new SearchPage(browserPage); searchPage.search(); }); });
Search POM文件:search.spec.ts
// @ts-check import { expect, Page } from "@playwright/test"; export class SearchPage { browserPage: Page; constructor(page: Page) { this.browserPage = page; } public async search(): Promise<void> { console.log(this.browserPage.title()); await this.browserPage.type('input[name="q"]', "Playwright") await this.browserPage.keyboard.press('Enter'); let text = await this.browserPage.innerText('//h3[contains(text(),"Playwright:")]') expect(text).toContain('Playwright: Fast and reliable'); } }
问题原因与解决方法
核心原因
- 未等待异步方法执行:测试用例中调用
searchPage.search()时未加await,导致Playwright在异步操作完成前结束测试,页面上下文被提前销毁。 - 异步方法同步调用:
this.browserPage.title()是异步方法,直接同步调用会引发上下文状态异常。 - 全局变量生命周期混乱:全局变量
browserContext和browserPage未被正确清理,可能导致资源泄漏或上下文提前释放。
修复步骤
1. 等待异步方法执行
在测试用例中给search()添加await:
test("Navigate to Google", async () => { let extensionUrl = 'https://google.com'; await browserPage.goto(extensionUrl); let searchPage = new SearchPage(browserPage); await searchPage.search(); // 添加await等待异步操作完成 });
2. 修复异步方法同步调用问题
修改search方法中title()的调用:
public async search(): Promise<void> { const title = await this.browserPage.title(); // 添加await console.log(title); await this.browserPage.type('input[name="q"]', "Playwright") await this.browserPage.keyboard.press('Enter'); let text = await this.browserPage.innerText('//h3[contains(text(),"Playwright:")]') expect(text).toContain('Playwright: Fast and reliable'); }
3. 优化上下文生命周期管理
避免全局变量,添加afterAll手动清理资源:
test.describe("test", () => { // 移除不必要的async let browserContext: BrowserContext; let browserPage: Page; test.beforeAll(async () => { browserContext = await chromium.launchPersistentContext("", { headless: false, channel: "chrome", acceptDownloads: true, recordVideo: { dir: "videos", size: { width: 640, height: 480 }, }, slowMo: 500, strictSelectors: false, // args: [ // `--disable-extensions-except=${extensionDir},${widgetDir}`, // `--load-extension=${extensionDir},${widgetDir}`, // ], }); await browserContext.grantPermissions([ "notifications", "clipboard-read", "clipboard-write", ]); browserPage = await browserContext.newPage(); }); test.afterAll(async () => { await browserPage.close(); await browserContext.close(); // 手动清理上下文,避免资源泄漏 }); test("Navigate to Google", async () => { let extensionUrl = 'https://google.com'; await browserPage.goto(extensionUrl); let searchPage = new SearchPage(browserPage); await searchPage.search(); }); });
内容的提问来源于stack exchange,提问作者ramkumar-yoganathan
相关产品推荐
相关产品推荐

