Table of contents
Monitoring JavaScript log messages is how you know, at a basic level, what the browser’s JavaScript engine is doing in detail. Playwright provides an efficient way to listen for console logs and uncaught exceptions in your pages. This capability is invaluable for developers and testers aiming to catch and resolve issues early in the development cycle. This article will guide you through the process of setting up Playwright to monitor JavaScript logs and exceptions, enhancing your testing strategy.
Setting Up Your Environment
Testing requires a basic Playwright setup. Setup involves a straightforward setup process that you can find in the official Playwright documentation. You can also write and run your first Playwright tests using Checkly.
After that, it would be nice to check a page with totally predictable log messages and errors. In my case I stood up a tiny server who’s in-page code had the following lines:
console.error('hello there this is an error')
console.log('this is a log message')
//an uncaught exception will interrupt JS execution, don't do this in prod! :)
throw new Error('Do not do this outside of a try/catch block!');
Once your environment is ready, you can start implementing the techniques discussed here.
Listening for Console Log Messages
JavaScript applications can generate various types of console messages, including logs, warnings, and errors. These messages are often indicative of the application's state or issues that need attention. Playwright allows you to capture these messages by adding an event listener to the page object for console events.
Implementing the Console Listener
To listen for console messages, you'll need to attach an event listener to the page object as follows:
page.on('console', msg => {});
This will let you act on the console messages that you receive. It would be tempting to try to simply console.log out from this inner function, to record each log message. The following code, however, is nonfunctional:
page.on('console', msg => {console.log(message)});
This inner console.log()
will be evaluated within the page load, and won't show up when you're running your playwright test. Instead, you want to initialize an array before the page load, then push to that array.
test('Localhost error logging', async ({ page }) => {
const logs = []
// Listen for all console logs
page.on('console', msg => {logs.push({msg, type: msg.type()})});
// Listen for all console events and handle errors
await page.goto('localhost:3000');
console.log(logs);
})
In this example, we're pushing each console message to a logs
array, including the message type and the text of the message. We then log out the logs
array (note that this code doesn’t actually include an assertion and will never fail).
Understanding the ConsoleMessage Class
Playwright's ConsoleMessage
class represents a console message event on a page, such as logs, warnings, errors, debug messages, and more. Each ConsoleMessage
instance provides detailed information about the message, including its type, text, location (URL and line number), and any arguments passed to the console method.
Filtering Messages by Type
In many scenarios, you might be interested in monitoring specific types of messages, such as errors or warnings. You can filter messages by their type using the type()
method of the ConsoleMessage
class:
const errors = []
page.on('console', message => {
if (message.type() === 'error') {
errors.push(`Error message: ${message.text()}`);
}
});
This technique is particularly useful for focusing on critical issues that could impact the application's functionality or user experience.
There are 18 log message types but the ones you’re likely to run into are log
, debug
, info
, error
, and warning
.
Accessing Message Location
Playwright allows you to access the location where a console message was generated, including the URL, line number, and column number. This information is invaluable for debugging purposes, as it helps pinpoint the exact source of a message:
page.on('console', message => {
const location = message.location();
logs.push(`Message from ${location.url}:${location.lineNumber}:${location.columnNumber}`);
});
If you’re using the demo JS from the ‘setting up’ section above, the result would be:
[
'Message from http://localhost:3000/index.js:0:8',
'Message from http://localhost:3000/index.js:1:8'
]
Asserting Console Messages in Tests
Advanced monitoring also involves asserting the presence or absence of specific console messages within your tests. By collecting messages in an array, you can assert expectations about the messages that should or should not appear during test execution:
test('Localhost error logging', async ({ page }) => {
const logs = []
page.on('console', msg => logs.push(msg.text()));
await page.goto('localhost:3000');
console.log(logs);// [ 'hello there this is an error', 'this is a log message apples' ]
expect(logs).toContain('hello there this is an error');
})
Note that toContain
is a simple string match and won't accept a regular expression pattern. In the demo JS run above, running expect(logs).toContain('apples')
will fail, as it needs to match the complete string within the array.
Capturing Uncaught Exceptions
Uncaught exceptions are critical errors that can disrupt the normal operation of your application. Playwright provides a straightforward way to capture these exceptions using the pageerror event.
Implementing the Exception Listener
Similar to capturing console messages, you can listen for uncaught exceptions by adding an event listener for the pageerror event:
const errors = [];
page.on('pageerror', exception => {
errors.push(exception.message);
});
// later in the test
console.log(errors) //[ 'Do not do this outside of a try/catch block!' ]
Here, we're collecting the exception messages in an errors array. This approach allows you to keep track of uncaught exceptions that occur during the execution of your Playwright scripts.
Asserting Conditions Based on Logs and Exceptions
With the captured console messages and exceptions, you can now assert certain conditions to ensure your application behaves as expected. For instance, you might want to verify that no errors or warning messages are present:
await page.goto('<http://localhost:8080>');
// Additional test steps...
expect(logs).toHaveLength(0);
expect(errors).toHaveLength(0);
These assertions confirm that no console messages or uncaught exceptions were encountered during the test execution. If any messages or exceptions are captured, the test will fail. Note that it is probably not a good idea to do too much testing based on the number of log messages, especially the number you’re expecting isn’t zero. Testing with Playwright should largely be based on user expectations. And no one loading your home page expects that your page won’t log anything to the console!
Soft Assertions for Continuous Monitoring
In some cases, you might want to continue running your test even after encountering log messages or exceptions. This can be achieved by implementing soft assertions, which allow the test to proceed while still reporting the issues encountered:
// Example of a soft assertion implementation
if (logs.length > 0) {
console.warn('Console messages detected:', logs);
}
if (errors.length > 0) {
console.error('Uncaught exceptions detected:', errors);
}
Soft assertions are particularly useful for logging purposes or when you want to aggregate issues across multiple test cases without halting execution.
Going Further
Monitoring JavaScript log messages and exceptions is a powerful technique for enhancing the quality of web applications. Playwright makes it easy to implement this monitoring within your automated tests, providing valuable insights into potential issues and ensuring that your application meets the desired standards of reliability and performance. By incorporating these practices into your testing strategy, you can proactively address issues, leading to a more robust and error-free application.
To see log messages in Playwright in action, check out this video from the Checkly YouTube page:
Join the Checkly Community
If you'd like to join a community of Playwright users, join the Checkly Slack, with our awesome #Playwright-Community channel.