From 19a6fdb3897b510c32f55207dad509c03e816a7f Mon Sep 17 00:00:00 2001 From: Bill Ruddock Date: Sun, 12 Oct 2025 23:41:31 +0100 Subject: [PATCH 1/3] Add assertNoConsoleMessages() Check page for console messages at specified levels: 'debug': console.debug() calls (not checked by default) 'error': console.error() calls 'info': console.info() calls 'warning': console.warn() calls (can also specify level as 'warn') --- src/Api/Concerns/MakesConsoleAssertions.php | 23 ++++ src/Playwright/InitScript.php | 16 ++- src/Playwright/Page.php | 30 +++++ .../Webpage/AssertNoConsoleMessagesTest.php | 107 ++++++++++++++++++ 4 files changed, 175 insertions(+), 1 deletion(-) create mode 100644 tests/Browser/Webpage/AssertNoConsoleMessagesTest.php diff --git a/src/Api/Concerns/MakesConsoleAssertions.php b/src/Api/Concerns/MakesConsoleAssertions.php index 0ac7a8f2..0cdd4d17 100644 --- a/src/Api/Concerns/MakesConsoleAssertions.php +++ b/src/Api/Concerns/MakesConsoleAssertions.php @@ -72,6 +72,29 @@ public function assertNoConsoleLogs(): Webpage return $this; } + /** + * Asserts there are no console messages at given levels on the page. + * + * @param array|string $levels Console message level(s) to check for (debug, info, error, warning). + */ + public function assertNoConsoleMessages(array|string $levels = ['info', 'error', 'warning']): Webpage + { + if (is_string($levels)) { + $levels = [$levels]; + } + $messages = $this->page->consoleMessages($levels); + + expect($messages)->toBeEmpty(sprintf( + 'Expected no console messages at levels [%s] on the page initially with the url [%s], but found %d: %s', + implode(', ', $levels), + $this->initialUrl, + count($messages), + implode(', ', array_map(fn (array $log) => "{$log['level']}: {$log['message']}", $messages)), + )); + + return $this; + } + /** * Asserts there are no JavaScript errors on the page. */ diff --git a/src/Playwright/InitScript.php b/src/Playwright/InitScript.php index c9d0221d..eaec4d7e 100644 --- a/src/Playwright/InitScript.php +++ b/src/Playwright/InitScript.php @@ -23,7 +23,8 @@ public static function get(): string window.__pestBrowser = { jsErrors: [], - consoleLogs: [] + consoleLogs: [], + consoleMessages: [] }; const originalConsoleLog = console.log; @@ -35,6 +36,19 @@ public static function get(): string originalConsoleLog.apply(console, args); }; + ['debug', 'error', 'info', 'warning'].forEach(function (level) { + const methodName = level === 'warning' ? 'warn' : level; + const originalConsoleMethod = console[methodName]; + console[methodName] = function(...args) { + window.__pestBrowser.consoleMessages.push({ + timestamp: new Date().getTime(), + level: level, + message: args.map(arg => String(arg)).join(' ') + }); + originalConsoleMethod.apply(console, args); + }; + }); + window.addEventListener('error', (e) => { window.__pestBrowser.jsErrors.push({ message: e.message, diff --git a/src/Playwright/Page.php b/src/Playwright/Page.php index d97f3db3..a4a46fbe 100644 --- a/src/Playwright/Page.php +++ b/src/Playwright/Page.php @@ -463,6 +463,36 @@ public function consoleLogs(): array return $consoleLogs; } + /** + * Get the console messages at given levels from the page, if any. + * + * @param array|string $levels Message levels to filter for ('debug', 'info', 'error', 'warning') + * + * @return array + */ + public function consoleMessages(array|string $levels = ['info', 'error', 'warning']): array + { + $consoleMessages = $this->evaluate('window.__pestBrowser.consoleMessages || []'); + + /** @var array $consoleMessages */ + + if (is_string($levels)) { + $checkLevels = [$levels => true]; + } else { + $checkLevels = array_flip($levels); + if (array_key_exists('warn', $checkLevels)) { + $checkLevels['warning'] = true; + } + } + + $messages = array_filter( + $consoleMessages, + fn (array $log) => array_key_exists($log['level'], $checkLevels) + ); + + return $messages; + } + /** * Get the broken images from the page, if any. * diff --git a/tests/Browser/Webpage/AssertNoConsoleMessagesTest.php b/tests/Browser/Webpage/AssertNoConsoleMessagesTest.php new file mode 100644 index 00000000..719960fe --- /dev/null +++ b/tests/Browser/Webpage/AssertNoConsoleMessagesTest.php @@ -0,0 +1,107 @@ + ' +
+ '); + + $page = visit('/'); + + $page->assertNoConsoleMessages(); +}); + +it('ignores debug messages by default', function (): void { + Route::get('/', fn (): string => ' + +
+ '); + + $page = visit('/'); + + $page->assertNoConsoleMessages(); +}); + +it('asserts that there are console messages', function (): void { + Route::get('/', fn (): string => ' + +
+ '); + + $page = visit('/'); + + $page->assertNoConsoleMessages(); +})->throws(ExpectationFailedException::class, 'but found 1: error: Hello, World!'); + +it('asserts that there are console debug messages', function (): void { + Route::get('/', fn (): string => ' + +
+ '); + + $page = visit('/'); + + $page->assertNoConsoleMessages('debug'); +})->throws(ExpectationFailedException::class, 'but found 1: debug: Hello, World!'); + +it('asserts that there are console error messages', function (): void { + Route::get('/', fn (): string => ' + +
+ '); + + $page = visit('/'); + + $page->assertNoConsoleMessages('error'); +})->throws(ExpectationFailedException::class, 'but found 1: error: Hello, World!'); + +it('asserts that there are console info messages', function (): void { + Route::get('/', fn (): string => ' + +
+ '); + + $page = visit('/'); + + $page->assertNoConsoleMessages('info'); +})->throws(ExpectationFailedException::class, 'but found 1: info: Hello, World!'); + +it('asserts that there are console warning messages', function (): void { + Route::get('/', fn (): string => ' + +
+ '); + + $page = visit('/'); + + $page->assertNoConsoleMessages('warning'); +})->throws(ExpectationFailedException::class, 'but found 1: warning: Hello, World!'); + +it('allows alias warn for console warning messages', function (): void { + Route::get('/', fn (): string => ' + +
+ '); + + $page = visit('/'); + + $page->assertNoConsoleMessages('warn'); +})->throws(ExpectationFailedException::class, 'but found 1: warning: Hello, World!'); From 5c023daf39411b9686cfe06a08fe6460dd4f8196 Mon Sep 17 00:00:00 2001 From: Bill Ruddock Date: Mon, 13 Oct 2025 00:22:00 +0100 Subject: [PATCH 2/3] lint fixes: console message assertions --- src/Api/Concerns/MakesConsoleAssertions.php | 4 ++-- src/Playwright/Page.php | 10 +++------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/Api/Concerns/MakesConsoleAssertions.php b/src/Api/Concerns/MakesConsoleAssertions.php index 0cdd4d17..63fdf8a4 100644 --- a/src/Api/Concerns/MakesConsoleAssertions.php +++ b/src/Api/Concerns/MakesConsoleAssertions.php @@ -75,7 +75,7 @@ public function assertNoConsoleLogs(): Webpage /** * Asserts there are no console messages at given levels on the page. * - * @param array|string $levels Console message level(s) to check for (debug, info, error, warning). + * @param array|string $levels Console message level(s) to check for (debug, info, error, warning). */ public function assertNoConsoleMessages(array|string $levels = ['info', 'error', 'warning']): Webpage { @@ -89,7 +89,7 @@ public function assertNoConsoleMessages(array|string $levels = ['info', 'error', implode(', ', $levels), $this->initialUrl, count($messages), - implode(', ', array_map(fn (array $log) => "{$log['level']}: {$log['message']}", $messages)), + implode(', ', array_map(fn (array $log): string => "{$log['level']}: {$log['message']}", $messages)), )); return $this; diff --git a/src/Playwright/Page.php b/src/Playwright/Page.php index a4a46fbe..06604569 100644 --- a/src/Playwright/Page.php +++ b/src/Playwright/Page.php @@ -466,8 +466,7 @@ public function consoleLogs(): array /** * Get the console messages at given levels from the page, if any. * - * @param array|string $levels Message levels to filter for ('debug', 'info', 'error', 'warning') - * + * @param array|string $levels Message levels to filter for ('debug', 'info', 'error', 'warning') * @return array */ public function consoleMessages(array|string $levels = ['info', 'error', 'warning']): array @@ -475,7 +474,6 @@ public function consoleMessages(array|string $levels = ['info', 'error', 'warnin $consoleMessages = $this->evaluate('window.__pestBrowser.consoleMessages || []'); /** @var array $consoleMessages */ - if (is_string($levels)) { $checkLevels = [$levels => true]; } else { @@ -485,12 +483,10 @@ public function consoleMessages(array|string $levels = ['info', 'error', 'warnin } } - $messages = array_filter( + return array_filter( $consoleMessages, - fn (array $log) => array_key_exists($log['level'], $checkLevels) + fn (array $log): bool => array_key_exists($log['level'], $checkLevels) ); - - return $messages; } /** From e045e393645b732e704b318a1e9383f01d9a2f09 Mon Sep 17 00:00:00 2001 From: Bill Ruddock Date: Fri, 17 Oct 2025 04:46:24 +0100 Subject: [PATCH 3/3] Output console messages (at default levels) on expectation failed --- src/Exceptions/BrowserExpectationFailedException.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/Exceptions/BrowserExpectationFailedException.php b/src/Exceptions/BrowserExpectationFailedException.php index 8fff0be3..d10ec507 100644 --- a/src/Exceptions/BrowserExpectationFailedException.php +++ b/src/Exceptions/BrowserExpectationFailedException.php @@ -39,6 +39,15 @@ public static function from(Page $page, ExpectationFailedException $e): Expectat )); } + $consoleMessages = $page->consoleMessages(); + + if (count($consoleMessages) > 0) { + $message .= "\n\nThe following console messages were found:\n".implode("\n", array_map( + fn (array $error): string => $error['level'] . ': ' . $error['message'], + $consoleMessages, + )); + } + $javaScriptErrors = $page->javaScriptErrors(); if (count($javaScriptErrors) > 0) {