Skip to main content

Chrome 扩展程序

介绍

¥Introduction

注意

扩展程序仅适用于通过持久上下文启动的 Chrome / Chromium。使用自定义浏览器参数需要你自担风险,因为其中一些参数可能会破坏 Playwright 功能。

¥Extensions only work in Chrome / Chromium launched with a persistent context. Use custom browser args at your own risk, as some of them may break Playwright functionality.

以下是获取源位于 ./my-extension清单 v2 扩展的 背景页 句柄的代码:

¥The following is code for getting a handle to the background page of a Manifest v2 extension whose source is located in ./my-extension:

const { chromium } = require('playwright');

(async () => {
const pathToExtension = require('path').join(__dirname, 'my-extension');
const userDataDir = '/tmp/test-user-data-dir';
const browserContext = await chromium.launchPersistentContext(userDataDir, {
headless: false,
args: [
`--disable-extensions-except=${pathToExtension}`,
`--load-extension=${pathToExtension}`
]
});
let [backgroundPage] = browserContext.backgroundPages();
if (!backgroundPage)
backgroundPage = await browserContext.waitForEvent('backgroundpage');

// Test the background page as you would any other page.
await browserContext.close();
})();

测试

¥Testing

要在运行测试时加载扩展,你可以使用测试装置来设置上下文。例如,你还可以动态检索扩展 ID 并使用它来加载和测试弹出页面。

¥To have the extension loaded when running tests you can use a test fixture to set the context. You can also dynamically retrieve the extension id and use it to load and test the popup page for example.

首先,添加将加载扩展的装置:

¥First, add fixtures that will load the extension:

fixtures.ts
import { test as base, chromium, type BrowserContext } from '@playwright/test';
import path from 'path';

export const test = base.extend<{
context: BrowserContext;
extensionId: string;
}>({
context: async ({ }, use) => {
const pathToExtension = path.join(__dirname, 'my-extension');
const context = await chromium.launchPersistentContext('', {
headless: false,
args: [
`--disable-extensions-except=${pathToExtension}`,
`--load-extension=${pathToExtension}`,
],
});
await use(context);
await context.close();
},
extensionId: async ({ context }, use) => {
/*
// for manifest v2:
let [background] = context.backgroundPages()
if (!background)
background = await context.waitForEvent('backgroundpage')
*/

// for manifest v3:
let [background] = context.serviceWorkers();
if (!background)
background = await context.waitForEvent('serviceworker');

const extensionId = background.url().split('/')[2];
await use(extensionId);
},
});
export const expect = test.expect;

然后在测试中使用这些装置:

¥Then use these fixtures in a test:

import { test, expect } from './fixtures';

test('example test', async ({ page }) => {
await page.goto('https://example.com');
await expect(page.locator('body')).toHaveText('Changed by my-extension');
});

test('popup page', async ({ page, extensionId }) => {
await page.goto(`chrome-extension://${extensionId}/popup.html`);
await expect(page.locator('body')).toHaveText('my-extension popup');
});

无头模式

¥Headless mode

危险

headless=new 模式不受 Playwright 官方支持,可能会导致意外行为。

¥headless=new mode is not officially supported by Playwright and might result in unexpected behavior.

默认情况下,Playwright 中 Chrome 的无头模式不支持 Chrome 扩展。为了克服这个限制,你可以使用以下代码以新的无头模式运行 Chrome 的持久上下文:

¥By default, Chrome's headless mode in Playwright does not support Chrome extensions. To overcome this limitation, you can run Chrome's persistent context with a new headless mode by using the following code:

fixtures.ts
// ...

const pathToExtension = path.join(__dirname, 'my-extension');
const context = await chromium.launchPersistentContext('', {
headless: false,
args: [
`--headless=new`,
`--disable-extensions-except=${pathToExtension}`,
`--load-extension=${pathToExtension}`,
],
});
// ...