WebView2
はじめに
以下では、Playwright を Microsoft Edge WebView2 と共に使用する方法について説明します。WebView2 は WinForms コントロールであり、内部的には Microsoft Edge を使用して Web コンテンツをレンダリングします。これは Microsoft Edge ブラウザの一部であり、Windows 10 および Windows 11 で利用可能です。Playwright は WebView2 アプリケーションを自動化するために使用でき、WebView2 内の Web コンテンツをテストするために使用できます。WebView2 に接続するために、Playwright は Chrome DevTools Protocol (CDP) を介して接続する BrowserType.connectOverCDP() を使用します。
概要
WebView2 コントロールに CDP 接続をリッスンさせるには、`--remote-debugging-port=9222` を指定した `WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS` 環境変数を設定するか、`--remote-debugging-port=9222` 引数を指定して EnsureCoreWebView2Async を呼び出すことで指示できます。これにより、Chrome DevTools Protocol が有効になった状態で WebView2 プロセスが開始され、Playwright による自動化が可能になります。9222 はこの場合のポートの例ですが、他の未使用のポートも同様に使用できます。
await this.webView.EnsureCoreWebView2Async(await CoreWebView2Environment.CreateAsync(null, null, new CoreWebView2EnvironmentOptions()
{
AdditionalBrowserArguments = "--remote-debugging-port=9222",
})).ConfigureAwait(false);
WebView2 コントロールを含むアプリケーションが実行されたら、Playwright 経由でそれに接続できます
Browser browser = playwright.chromium().connectOverCDP("http://localhost:9222");
BrowserContext context = browser.contexts().get(0);
Page page = context.pages().get(0);
WebView2 コントロールが準備完了であることを確認するために、CoreWebView2InitializationCompleted
イベントを待つことができます
this.webView.CoreWebView2InitializationCompleted += (_, e) =>
{
if (e.IsSuccess)
{
Console.WriteLine("WebView2 initialized");
}
};
テストの作成と実行
デフォルトでは、WebView2 コントロールはすべてのインスタンスに対して同じユーザーデータディレクトリを使用します。これは、複数のテストを並行して実行すると、それらが互いに干渉し合うことを意味します。これを避けるために、`WEBVIEW2_USER_DATA_FOLDER` 環境変数を設定するか (または WebView2.EnsureCoreWebView2Async Method を使用して)、各テストに異なるフォルダーを指定する必要があります。これにより、各テストが独自のユーザーデータディレクトリで実行されるようになります。
以下を使用すると、Playwright は WebView2 アプリケーションをサブプロセスとして実行し、一意のユーザーデータディレクトリを割り当て、テストに Page インスタンスを提供します
package com.example;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
public class WebView2Process {
public int cdpPort;
private Path _dataDir;
private Process _process;
private Path _executablePath = Path.of("../webview2-app/bin/Debug/net8.0-windows/webview2.exe");
public WebView2Process() throws IOException {
cdpPort = nextFreePort();
_dataDir = Files.createTempDirectory("pw-java-webview2-tests-");
if (!Files.exists(_executablePath)) {
throw new RuntimeException("Executable not found: " + _executablePath);
}
ProcessBuilder pb = new ProcessBuilder().command(_executablePath.toAbsolutePath().toString());
Map<String, String> envMap = pb.environment();
envMap.put("WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS", "--remote-debugging-port=" + cdpPort);
envMap.put("WEBVIEW2_USER_DATA_FOLDER", _dataDir.toString());
_process = pb.start();
// wait until "WebView2 initialized" got printed
BufferedReader reader = new BufferedReader(new InputStreamReader(_process.getInputStream()));
while (true) {
String line = reader.readLine();
if (line == null) {
throw new RuntimeException("WebView2 process exited");
}
if (line.contains("WebView2 initialized")) {
break;
}
}
}
private static final AtomicInteger nextUnusedPort = new AtomicInteger(9000);
private static boolean available(int port) {
try (ServerSocket ignored = new ServerSocket(port)) {
return true;
} catch (IOException ignored) {
return false;
}
}
static int nextFreePort() {
for (int i = 0; i < 100; i++) {
int port = nextUnusedPort.getAndIncrement();
if (available(port)) {
return port;
}
}
throw new RuntimeException("Cannot find free port: " + nextUnusedPort.get());
}
public void dispose() {
_process.destroy();
try {
_process.waitFor();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
package com.example;
import com.microsoft.playwright.Browser;
import com.microsoft.playwright.BrowserContext;
import com.microsoft.playwright.Locator;
import com.microsoft.playwright.Page;
import com.microsoft.playwright.Playwright;
import org.junit.jupiter.api.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;
import java.io.IOException;
public class TestExample {
// Shared between all tests in this class.
static WebView2Process webview2Process;
static Playwright playwright;
static Browser browser;
static BrowserContext context;
static Page page;
@BeforeAll
static void launchBrowser() throws IOException {
playwright = Playwright.create();
webview2Process = new WebView2Process();
browser = playwright.chromium().connectOverCDP("http://127.0.0.1:" + webview2Process.cdpPort);
context = browser.contexts().get(0);
page = context.pages().get(0);
}
@AfterAll
static void closeBrowser() {
webview2Process.dispose();
}
@Test
public void shouldClickButton() {
page.navigate("https://playwright.dokyumento.jp");
Locator gettingStarted = page.getByText("Get started");
assertThat(gettingStarted).isVisible();
}
}
デバッグ
webview2 コントロール内で、右クリックしてコンテキストメニューを開き、「Inspect (検査)」を選択して DevTools を開くか、F12 キーを押すことができます。また、WebView2.CoreWebView2.OpenDevToolsWindow メソッドを使用して、プログラムで DevTools を開くこともできます。
テストのデバッグについては、Playwright の デバッグガイドを参照してください。