Catégories
Astuces et Design

Apprenez à tester de bout en bout avec Puppeteer – SitePoint

Dans ce didacticiel, nous apprendrons ce que sont les tests, les différents types de tests, puis nous utiliserons Puppeteer pour effectuer des tests de bout en bout sur notre application. À la fin de ce didacticiel, vous devriez pouvoir tester facilement vos applications de bout en bout avec Puppeteer.

Qu'est-ce que le marionnettiste?

Puppeteer est une bibliothèque de nœuds qui fournit une API de haut niveau pour contrôler Chrome ou Chromium via le protocole DevTools. Puppeteer fonctionne sans tête par défaut, mais peut être configuré pour exécuter complètement Chrome (ou sans tête) Chrome ou Chrome.

Conditions préalables

Pour ce tutoriel, vous avez besoin d'une connaissance de base de JavaScript, ES6 + et Node.js.

Vous devez également avoir installé la dernière version de Node.js.

Nous utiliserons du fil tout au long de ce didacticiel. Si vous n'avez pas yarn déjà installé, installez-le à partir d'ici.

Vous devez également connaître les bases de Marionnettiste. Pour comprendre les bases de Puppeteer, consultez ce tutoriel simple.

Pour vous assurer que nous sommes sur la même page, voici les versions utilisées dans ce didacticiel:

  • Noeud 13.3.0
  • npm 6.13.2
  • fil 1.21.1
  • marionnettiste 2.0.0
  • create-react-app 3.3.0

Introduction aux tests

En termes simples, essai est un processus pour évaluer l'application fonctionne comme prévu. Il aide à détecter les bogues avant le déploiement de votre application.

Il existe quatre types de tests différents:

  1. Test statique: utilise un système de type statique comme TypeScript, ReasonML, Flow ou un linter comme ESLint. Cela aide à capturer les erreurs de base comme les fautes de frappe et la syntaxe.
  2. Tests unitaires: la plus petite partie d'une application, également appelée unité, est testée.
  3. Test d'intégration: plusieurs unités connexes sont testées ensemble pour voir si l'application fonctionne parfaitement en combinaison.
  4. Test de bout en bout: l'application entière est testée du début à la fin, tout comme un utilisateur normal, pour voir si elle se comporte comme prévu.

Le trophée de test de Kent C Dodds est une excellente visualisation des différents types de tests:

Trophée d'essais - Kent C Dodds

Le trophée de test doit être lu de bas en haut. Si vous effectuez ces quatre niveaux de test, vous pouvez être suffisamment confiant avec le code que vous expédiez.

Réalisons maintenant des tests de bout en bout avec Puppeteer.

Tests de bout en bout avec Puppeteer

Initions un nouveau projet React avec create-react-app, également connu sous le nom de CRA. Allez-y et tapez ce qui suit dans le terminal:

$ npx create-react-app e2e-puppeteer

Cela amorcera un nouveau projet React dans un e2e-puppeteer dossier. Merci aux derniers create-react-app version, cela installera également testing-library par défaut afin que nous puissions tester nos applications facilement.

Allez à l'intérieur du e2e-puppeteer répertoire et démarrez le serveur en tapant ce qui suit dans le terminal:

$ cd e2e-puppeteer
$ yarn start

Ça devrait ressembler à ça:

React Init

Notre App.js ressemble à ça:

importer React à partir de 'react';
importer le logo de './logo.svg';
import './App.css';

fonction App () {
  revenir (
    
logo

Éditer src/App.js et enregistrez pour recharger.

Apprenez à réagir
); } exporter l'application par défaut;

Nous allons tester le App.js fonction et le code sera écrit en App.test.js. Alors allez-y et ouvrez App.test.js. Il devrait avoir le contenu suivant:

import React from 'react';
import { render } from '@testing-library/react'; // 1
import App from './App';

test('renders learn react link', () => { // 2
  const { getByText } = render(); // 3
  const linkElement = getByText(/learn react/i); // 4
  expect(linkElement).toBeInTheDocument(); // 5
});

