Détecter les erreurs JS avec Playwright

6 janvier 2025 - 619 mots - playwright

Playwright est une librairie open-source développée par Microsoft qui permet d’automatiser les tests de navigateurs web. En plus des tests end-to-end classiques, elle offre des fonctionnalités avancées pour détecter et analyser les erreurs JavaScript qui surviennent pendant l’exécution des tests. Dans le cadre d’un audit que j’ai eu à réaliser, cette fonctionnalité est vraiment utile pour identifier les bugs côté client avant qu’ils n’atteignent la production.

Logo Playwright

Contexte

J’ai trois pages HTML :

  • page0.html qui est une page HTML sans erreurs
  • page1.html qui est une page HTML qui génère une erreur JS
  • page2.html qui est une page HTML qui génère un warning JS
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>

Mise en place

  • On va commencer par mettre en place l’environnement de test avec la commande npm init playwright@latest
  • La commande va nous poser quelques questions sur le déploiement :
Installation : Questions
  • La commande va générer tous les fichiers et installer les dépendances :
Installation : Génération des fichiers et Installation des dépendances
  • La commande donne ensuite quelques commandes pour utiliser playwright :
Installation : Commandes

Théorie

Playwright permet de se brancher sur différents évènements de la page. L’un d’eux console permet de récupérer des objets de type ConsoleMessage. Chaque message de la console déclenchera un évènement.

On peut y récupérer :

  • le type
  • le message
  • l’origine du message (fichier, line et colonne)
  • la page d’origine

Ainsi, le code sera basiquement cela :

 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());
  }
});

Utilisation

Maintenant que l’on a la théorie, on peut l’appliquer sur nos fichiers HTML.

On va créer un scénario en trois étapes :

  • Avant chaque test :
    • Je me branche sur l’évènement console et je récupère les erreurs et les warnings de la console
  • Après chaque test :
    • Je réinitialise les erreurs et warnings de la page
  • Pour chaque test :
    • Je vais sur le chaque fichier HTML
    • Je vérifie qu’il y a bien le bon nombre d’erreurs et de warnings de la console attendus

Voici le 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);
  });
});

Et pour tester cela, une commande :

1
npx playwright test --project=chromium

Et voilà le résultat :

Resultat du test

Laisser un commentaire

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