diff --git a/lib/PuppeteerSharp.Nunit/TestExpectations/TestExpectations.local.json b/lib/PuppeteerSharp.Nunit/TestExpectations/TestExpectations.local.json index 033172d5d..463dc3c5a 100644 --- a/lib/PuppeteerSharp.Nunit/TestExpectations/TestExpectations.local.json +++ b/lib/PuppeteerSharp.Nunit/TestExpectations/TestExpectations.local.json @@ -1020,21 +1020,6 @@ "FAIL" ] }, - { - "comment": "This is part of organizing the webdriver bidi implementation, We will remove it one by one", - "testIdPattern": "[page.spec] *Page.Events.PageError*", - "platforms": [ - "darwin", - "linux", - "win32" - ], - "parameters": [ - "webDriverBiDi" - ], - "expectations": [ - "FAIL" - ] - }, { "comment": "This is part of organizing the webdriver bidi implementation, We will remove it one by one", "testIdPattern": "[page.spec] *Page.Events.Popup*", diff --git a/lib/PuppeteerSharp.Tests/PageTests/PageEventsPageErrorTests.cs b/lib/PuppeteerSharp.Tests/PageTests/PageEventsPageErrorTests.cs index 47d235556..0115ffc70 100644 --- a/lib/PuppeteerSharp.Tests/PageTests/PageEventsPageErrorTests.cs +++ b/lib/PuppeteerSharp.Tests/PageTests/PageEventsPageErrorTests.cs @@ -6,27 +6,27 @@ namespace PuppeteerSharp.Tests.PageTests { public class PageEventsPageErrorTests : PuppeteerPageBaseTest { - public PageEventsPageErrorTests() : base() - { - } - [Test, PuppeteerTest("page.spec", "Page Page.Events.PageError", "should fire")] public async Task ShouldFire() { - string error = null; + var errorTask = new TaskCompletionSource(); void EventHandler(object sender, PageErrorEventArgs e) { - error = e.Message; + if (e.Message.Contains("Fancy")) + { + errorTask.TrySetResult(e.Message); + } Page.PageError -= EventHandler; } Page.PageError += EventHandler; await Task.WhenAll( - Page.GoToAsync(TestConstants.ServerUrl + "/error.html"), - WaitEvent(Page.Client, "Runtime.exceptionThrown") + errorTask.Task, + Page.GoToAsync(TestConstants.ServerUrl + "/error.html") ); + var error = await errorTask.Task; Assert.That(error, Does.Contain("Fancy")); } } diff --git a/lib/PuppeteerSharp/Bidi/BidiFrame.cs b/lib/PuppeteerSharp/Bidi/BidiFrame.cs index cd8b62180..a9f429492 100644 --- a/lib/PuppeteerSharp/Bidi/BidiFrame.cs +++ b/lib/PuppeteerSharp/Bidi/BidiFrame.cs @@ -579,6 +579,31 @@ private void Initialize() var dialog = BidiDialog.From(args.UserPrompt); ((Page)Page).OnDialog(new DialogEventArgs(dialog)); }; + + BrowsingContext.Log += (sender, args) => + { + if (args.Type == "javascript") + { + var text = args.Text ?? string.Empty; + var messageLines = new List { text }; + + var stackLines = new List(); + if (args.StackTrace != null) + { + foreach (var frame in args.StackTrace.CallFrames) + { + stackLines.Add($" at {(string.IsNullOrEmpty(frame.FunctionName) ? "" : frame.FunctionName)} ({frame.Url}:{frame.LineNumber + 1}:{frame.ColumnNumber + 1})"); + if (stackLines.Count >= 10) + { + break; + } + } + } + + var fullStack = string.Join("\n", messageLines.Concat(stackLines)); + BidiPage.OnPageError(new PageErrorEventArgs(fullStack)); + } + }; } private void CreateFrameTarget(BrowsingContext browsingContext) diff --git a/lib/PuppeteerSharp/Bidi/BidiPage.cs b/lib/PuppeteerSharp/Bidi/BidiPage.cs index a2459abb3..4cae0e262 100644 --- a/lib/PuppeteerSharp/Bidi/BidiPage.cs +++ b/lib/PuppeteerSharp/Bidi/BidiPage.cs @@ -461,6 +461,8 @@ internal static BidiPage From(BidiBrowserContext browserContext, BrowsingContext return page; } + internal new void OnPageError(PageErrorEventArgs e) => base.OnPageError(e); + /// protected override Task PdfInternalAsync(string file, PdfOptions options) => throw new NotImplementedException(); diff --git a/lib/PuppeteerSharp/Bidi/Core/BrowsingContext.cs b/lib/PuppeteerSharp/Bidi/Core/BrowsingContext.cs index aabe1c555..f1fd66ec0 100644 --- a/lib/PuppeteerSharp/Bidi/Core/BrowsingContext.cs +++ b/lib/PuppeteerSharp/Bidi/Core/BrowsingContext.cs @@ -65,6 +65,8 @@ private BrowsingContext(UserContext userContext, BrowsingContext parent, string public event EventHandler UserPrompt; + public event EventHandler Log; + public UserContext UserContext { get; } public string Id { get; } @@ -326,6 +328,16 @@ private void Initialize() var userPrompt = Core.UserPrompt.From(this, args); OnUserPromptOpened(new UserPromptEventArgs(userPrompt)); }; + + Session.LogEntryAdded += (_, args) => + { + if (args.Source.Context != Id) + { + return; + } + + OnLogEntry(args); + }; } private void OnNavigation(BrowserContextNavigationEventArgs args) => Navigation?.Invoke(this, args); @@ -352,4 +364,6 @@ private void Dispose(string reason) private void OnWorker(DedicatedWorkerRealm args) => Worker?.Invoke(this, new WorkerRealmEventArgs(args)); private void OnUserPromptOpened(UserPromptEventArgs args) => UserPrompt?.Invoke(this, args); + + private void OnLogEntry(WebDriverBiDi.Log.EntryAddedEventArgs args) => Log?.Invoke(this, args); } diff --git a/lib/PuppeteerSharp/Bidi/Core/Session.cs b/lib/PuppeteerSharp/Bidi/Core/Session.cs index d73c4e5f0..e9ea872fe 100644 --- a/lib/PuppeteerSharp/Bidi/Core/Session.cs +++ b/lib/PuppeteerSharp/Bidi/Core/Session.cs @@ -68,6 +68,8 @@ internal class Session(BiDiDriver driver, NewCommandResult info) : IDisposable public event EventHandler BrowsingContextUserPromptClosed; + public event EventHandler LogEntryAdded; + public BiDiDriver Driver { get; } = driver; public NewCommandResult Info { get; } = info; @@ -118,6 +120,7 @@ private async Task InitializeAsync() Driver.Network.OnResponseCompleted.AddObserver(OnNetworkResponseCompleted); Driver.BrowsingContext.OnUserPromptOpened.AddObserver(OnBrowsingContextUserPromptOpened); Driver.BrowsingContext.OnUserPromptClosed.AddObserver(OnBrowsingContextUserPromptClosed); + Driver.Log.OnEntryAdded.AddObserver(OnLogEntryAdded); } private void OnFragmentNavigated(WebDriverBiDi.BrowsingContext.NavigationEventArgs info) @@ -159,4 +162,6 @@ private void OnFragmentNavigated(WebDriverBiDi.BrowsingContext.NavigationEventAr private void OnBrowsingContextUserPromptOpened(WebDriverBiDi.BrowsingContext.UserPromptOpenedEventArgs obj) => BrowsingContextUserPromptOpened?.Invoke(this, obj); private void OnBrowsingContextUserPromptClosed(WebDriverBiDi.BrowsingContext.UserPromptClosedEventArgs obj) => BrowsingContextUserPromptClosed?.Invoke(this, obj); + + private void OnLogEntryAdded(WebDriverBiDi.Log.EntryAddedEventArgs obj) => LogEntryAdded?.Invoke(this, obj); }