WebView2

简介

以下将解释如何在 Playwright 中使用 Microsoft Edge WebView2。WebView2 是一个 WinForms 控件,它在后台使用 Microsoft Edge 来渲染 Web 内容。它是 Microsoft Edge 浏览器的一部分,适用于 Windows 10 和 Windows 11。Playwright 可用于自动化 WebView2 应用程序,并可用于测试 WebView2 中的 Web 内容。为了连接到 WebView2,Playwright 使用 browserType.connectOverCDP(),它通过 Chrome DevTools 协议 (CDP) 进行连接。

概述

WebView2 控件可以通过设置 WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS 环境变量为 --remote-debugging-port=9222 或调用 EnsureCoreWebView2Async 并传入 --remote-debugging-port=9222 参数来监听传入的 CDP 连接。这将启动带有启用 Chrome DevTools 协议的 WebView2 进程,从而允许 Playwright 进行自动化。9222 是示例端口,也可以使用其他未使用的端口。

await this.webView.EnsureCoreWebView2Async(await CoreWebView2Environment.CreateAsync(null, null, new CoreWebView2EnvironmentOptions()
{
  AdditionalBrowserArguments = "--remote-debugging-port=9222",
})).ConfigureAwait(false);

一旦您的应用程序与 WebView2 控件正在运行,您可以通过 Playwright 连接到它:

const browser = await playwright.chromium.connectOverCDP('http://localhost:9222');
const context = browser.contexts()[0];
const page = context.pages()[0];

为了确保 WebView2 控件已经准备好,您可以等待 CoreWebView2InitializationCompleted 事件:

this.webView.CoreWebView2InitializationCompleted += (_, e) =>
{
    if (e.IsSuccess)
    {
        Console.WriteLine("WebView2 initialized");
    }
};

编写和运行测试

默认情况下,WebView2 控件会使用相同的用户数据目录,这意味着如果您并行运行多个测试,它们可能会相互干扰。为了避免这种情况,您应该设置 WEBVIEW2_USER_DATA_FOLDER 环境变量(或使用 WebView2.EnsureCoreWebView2Async 方法)为每个测试指定不同的文件夹。这样可以确保每个测试运行在其独立的用户数据目录中。

使用以下代码,Playwright 将作为子进程运行您的 WebView2 应用程序,为其分配唯一的用户数据目录,并为您的测试提供 Page 实例:

webView2Test.ts
import { test as base } from '@playwright/test';
import fs from 'fs';
import os from 'os';
import path from 'path';
import childProcess from 'child_process';

const EXECUTABLE_PATH = path.join(
    __dirname,
    '../../webview2-app/bin/Debug/net8.0-windows/webview2.exe',
);

export const test = base.extend({
  browser: async ({ playwright }, use, testInfo) => {
    const cdpPort = 10000 + testInfo.workerIndex;
    // Make sure that the executable exists and is executable
    fs.accessSync(EXECUTABLE_PATH, fs.constants.X_OK);
    const userDataDir = path.join(
        fs.realpathSync.native(os.tmpdir()),
        `playwright-webview2-tests/user-data-dir-${testInfo.workerIndex}`,
    );
    const webView2Process = childProcess.spawn(EXECUTABLE_PATH, [], {
      shell: true,
      env: {
        ...process.env,
        WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS: `--remote-debugging-port=${cdpPort}`,
        WEBVIEW2_USER_DATA_FOLDER: userDataDir,
      }
    });
    await new Promise<void>(resolve => webView2Process.stdout.on('data', data => {
      if (data.toString().includes('WebView2 initialized'))
        resolve();
    }));
    const browser = await playwright.chromium.connectOverCDP(`http://127.0.0.1:${cdpPort}`);
    await use(browser);
    await browser.close();
    childProcess.execSync(`taskkill /pid ${webView2Process.pid} /T /F`);
    fs.rmdirSync(userDataDir, { recursive: true });
  },
  context: async ({ browser }, use) => {
    const context = browser.contexts()[0];
    await use(context);
  },
  page: async ({ context }, use) => {
    const page = context.pages()[0];
    await use(page);
  },
});

export { expect } from '@playwright/test';
example.spec.ts
import { test, expect } from './webView2Test';

test('test WebView2', async ({ page }) => {
  await page.goto('https://playwright.dev');
  const getStarted = page.getByText('Get Started');
  await expect(getStarted).toBeVisible();
});

调试

在 WebView2 控件内,您可以右键单击打开上下文菜单并选择 "Inspect" 来打开 DevTools,或者按 F12 键。您也可以使用 WebView2.CoreWebView2.OpenDevToolsWindow 方法来程序化地打开 DevTools。

关于调试测试的更多内容,请参阅 Playwright 调试指南。