Voici ce qui se passe dans le code ci-dessus:

  1. nous import le render fonction du @testing-library/react paquet.
  2. Nous utilisons ensuite le global test fonction de Jest, qui est notre lanceur de test installé par défaut via CRA. Le premier paramètre est une chaîne qui décrit notre test, et le second paramètre est une fonction où nous écrivons le code que nous voulons tester.
  3. Ensuite, nous rendons le App composant et détruire une méthode appelée getByText, qui recherche tous les éléments ayant un nœud de texte avec textContent.
  4. Ensuite, nous appelons le getByText fonctionner avec le texte que nous voulons vérifier. Dans ce cas, nous vérifions learn react avec le drapeau insensible à la casse.
  5. Enfin, nous faisons l'affirmation avec le expect pour vérifier si le texte existe dans le DOM.

Cela vient par défaut lorsque nous démarrons avec CRA. Allez-y et ouvrez un autre terminal et tapez ce qui suit:

$ yarn test

Lorsqu'il affiche une invite, tapez a pour exécuter tous les tests. Vous devriez maintenant voir ceci:

React Init Test

Maintenant, testons cette application avec des tests de bout en bout.

Test de la chaudière avec un marionnettiste

Allez-y et installez puppeteer comme dépendance de développement en tapant ce qui suit dans le terminal:

$ yarn add -D puppeteer

Maintenant, ouvrez App.test.js et collez ce qui suit:

import puppeteer from "puppeteer"; // 1

let browser;
let page;

// 2
beforeAll(async () => {
  browser = await puppeteer.launch({
    headless: false
  });
  page = await browser.newPage();
  await page.goto("http://localhost:3000/");
});

// 3
test("renders learn react link", async () => {
  await page.waitForSelector(".App");

  const header = await page.$eval(".App-header>p", e => e.innerHTML);
  expect(header).toBe(`Edit src/App.js and save to reload.`);

  const link = await page.$eval(".App-header>a", e => {
    return {
      innerHTML: e.innerHTML,
      href: e.href
    };
  });
  expect(link.innerHTML).toBe(`Learn React`);
  expect(link.href).toBe("https://reactjs.org/");
});

// 4
afterAll(() => {
  browser.close();
});

Voici ce que nous faisons dans le code ci-dessus:

  1. Premièrement, nous importons le puppeteer empaqueter et déclarer quelques variables globales, browser et page.
  2. Ensuite, nous avons le beforeAll fonction fournie par Jest. Cela s'exécute avant l'exécution de tous les tests. Ici, nous lançons un nouveau navigateur Chromium en appelant puppeteer.launch(), tout en définissant headless mode à false nous voyons donc ce qui se passe. Ensuite, nous créons une nouvelle page en appelant browser.newPage() puis accédez à l'URL de notre application React http://localhost:3000/ en appelant le page.goto() une fonction.
  3. Ensuite, nous attendons le .App sélecteur à charger. Quand il se charge, nous obtenons le innerHTML de .App-header>p sélecteur en utilisant le page.$eval() méthode et la comparer avec Edit src/App.js et économiser pour recharger .. Nous faisons la même chose avec le .App-header>a sélecteur. Nous revenons innerHTML et href puis on les compare avec Learn React et https://reactjs.org/ respectivement pour tester notre assertion avec Jest expect() une fonction.
  4. Enfin, nous appelons afterAll fonction fournie par Jest. Cela s'exécute après l'exécution de tous les tests. Ici, nous fermons le navigateur.

Ce test devrait s'exécuter automatiquement et vous donner le résultat suivant:

E2E Test Puppeteer Basic

Allons de l'avant et créons une application de comptoir.

Conversion de la chaudière en application de comptoir

Tout d'abord, modifiez du CSS en changeant App.css aux éléments suivants:

.header {
  font-size: 56px;
  text-align: center;
}

.counter-app {
  display: flex;
  justify-content: space-around;
}

button {
  background-color: navajowhite;
  font-size: 32px;
}

.count {
  font-size: 48px;
}

Maintenant changez App.js aux éléments suivants:

import React, { useState } from "react";
import "./App.css";

function App() {
  const (count, setCount) = useState(0);
  return (
    <>
      

Counter

{count}
); } export default App;

Ici, nous créons une application de compteur simple avec deux boutons, Increment et Decrement. En appuyant sur Increment bouton, le compteur est augmenté de 1, et en appuyant sur Decrement bouton, le compteur est diminué de 1. Il ressemble à ceci:

