Test de code JavaScript avec Jest for dummies. Partie 1

Bonjour, Habr! Ce guide est la premiÚre partie d'une série d'articles prévus sur un cadre de test aussi génial que Jest. Le matériel sera utile pour les débutants et ceux qui viennent de se familiariser avec les tests et souhaitent étudier ce cadre. Dans la premiÚre partie, nous discuterons: comment démarrer avec jest, comment écrire un test simple et quelles méthodes existe-t-il pour comparer les valeurs à vérifier avec celles attendues. Peu importe - bienvenue à Kat!

Qu'est-ce que Jest?


Comme indiqué sur la page d'accueil du projet:
Jest est un incroyable environnement de test JavaScript axé sur la simplicité.
Et en effet, Jest est trÚs simple. Il ne nécessite pas de paramÚtres supplémentaires, facile à comprendre et à utiliser, et possÚde également une trÚs bonne documentation. Idéal pour les projets utilisant Node, React, Angular, Vue, Babel, TypeScript et plus encore.
Il est Ă©galement open source et soutenu par Facebook.

Installation


Pour installer Jest dans votre projet, procédez comme suit:

npm install --save-dev jest

Si vous utilisez du fil:

yarn add --dev jest

AprĂšs l'installation, vous pouvez mettre Ă  jour la section des scripts de votre package.json:

“scripts” : {
     “test”: “jest”
}

