diff --git a/bin/lib/handlers.js b/bin/lib/handlers.js index 6210335..54c5b38 100644 --- a/bin/lib/handlers.js +++ b/bin/lib/handlers.js @@ -381,6 +381,7 @@ class PageHandler extends BaseHandler { opener: () => this.getOpener(page, command), consoleMessages: () => this.consoleMessages(page, command), clearConsoleMessages: () => page.clearConsoleMessages(), + pageErrors: () => this.pageErrors(page, command), clearPageErrors: () => page.clearPageErrors(), content: async () => ({ content: await page.content() }), setContent: () => page.setContent(command.html, command.options), @@ -532,6 +533,18 @@ class PageHandler extends BaseHandler { return { messages: messages.map(message => this.serializeConsoleMessage(message)) }; } + async pageErrors(page, command) { + // An empty PHP options bag is [], so its .filter is Array#filter. + const filter = command.options?.filter; + const errors = await page.pageErrors(typeof filter === 'string' ? { filter } : {}); + // Error.message and Error.stack are not enumerable and would be lost in JSON. + return { errors: errors.map(error => ({ + name: error.name, + message: error.message, + stack: error.stack ?? null, + })) }; + } + async unrouteAll(page, pageId, options) { await page.unrouteAll(options || {}); RouteUtils.forgetRoutes(this.routes, pageId); diff --git a/docs/guide/advanced-recipes.md b/docs/guide/advanced-recipes.md index fe5684d..e0bde83 100644 --- a/docs/guide/advanced-recipes.md +++ b/docs/guide/advanced-recipes.md @@ -8,6 +8,7 @@ power of Playwright for PHP. * [File Uploads](#file-uploads) * [Network Interception](#network-interception) * [Handling Dialogs](#handling-dialogs) +* [Inspecting JavaScript Errors](#inspecting-javascript-errors) * [Working with Frames](#working-with-frames) * [Connecting to External Browsers](#connecting-to-external-browsers) * [Browser Configuration with `PlaywrightConfigBuilder`](#browser-configuration-with-playwrightconfigbuilder) @@ -80,6 +81,37 @@ $this->page->events()->onDialog(function ($dialog) { $this->page->locator('#delete-item-button')->click(); ``` +## Inspecting JavaScript Errors + +Use `pageErrors()` to read uncaught JavaScript errors recorded by the page, including errors raised before +you inspect them. Each `PageErrorInterface` exposes the JavaScript error's `name()`, `message()` and `stack()`. +The stack is `null` when unavailable. + +```php +use Playwright\Page\Options\PageErrorsOptions; + +// Include errors from earlier navigations in this page. +$errors = $this->page->pageErrors(new PageErrorsOptions(filter: 'all')); + +foreach ($errors as $error) { + echo $error->name().': '.$error->message().PHP_EOL; + if (null !== $error->stack()) { + echo $error->stack().PHP_EOL; + } +} + +$this->page->clearPageErrors(); +``` + +An array works too: `$this->page->pageErrors(['filter' => 'all'])`. Without options, the filter defaults to +`'since-navigation'`, returning errors since the last navigation. Playwright retains up to 200 recent errors +per page; reading them does not clear the history. `clearPageErrors()` clears the entire recorded history, +including errors from previous navigations. + +`pageErrors()` reads errors already recorded; it does not wait for a future error. After triggering an asynchronous +action, wait for the relevant application state before reading its errors. Messages logged with `console.error()` +belong to `consoleMessages()` instead. + ## Working with Frames If your page uses `