You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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');
  }
}

问题原因与解决方法

核心原因

  1. 未等待异步方法执行:测试用例中调用searchPage.search()时未加await,导致Playwright在异步操作完成前结束测试,页面上下文被提前销毁。
  2. 异步方法同步调用:this.browserPage.title()是异步方法,直接同步调用会引发上下文状态异常。
  3. 全局变量生命周期混乱:全局变量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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 04:24:12