Compteur de réaction

Test de l'application Counter avec Puppeteer

Maintenant, changez le App.test.js aux éléments suivants:

import puppeteer from "puppeteer";

let browser;
let page;

beforeAll(async () => {
  browser = await puppeteer.launch({
    headless: false
  });
  page = await browser.newPage();
  await page.goto("http://localhost:3000/");
});

// 1
test("renders counter", async () => {
  await page.waitForSelector(".header");

  const header = await page.$eval(".header", e => e.innerHTML);
  expect(header).toBe("Counter");
});

// 2
test("sets initial state to zero", async () => {
  await page.waitForSelector(".counter-app");

  const count = await page.$eval(".count", e => e.innerHTML);
  expect(count).toBe("0");
});

// 3
test("increments counter by 1", async () => {
  await page.waitForSelector(".counter-app");

  await page.click(".increment");
  const count = await page.$eval(".count", e => e.innerHTML);
  expect(count).toBe("1");
});

// 4
test("decrements counter by 1", async () => {
  await page.waitForSelector(".counter-app");

  await page.click(".decrement");
  const count = await page.$eval(".count", e => e.innerHTML);
  expect(count).toBe("0");
});

afterAll(() => {
  browser.close();
});

Ici, on garde le beforeAll et afterAll fonctionner de la même manière, comme précédemment, où nous initialisons un navigateur et allons à http://localhost:3000/ dans beforeAll et nous fermons le navigateur afterAll. Ensuite, nous faisons ce qui suit:

  1. Nous vérifions si le texte Counter est rendu. Pour cela, nous attendons le .header sélecteur à charger. Ensuite, nous utilisons page.$eval() pour obtenir le innerHTML de .header sélecteur. Et puis nous faisons enfin l'affirmation de vérifier si Counter est rendu.
  2. Ensuite, nous vérifions si l'état initial est zéro. Nous attendons le .counter-app sélecteur à charger. Ensuite, nous obtenons le innerHTML du .count sélecteur. On compare enfin si le count est 0. Notez que nous utilisons un string alors que notre état est un number. Ceci est dû au fait innerHTML renvoie toujours un string.
  3. Ici, nous vérifions si un clic sur le bouton incrémente l'état de 1. D'abord, nous attendons le .counter-app sélecteur à charger. On clique ensuite sur le .increment bouton. Cela devrait augmenter l'état de 0 à 1. Nous obtenons ensuite le innerHTML du .count sélecteur. Ensuite, nous le comparons à 1, comme notre increment la fonction doit toujours augmenter l'état de 1.
  4. Le bouton de décrémentation doit diminuer l'état de 1. Il fonctionne de la même manière que le bouton d'incrémentation. Tout d'abord, nous attendons le .counter-app sélecteur à charger. On clique ensuite sur le .decrement bouton. Cela devrait diminuer l'état de 1 à 0. Notez que l'état était 1 après avoir cliqué sur le increment bouton. Nous obtenons ensuite le innerHTML du .count sélecteur. Ensuite, nous le comparons à 0, comme notre decrement la fonction doit toujours diminuer l'état de 1.

Le résultat devrait maintenant ressembler à ceci:

Compteur de marionnettistes de test E2E

Conclusion

Dans ce didacticiel, nous avons découvert différents types de tests: tests statiques, tests unitaires, tests d'intégration et tests de bout en bout. Nous avons ensuite effectué des tests de bout en bout sur notre passe-partout, amorcés à l'aide de create-react-app.

Plus tard, nous avons converti l'application en application de compteur. Enfin, nous avons effectué des tests de bout en bout sur l'application de compteur.

La bibliothèque Puppeteer est utile non seulement pour effectuer des tests de bout en bout, mais également pour effectuer différents types d'automatisation de navigateur. Puppeteer est soutenu par Google et est activement maintenu, alors assurez-vous de vérifier ses documents pour comprendre les nombreux cas d'utilisation qu'il propose.

Vous pouvez trouver le code de ce tutoriel sur GitHub.

Pour en savoir plus sur les tests, SitePoint Premium fournit une gamme de ressources, notamment:

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *