Detecting JS Errors with Playwright

6 January 2025 - 563 mots - playwright

Playwright is an open-source library developed by Microsoft that allows automating web browser tests. In addition to classic end-to-end tests, it offers advanced features to detect and analyze JavaScript errors that occur during test execution. As part of an audit I had to carry out, this feature proved extremely useful for identifying client-side bugs before they reach production.

Playwright Logo

Context

I have three HTML pages:

  • page0.html, an HTML page with no errors
  • page1.html, an HTML page generating a JS error
  • page2.html, an HTML page generating a JS warning
1
2
3
4
5
6
<html>
  <body>
    <h1>Hello world</h1>
    <h2>Page 0</h2>
  </body>
</html>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<html>
  <head>
    <script type="text/javascript">
      console.error('Console error');
    </script>
  </head>
  <body>
    <h1>Hello world</h1>
    <h2>Page 1</h2>
  </body>
</html>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<html>
  <head>
    <script type="text/javascript">
      console.warn('Console warn');
    </script>
  </head>
  <body>
    <h1>Hello world</h1>
    <h2>Page 2</h2>
  </body>
</html>

Setup

  • Start by setting up the test environment using the command npm init playwright@latest
  • The command will ask a few questions about the setup:
Installation: Questions
  • The command will generate all the files and install the dependencies:
Installation: File Generation and Dependency Installation
  • The command will then provide some commands to use Playwright:
Installation: Commands

Theory

Playwright allows you to listen to various page events. One of them, console, enables you to capture ConsoleMessage objects. Each console message triggers an event.

You can retrieve:

  • The type
  • The message
  • The origin of the message (file, line, and column)
  • The originating page

Here’s a basic implementation:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
page.on('console', (msg) => {
  console.log(msg.type()); // warning, error,...
  console.log(msg.text());
  console.log(msg.location().url);
  console.log(msg.location().lineNumber);
  console.log(msg.location().columnNumber);
  if (msg.page) {
    console.log(msg.page.url());
  }
});

Implementation

Now that we have the theory, let’s apply it to our HTML files.

We’ll create a scenario with three steps:

  • Before each test:
    • Listen to the console event and capture errors and warnings.
  • After each test:
    • Reset the errors and warnings on the page.
  • For each test:
    • Visit each HTML file.
    • Verify the expected number of console errors and warnings.

Here’s the code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
import { test, expect } from '@playwright/test';
import { dirname } from 'path';

test.describe('Audit', () => {
  type BasicConsoleMessage = {url: string, error: string};
  let consoleErrors: BasicConsoleMessage[] = [];
  let consoleWarnings: BasicConsoleMessage[] = [];

  test.beforeEach(async ({ page }) => {
    page.on('console', (msg) => {
      if (msg.type() === 'error') {
        consoleErrors.push({
          url: page.url(),
          error: msg.text(),
        });
      }
      if (msg.type() === 'warning') {
        consoleWarnings.push({
          url: page.url(),
          error: msg.text(),
        });
      }
    });
  });

  test.afterEach(async () => {
    consoleErrors = [];
    consoleWarnings = [];
  });

  test('Page 0', async ({ page }) => {
    await page.goto(`file://${dirname(__dirname)}/page0.html`);

    await expect(page.getByRole('heading', {
      level: 1
    })).toContainText('Hello world');
    await expect(consoleErrors).toHaveLength(0);
    await expect(consoleWarnings).toHaveLength(0);
  });

  test('Page 1', async ({ page }) => {
    await page.goto(`file://${dirname(__dirname)}/page1.html`);

    await expect(page.getByRole('heading', {
      level: 1
    })).toContainText('Hello world');
    await expect(consoleErrors).toHaveLength(1);
    await expect(consoleWarnings).toHaveLength(0);
  });

  test('Page 2', async ({ page }) => {
    await page.goto(`file://${dirname(__dirname)}/page2.html`);

    await expect(page.getByRole('heading', {
      level: 1
    })).toContainText('Hello world');
    await expect(consoleErrors).toHaveLength(0);
    await expect(consoleWarnings).toHaveLength(1);
  });
});

And to run the tests, use this command:

1
npx playwright test --project=chromium

Here’s the result:

Test Result

Laisser un commentaire

Merci. Votre message a bien été enregistré.