Écriture d’un test Jest

Objectifs de formation

Une fois cette unité terminée, vous pourrez :

  • Écrire un test pour vérifier votre configuration
  • Écrire un test qui échoue et le corriger en modifiant votre composant
  • Identifier les commandes Jest de base
  • Présenter les points d’ancrage de cycle de vie

Partir d’un composant Web Lightning

Pour tester un composant Web Lightning, nous devons d’abord avoir un composant à tester.

Création d’un composant Web Lightning

  1. Dans Visual Studio Code, ouvrez la palette de commandes en appuyant sur Ctrl+Maj+P (Windows) ou sur Cmd+Maj+P (macOS).
  2. Saisissez lightning web.
  3. Sélectionnez SFDX :. création d’un composant Web Lightning. N’utilisez pas SFDX : création d’un composant Lightning. (Cela crée un composant Aura.)
  4. Saisissez unitTest pour nommer le nouveau composant.
  5. Appuyez sur Entrée.
  6. Appuyez de nouveau sur Entrée pour accepter l’emplacement par défaut force-app/main/default/lwc.

Cette action crée le répertoire unitTest dans le répertoire lwc comprenant les fichiers de base initiaux.

Répertoire unitTest dans le projet test-lwc.

Écriture d’un test de base

Les tests Jest sont écrits, enregistrés et exécutés différemment des tests Jasmine ou Mocha destinés à Lightning Testing Service pour les composants Aura. Les tests Jest sont uniquement locaux, et sont enregistrés et exécutés indépendamment de Salesforce. Vous obtiendrez d’ailleurs une erreur si vous essayez de déployer des tests Jest dans votre organisation Salesforce. Bien que les tests Jest pour les composants Web Lightning ne soient pas déployés dans votre organisation Salesforce, veillez à les valider dans le système de contrôle de version avec le composant lui-même. 

Création du dossier __tests__

Les fichiers test doivent être séparés des autres fichiers de composant. Créez un dossier nommé __tests__ au niveau supérieur du dossier du paquet de votre composant. Enregistrez tous les tests relatifs à ce composant dans le dossier __tests__. 

  1. Dans Visual Studio Code, cliquez avec le bouton droit de la souris sur le répertoire unitTest et sélectionnez Nouveau dossier.
  2. Saisissez __tests__.
  3. Appuyez sur Entrée.

Configuration de .forceignore

