Debugging a WebView2 component using Playwright in .NET

  • Gérald Barré

To write end-to-end tests of an application hosting a WebView2 component, you may want to use Playwright. Playwright allows to control the browser and to interact with the DOM. This is a well-known tool to test web applications.

To attach Playwright to a WebView2 component, you need to use the Chromium DevTools protocol. When initializing the WebView2, you can use the --remote-debugging-port option to specify the port on which the DevTools protocol is listening. You can set this option manually when initializing the WebView2, or you can use the environment variable WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS to specify additional arguments to pass to the browser automatically.

First, you need to add a reference to the Microsoft.Playwright NuGet package:

Shell
dotnet add package Microsoft.Playwright

Then, you can use the following code to start the application and attach Playwright to the WebView2 components:

C#
// Start the external application with WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS which allows
// to specify the port to use for the protocol.
//
// note: If the component is in the current process, you can use the following code before instantiating the WebView2:
// Environment.SetEnvironmentVariable("WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS", "--remote-debugging-port=" + Port);
const int Port = 9334;
var psi = new ProcessStartInfo
{
    FileName = @"ApplicationContainingWebViews.exe",
    Environment =
    {
        // If you start multiple instances of your application, you may need to use a different port for each instance
        { "WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS", "--remote-debugging-port=" + Port },

        // If you start multiple instances of your application, you may need to use different
        // data folder for each instance to avoid sharing state
        // https://learn.microsoft.com/en-us/microsoft-edge/webview2/concepts/user-data-folder?tabs=win32&WT.mc_id=DT-MVP-5003978
        // { "WEBVIEW2_USER_DATA_FOLDER", Path.Combine(Path.GetTempPath(), "WebView2") },
    },
};
var process = Process.Start(psi);

using var httpClient = new HttpClient();

// Wait for the WebView2 to be initialized and get the protocol URL
string? url = null;
while (url == null)
{
    try
    {
        var version = await httpClient.GetFromJsonAsync<JsonElement>($"http://localhost:{Port}/json/version/");
        url = version.GetProperty("webSocketDebuggerUrl").GetString();
    }
    catch
    {
        await Task.Delay(100);
    }
}

// Initialize playwright using the protocol url
using var playwright = await Microsoft.Playwright.Playwright.CreateAsync();
await using var browser = await playwright.Chromium.ConnectOverCDPAsync(url);

// If you have multiple webviews, you can iterate on Pages to find the right one
var page = browser.Contexts[0].Pages[0];

// Interact with the page
await page.GotoAsync("https://www.meziantou.net");

var element = await page.QuerySelectorAsync("aside h3");
Assert.Equal("Gérald Barré", await element.TextContentAsync());

Do you have a question or a suggestion about this post? Contact me!

Follow me:
Enjoy this blog?Buy Me A Coffee💖 Sponsor on GitHub