Avec ce simple appel, nous pouvons déjà exécuter nos tests (en fait, jest aura besoin d'au moins un test pour exister).

Vous pouvez Ă©galement installer globalement (mais je ne recommanderais pas de le faire, car pour moi l'installation globale des modules est une mauvaise pratique):

npm install jest --global

Et en conséquence pour le fil:

yarn global add jest

AprĂšs cela, vous pouvez utiliser jest directement depuis la ligne de commande.

En appelant la commande jest --init Ă  la racine du projet, aprĂšs avoir rĂ©pondu Ă  quelques questions, vous obtiendrez le fichier de paramĂštres jest.config.js. Ou vous pouvez ajouter la configuration directement Ă  votre package.json. Pour ce faire, ajoutez la clĂ© "jest" Ă  la racine json et dans l'objet correspondant, vous pouvez ajouter les paramĂštres dont vous avez besoin. Nous analyserons les options elles-mĂȘmes ultĂ©rieurement. Ce n'est pas nĂ©cessaire Ă  ce stade, car la plaisanterie peut ĂȘtre utilisĂ©e immĂ©diatement, sans configurations supplĂ©mentaires.

Premier test


Créons le fichier first.test.js et écrivons notre premier test:

//first.test.js
test('My first test', () => {
    expect(Math.max(1, 5, 10)).toBe(10);
});

Et exécutez nos tests en utilisant npm run test ou directement avec la commande jest (si installée globalement). AprÚs le lancement, nous verrons un rapport sur la réussite des tests.

 <b>PASS</b>  ./first.test.js
  ✓ My first test (1 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        0.618 s, estimated 1 s

Brisons notre test et exécutons à nouveau la plaisanterie:

//first.test.js
test('My first test', () => {
    expect(Math.max(1, 5, 10)).toBe(5);
});

Comme nous pouvons le voir, maintenant notre test ne passe pas le test. Jest affiche des informations détaillées sur l'origine du problÚme, le résultat attendu et ce que nous avons obtenu à la place.

Analysons maintenant le code du test lui-mĂȘme. Fonction testutilisĂ© pour crĂ©er un nouveau test. Il prend trois arguments (dans l'exemple, nous avons utilisĂ© un appel avec deux arguments). La premiĂšre est une ligne avec le nom du test, sa plaisanterie s'affichera dans le rapport. La seconde est une fonction qui contient la logique de notre test. Vous pouvez Ă©galement utiliser le 3Ăšme argument - timeout. Il est facultatif et sa valeur par dĂ©faut est de 5 secondes. Elle est dĂ©finie en millisecondes. Ce paramĂštre est nĂ©cessaire lorsque nous travaillons avec du code asynchrone et renvoyons une promesse de la fonction de test. Il indique combien de temps la plaisanterie doit attendre pour que la promesse soit rĂ©solue. PassĂ© ce dĂ©lai, si la promesse n'a pas Ă©tĂ© autorisĂ©e - la plaisanterie considĂ©rera que le test a Ă©chouĂ©. Vous trouverez plus d'informations sur l'utilisation des appels asynchrones dans les parties suivantes. Alternativement, vous pouvez l'utiliser () au lieu de test ().. Il n'y a aucune diffĂ©rence entre de tels appels. il () n'est qu'un alias de la fonction test () .

À l'intĂ©rieur de la fonction de test, nous appelons d'abord expect () . Nous lui transmettons la valeur que nous voulons vĂ©rifier. Dans notre cas, c'est le rĂ©sultat de l'appel Ă  Math.max (1, 5, 10) . expect () renvoie un objet wrapper qui a un certain nombre de mĂ©thodes pour comparer la valeur rĂ©sultante avec celle attendue. L'une de ces mĂ©thodes que nous avons utilisĂ©es est toBe .

Examinons les principales de ces méthodes:

  • toBe() — , , . Object.is(). === 0 -0, NaN c NaN.
  • toEqual() — , . . . .

    test('toEqual with objects', () => {
        expect({ foo: 'foo', subObject: { baz: 'baz' } })
            .toEqual({ foo: 'foo', subObject: { baz: 'baz' } });  // 
        expect({ foo: 'foo', subObject: { num: 0 } })
            .toEqual({ foo: 'foo', subObject: { baz: 'baz' } });  //    .
    });
    
    test('toEqual with arrays', () => {
        expect([11, 19, 5]).toEqual([11, 19, 5]); // 
        expect([11, 19, 5]).toEqual([11, 19]); // 
    });
    

  • toContain() — . ===.

    const arr = ['apple', 'orange', 'banana'];
    expect(arr).toContain('banana');
    expect(new Set(arr)).toContain('banana');
    expect('apple, orange, banana').toContain('banana');
    

  • toContainEqual() — .

    expect([{a: 1}, {b: 2}]).toContainEqual({a: 1});
    

  • toHaveLength() — length .

    expect([1, 2, 3, 4]).toHaveLength(4);
    expect('foo').toHaveLength(3);
    expect({ length: 1 }).toHaveLength(1);
    

  • toBeNull() — null.
  • toBeUndefined() — undefined.
  • toBeDefined() — toBeUndefined. !== undefined.
  • toBeTruthy() — true. false, null, undefined, 0, NaN .
  • toBeFalsy() — toBeTruthy(). false.
  • toBeGreaterThan() toBeGreaterThanOrEqual() — , >, >=.
  • toBeLessThan() toBeLessThanOrEqual() — toBeGreaterThan() toBeGreaterThanOrEqual()
  • toBeCloseTo() — , , . .

    const num = 0.1 + 0.2; // 0.30000000000000004
    expect(num).toBeCloseTo(0.3);
    expect(Math.PI).toBeCloseTo(3.14, 2);
    

  • toMatch() — .

    expect('Banana').toMatch(/Ba/);
    

  • toThrow () - utilisĂ© lorsqu'il est nĂ©cessaire de vĂ©rifier l'exception. Vous pouvez vĂ©rifier Ă  la fois le fait de l'erreur elle-mĂȘme et vĂ©rifier la levĂ©e d'exceptions d'une certaine classe, soit par le message d'erreur, soit par la correspondance du message avec l'expression rĂ©guliĂšre.

    function funcWithError() {
        throw new Error('some error');
    }   
    expect(funcWithError).toThrow();
    expect(funcWithError).toThrow(Error);
    expect(funcWithError).toThrow('some error');
    expect(funcWithError).toThrow(/some/);
    

  • non - cette propriĂ©tĂ© vous permet de vĂ©rifier l'inĂ©galitĂ©. Il fournit un objet qui possĂšde toutes les mĂ©thodes rĂ©pertoriĂ©es ci-dessus, mais elles fonctionneront dans l'autre sens.

    expect(true).not.toBe(false);
    expect({ foo: 'bar' }).not.toEqual({});
    
    function funcWithoutError() {}
    expect(funcWithoutError).not.toThrow();
    

Écrivons quelques tests simples. CrĂ©ez d'abord un module simple qui contiendra plusieurs mĂ©thodes de travail avec les cercles.

// src/circle.js
const area = (radius) => Math.PI * radius ** 2;
const circumference = (radius) => 2 * Math.PI * radius;
module.exports = { area, circumference };

Ensuite, ajoutez les tests:

// tests/circle.test.js
const circle = require('../src/circle');

test('Circle area', () => {
    expect(circle.area(5)).toBeCloseTo(78.54);
    expect(circle.area()).toBeNaN();
});

test('Circumference', () => {
    expect(circle.circumference(11)).toBeCloseTo(69.1, 1);
    expect(circle.circumference()).toBeNaN();
});

Dans ces tests, nous avons vérifié le résultat de 2 méthodes - surface et circonférence . En utilisant la méthode toBeCloseTo, nous avons vérifié le résultat attendu. Dans le premier cas, nous avons vérifié ou la zone calculée du cercle avec un rayon de 5 est approximativement égale à 78,54, tandis que la différence avec la valeur obtenue (elle sera 78,53981633974483) n'est pas grande et le test sera compté. Dans la seconde, nous avons indiqué que nous souhaitons vérifier à 1 décimale prÚs. Nous avons également appelé nos méthodes sans argument et vérifié le résultat à l'aide de toBeNaN . Comme le résultat de leur exécution sera NaN, les tests seront passés avec succÚs.

Prenons un autre exemple. Créons une fonction qui filtrera un tableau de produits par prix:

// src/productFilter.js
const byPriceRange = (products, min, max) =>
         products.filter(item => item.price >= min && item.price <= max);
module.exports = { byPriceRange };

Et ajoutez un test:

// tests/product.test.js
const productFilter = require('../src/producFilter');

const products = [
    { name: 'onion', price: 12 },
    { name: 'tomato', price: 26 },
    { name: 'banana', price: 29 },
    { name: 'orange', price: 38 }
];

test('Test product filter by range', () => {
    const FROM = 15;
    const TO = 30;
    const filteredProducts = productFilter.byPriceRange(products, FROM, TO);

    expect(filteredProducts).toHaveLength(2);
    expect(filteredProducts).toContainEqual({ name: 'tomato', price: 26 });
    expect(filteredProducts).toEqual([{ name: 'tomato', price: 26 }, { name: 'banana', price: 29 }]);
    expect(filteredProducts[0].price).toBeGreaterThanOrEqual(FROM);
    expect(filteredProducts[1].price).toBeLessThanOrEqual(TO);
    expect(filteredProducts).not.toContainEqual({ name: 'orange', price: 38 });
});

Dans ce test, nous allons vĂ©rifier le rĂ©sultat de la fonction byRangePrice . Tout d'abord, nous avons vĂ©rifiĂ© la correspondance de la longueur du tableau rĂ©sultant avec celui attendu - 2. Le contrĂŽle suivant nĂ©cessite que l'Ă©lĂ©ment contienne l'Ă©lĂ©ment - {nom: 'tomate', prix: 26}. L'objet du tableau et l'objet transmis Ă  ContainEqual sont deux objets diffĂ©rents, pas une rĂ©fĂ©rence au mĂȘme. Mais toContainEqual comparera chaque propriĂ©tĂ©. Étant donnĂ© que les deux objets sont identiques, la vĂ©rification rĂ©ussira. Ensuite, nous utilisons toEqual pour vĂ©rifier la structure de l'ensemble du tableau et de ses Ă©lĂ©ments. Les mĂ©thodes toBeGreaterThanOrEqual et toBeLessThanOrEqual nous aideront Ă  vĂ©rifier le prix du premier et du deuxiĂšme Ă©lĂ©ment du tableau. Et enfin, en appelant not.toContainEqualvĂ©rifiera si l'Ă©lĂ©ment est contenu dans le tableau - {nom: 'orange', prix: 38}, qui, par condition, ne devrait pas ĂȘtre lĂ .

Dans ces exemples, nous avons écrit quelques tests simples en utilisant les fonctions de vérification décrites ci-dessus. Dans les parties suivantes, nous discuterons du travail avec le code asynchrone, les fonctions plaisanteries qui n'étaient pas couvertes dans cette partie du tutoriel, nous parlerons de sa configuration, et bien plus encore.

All Articles