Partagez les tests avec d’autres membres de l’équipe ou systèmes en validant le dossier __tests__ dans le système de contrôle de version. Ils constituent un élément essentiel de votre projet et de votre processus d’intégration continue. Pour les empêcher d’être déployés sur Salesforce, le fichier .forceignore est associé à une exclusion. 

  • Assurez-vous que le fichier .forceignore de votre projet contient les exclusions suivantes. Si ce n’est pas le cas, ajoutez-les et enregistrez le fichier.
    # LWC configuration files
    **/jsconfig.json
    **/.eslintrc.json
    # LWC Jest
    **/__tests__/**

Création du fichier test Jest

Notre premier test est simple. Nous disposons d’une fonction sum() censée ajouter deux nombres qui lui sont transmis en tant qu’arguments.

  1. Dans Visual Studio Code, cliquez avec le bouton droit de la souris sur le répertoire __tests__ et sélectionnez Nouveau fichier.
  2. Saisissez sum.test.js.
  3. Appuyez sur Entrée.
  4. Saisissez le code suivant dans le nouveau fichier test :
    import { sum } from '../sum';
      
    describe('sum()', () => {
      it('should add 1 and 2 returning 3', () => {
        expect(sum(1, 2)).toBe(3);
      });
    });
  5. Enregistrez le fichier.

Exécution du test

  1. Dans Visual Studio Code, sélectionnez Afficher, puis sélectionnez Terminal. Cette action ouvre un terminal dans Visual Studio Code. Le terminal utilise par défaut le répertoire de niveau supérieur du projet en cours.
  2. Dans le terminal, exécutez la commande suivante utilisée dans l’unité précédente :
    npm run test:unit
  3. Le test échoue en raison de la fonction de somme manquante.

Observons comment y remédier. 

  1. Dans Visual Studio Code, cliquez avec le bouton droit de la souris sur le répertoire unitTest et sélectionnez Nouveau fichier.
  2. Saisissez sum.js.
  3. Appuyez sur Entrée.
  4. Saisissez le bloc de code suivant dans le nouveau fichier :
    export function sum(x, y) {
      return x + y;
    }
  5. Enregistrez le fichier.
  6. Dans le terminal, exécutez à nouveau le test :
    npm run test:unit
  7. Le test réussit.


Félicitations ! Vous venez de vérifier que Jest est installé et fonctionne correctement.

Examinons le code test pour observer ce qui se passe.

import { sum } from '../sum';
  
describe('sum()', () => {
  it('should add 1 and 2 returning 3', () => {
    expect(sum(1, 2)).toBe(3);
  });
});
  • La ligne 1 importe la fonction sum exportée à partir du fichier JavaScript de somme.
  • La ligne 3 déclenche la suite de tests Jest. La fonction ou le bloc describe est une suite de tests et accepte deux arguments. Le premier est la description de l’unité que nous testons, qui se présente généralement sous la forme d’un nom. Le deuxième est une fonction de rappel qui contient un ou plusieurs tests. Vous pouvez également imbriquer les suites de tests describe les unes dans les autres pour plus de clarté.
  • La ligne 4 correspond au test (it est un alias de test). La fonction ou le bloc it accepte également deux arguments. Le premier est une autre description de nos attentes, qui commence généralement par un verbe. Le deuxième est une fonction de rappel qui crée le test et contient les assertions ou les attentes relatives au test.
  • La ligne 5 indique l’instruction expect, affirmant la condition de succès, c’est-à-dire que la fonction sum ajoute les deux arguments, 1 et 2, et renvoie 3. toBe est l’un des nombreux matchers Jest.
    Ajoutez une autre assertion avec la ligne suivante juste après la ligne 5 :
        expect(sum(1, 2)).not.toBeGreaterThan(3);
  • L’ajout de .not et .toBeGreaterThan permet de s’assurer que le nombre ne dépasse pas 3. Vous pouvez ajouter une autre instruction expect avec .not.toBeLessThan(3)

Passons maintenant au test du composant Web Lightning.

Les tests Jest pour un composant Web Lightning doivent tester le comportement d’un seul composant de manière isolée, avec un minimum de dépendances aux composants ou services externes.

Répétez le processus pour créer le fichier test unitTest.

Ce test permet de vérifier qu’une propriété est définie et, une fois ajoutée au DOM, qu’elle affichera le texte correct.

  1. Cliquez avec le bouton droit de la souris sur le répertoire __tests__ et sélectionnez Nouveau fichier.
  2. Saisissez unitTest.test.js.
  3. Appuyez sur Entrée.
  4. Saisissez le code suivant dans le nouveau fichier test :
    import { createElement } from 'lwc';
    import UnitTest from 'c/unitTest';
      
    describe('c-unit-test', () => {
      afterEach(() => {
        // The jsdom instance is shared across test cases in a single file so reset the DOM
        while(document.body.firstChild) {
          document.body.removeChild(document.body.firstChild);
        }
      });
      
      it('displays unit status with default unitNumber', () => {
        const element = createElement('c-unit-test', {
          is: UnitTest
        });
        expect(element.unitNumber).toBe(5);
        // Add the element to the jsdom instance
        document.body.appendChild(element);
        // Verify displayed greeting
        const div = element.shadowRoot.querySelector('div');
        expect(div.textContent).toBe('Unit 5 alive!');
      });
    });
  5. Enregistrez le fichier.
  6. Dans le terminal, exécutez à nouveau les tests :
    npm run test:unit
  7. Les tests échouent comme suit :
    Test Suites: 1 failed, 1 passed, 2 total
    Tests:       1 failed, 1 passed, 2 total

Examinons ce code test pour déterminer les modifications à apporter avant de mettre à jour le code pour obtenir la réussite du test.

  • La ligne 1 est nouvelle. Elle importe la méthode createElement à partir de l’infrastructure lwc. Elle n’est disponible que dans les tests.
  • La ligne 2 importe la classe UnitTest à partir du contrôleur JavaScript du composant.
  • La ligne 4 démarre le bloc de suite de tests describe.
  • La ligne 5 est une méthode de nettoyage Jest. afterEach() est l’une des méthodes de configuration et de nettoyage de Jest. La méthode afterEach() s’exécute après chaque test dans le bloc describe dans lequel elle se trouve. Cette méthode afterEach() réinitialise le DOM à la fin du test. Jest n’exécute pas de navigateur lors de l’exécution des tests. Jest utilise jsdom pour fournir un environnement qui se comporte de manière semblable au DOM ou au document d’un navigateur. Chaque fichier test reçoit une seule instance de jsdom et les modifications ne sont pas réinitialisées entre les tests à l’intérieur du fichier. Il est recommandé de nettoyer les données entre les tests afin que la sortie d’un test n’ait d’effets sur aucun autre test. Il existe d’autres méthodes de configuration et de nettoyage. Pour en savoir plus, consultez la section Ressources.
  • La ligne 12 démarre le bloc test it.
  • La ligne 13 indique l’utilisation de la méthode createElement importée. Elle crée une instance du composant et l’attribue à l’élément de constante, element.
  • À la ligne 16, l’instruction expect affirme que la variable unitNumber est définie sur 5. Nous vérifions que unitNumber est tout d’abord définie sur 5 ; il s’agit de la première exigence du test.
  • La ligne 18 permet d’ajouter element à la version jsdom de document.body en utilisant la méthode appendChild. L’appel joint le composant Web Lightning au DOM et le restitue, ce qui signifie également que les points d’ancrage de cycle de vie connectedCallback() et renderedCallback() sont appelés (nous en parlerons plus tard).
  • La ligne 20 utilise querySelector (une méthode de requête DOM standard) pour rechercher une balise div dans le DOM. Utilisez element.shadowRoot comme parent de la requête. Il s’agit d’une API de test uniquement qui vous permet d’examiner la frontière fantôme pour inspecter l’arbre fantôme d’un composant.
  • Enfin, à la ligne 21, l’instruction expect affirme que « Unit 5 alive! » se trouve bien dans l’élément textContent de la balise div. Il s’agit de la dernière exigence : affirmer que le texte est correct.

Pour que le test réussisse, vous devez ajouter du code aux fichiers HTML et JavaScript unitTest. Nous allons ajouter du code pour répondre aux exigences.

  1. Cliquez sur le fichier unitTest.html pour l’ouvrir.
  2. Remplacez unitTest.html par :
    <template>
      <lightning-card title="Unit Status" icon-name="standard:bot">
        <div class="slds-m-around_medium">
          Unit {unitNumber} alive!
        </div>
      </lightning-card>
    </template>
  3. Enregistrez le fichier.
  4. Cliquez sur le fichier unitTest.js pour l’ouvrir et remplacez-le par :
    import { LightningElement, api } from 'lwc';
    import { sum } from './sum';
      
    export default class UnitTest extends LightningElement {
      @api unitNumber = sum(2,3);
    }
  5. Enregistrez le fichier et exécutez les tests :
    npm run test:unit
  6. Tous les tests réussissent.

Test des mises à jour asynchrones du DOM

Lorsque l’état d’un composant Web Lightning change, le DOM se met à jour de manière asynchrone. Pour vous assurer que votre test attend la fin des mises à jour avant d’évaluer le résultat, renvoyez une promesse résolue. Pour ce faire, reliez le reste de votre code test à la promesse résolue. Jest attend que la chaîne promesse se termine avant de mettre fin au test. Si la promesse se termine avec l’état rejeté, Jest indique l’échec du test.

  1. Ouvrez unitTest.test.js.
  2. Ajoutez ce deuxième test après le dernier test.
    Dans ce test, nous souhaitons vérifier qu’une modification de propriété actualise le texte dans le DOM.
      it('displays unit status with updated unitNumber', () => {
        const element = createElement('c-unit-test', {
         is: UnitTest
        });
        // Add the element to the jsdom instance
        document.body.appendChild(element);
        // Update unitNumber after element is appended
        element.unitNumber = 6
        const div = element.shadowRoot.querySelector('div');
        // Verify displayed unit status
        expect(div.textContent).toBe('Unit 6 alive!');
      });
  3. Enregistrez le fichier et exécutez les tests.
    npm run test:unit
  4. Vous obtenez ce message d’échec :
    Expected: "Unit 6 alive!"
    Received: "Unit 5 alive!"

Que se passe-t-il ? L’instruction expect affirme que div.textContext reçoit toujours « Unit 5 alive! » au lieu de « Unit 6 alive! ». Afin d’appliquer la modification, nous devons l’attendre en renvoyant une promesse Promise résolue. 

  1. Remplacez l’instruction expect qui a échoué par ce qui suit, juste après le commentaire // Verify display unit status :
        expect(div.textContent).not.toBe('Unit 6 alive!');
        // Return a promise to wait for any asynchronous DOM updates. Jest
        // will automatically wait for the Promise chain to complete before
        // ending the test and fail the test if the promise rejects.
        return Promise.resolve().then(() => {
          expect(div.textContent).toBe('Unit 6 alive!');
        });
  2. Exécutez le test en utilisant la même commande que la dernière fois, ou en mettant en pratique l’une des autres possibilités présentées dans la section Exécution de tests Jest de l’unité précédente.
  3. Le test réussit.

Jusqu’ici, tout va bien. Trois tests ont réussi dans deux suites de tests. Vous allez maintenant ajouter un quatrième test afin de pouvoir vérifier que l’état de l’unité est mis à jour lors de la mise à jour d’un champ d’entrée. Pour ce faire, utilisez un événement de modification dans le champ d’entrée.

  1. Si ce n’est pas déjà fait, ouvrez unitTest.test.js.
  2. Ajoutez une ligne après le dernier test que vous avez intégré et ajoutez ce troisième test à la suite :
      it('displays unit status with input change event', () => {
        const element = createElement('c-unit-test', {
          is: UnitTest
        });
        document.body.appendChild(element);
        const div = element.shadowRoot.querySelector('div');
        // Trigger unit status input change
        const inputElement = element.shadowRoot.querySelector('lightning-input');
        inputElement.value = 7;
        inputElement.dispatchEvent(new CustomEvent('change'));
        return Promise.resolve().then(() => {
          expect(div.textContent).toBe('Unit 7 alive!');
        });
      });
  3. Enregistrez le fichier et exécutez le test. Le message d’échec suivant s’affiche :
    Message d’erreur. Vous pouvez observer qu’un seul test a été exécuté et que les deux autres ont été ignorés.

Observons ce qui est testé :

  • Vous devriez reconnaître les premières lignes. Vous ajoutez la classe UnitTest à document.body, puis vous créez une référence à l’élément div.
  • La constante inputElement est définie avec une référence à un champ lightning-input.
  • Ensuite, la valeur de ce champ d’entrée est définie sur 7.
  • Nous utilisons ensuite dispatchEvent pour déclencher un événement comportant un CustomEvent en utilisant un type d’événement « change ».
  • Vous reconnaissez l’élément Promise, car il n’a été modifié que selon la valeur du champ d’entrée modifié.

Mettons à jour le code pour qu’il réussisse. Pour ce faire, ajoutez lightning-input au fichier HTML et la méthode handleChange au contrôleur JavaScript.

  1. Ouvrez unitTest.html.
  2. Ajoutez le code suivant à l’intérieur de lightning,-card et avant div :
      <lightning-input
        label="Unit Number"
        value={unitNumber}
        onchange={handleChange} >
      </lightning-input>
  3. Enregistrez le fichier.
  4. Ouvrez unitTest.js.
  5. Ajoutez le code suivant après l’instruction @api unitNumber :
      handleChange(event) {
        this.unitNumber = event.target.value;
      }
  6. Enregistrez le fichier et exécutez les tests.
  7. Les tests réussissent en raison de l’élément d’entrée supplémentaire et du gestionnaire JavaScript.

Test des points d’ancrage de cycle de vie

Le cycle de vie des composants Web Lightning est géré par l’infrastructure. L’infrastructure crée des composants, les ajoute au DOM, les supprime du DOM et effectue les mises à jour du DOM chaque fois que l’état d’un composant change. Il existe plusieurs méthodes pour interagir avec le cycle de vie. 

Le point d’ancrage de cycle de vie connectedCallback() se déclenche lorsqu’un composant est inséré dans le DOM. Le point d’ancrage de cycle de vie disconnectedCallback() se déclenche lorsqu’un composant est supprimé du DOM. Ces points d’ancrage permettent notamment d’enregistrer et de supprimer des écouteurs d’événements. 

Consultez le code de lmsSubscriberWebComponent dans le référentiel d’exemples de lwc-recipes pour en découvrir un bon exemple.

Nous allons maintenant nous pencher sur l’écriture de tests Jest pour les services Wire. 

Ressources