For those interested I've just released WebView2.DevTools.Dom to NuGet.org. It's free for anyone to use.
More details and examples in the Readme.
You can expose a function to your JavaScript application to call.
await webView.EnsureCoreWebView2Async();
webView.CoreWebView2.DOMContentLoaded += async (s, e) =>
{
                var devToolsContext = await webView.CoreWebView2.CreateDevToolsContextAsync();
                await devToolsContext.ExposeFunctionAsync("jsAlertButtonClick", () =>
                {
                    _ = devToolsContext.EvaluateExpressionAsync("window.alert('Hello! You invoked window.alert()');");
                });
                await devToolsContext.ExposeFunctionAsync("csAlertButtonClick", () =>
                {
                    Dispatcher.InvokeAsync(() =>
                    {
                        WindowState = WindowState switch
                        {
                            WindowState.Maximized => WindowState.Normal,
                            WindowState.Normal => WindowState.Maximized,
                            _ => WindowState.Minimized,
                        };
                    });
                });
                var meaningOfLifeAsInt = await devToolsContext.EvaluateFunctionAsync<int>("() => Promise.resolve(42)");
                var jsAlertButton = await devToolsContext.QuerySelectorAsync("#jsAlertButton");
                var csAlertButton = await devToolsContext.QuerySelectorAsync("#csAlertButton");
                _ = jsAlertButton.AddEventListenerAsync("click", "jsAlertButtonClick");
                _ = csAlertButton.AddEventListenerAsync("click", "csAlertButtonClick");
                var innerText = await jsAlertButton.GetPropertyValueAsync<string>("innerText");
                var currentTimeSpan = await devToolsContext.QuerySelectorAsync("#current-time");
                var fpsSpan = await devToolsContext.QuerySelectorAsync("#fps");
                await devToolsContext.ExposeFunctionAsync<double, bool>("requestAnimationFrameCallback", (highResTime) =>
                {
                    var duration = NodaTime.Duration.FromNanoseconds(Math.Round(highResTime * 1000) * 1000);
                    callback(duration);
                    return false;
                });
                callback(NodaTime.Duration.Zero);
                void callback(NodaTime.Duration timestamp)
                {
                    _ = currentTimeSpan.SetInnerText(GetCurrentDateTime());
                    _ = fpsSpan.SetInnerText(CalculateFps(timestamp).ToString());
                    _ = devToolsContext.EvaluateExpressionAsync(@"window.requestAnimationFrame((x) => { window.requestAnimationFrameCallback(x)});");
                }
};
Functions persist across navigations so you only need to register a function once.
There's a working example available at https://github.com/ChromiumDotNet/WebView2.DevTools.Dom/blob/main/WebView2.DevTools.Dom.Wpf.Example/MainWindow.xaml.cs#L22