Découverte de Mocha
Tester sur le navigateur
Tester avec un Framework
Tests fonctionnels
Jest
Jest
39 min

Dans cette vidéo je vous propose de découvrir le framework de test Jest. Il a l'avantage de fonctionner simplement (pas/peu de configuration nécessaire) et rapidement gràce à sa capacité d'éxécuter les tests en parallèle.

L'installation

L'installation se fait simplement à l'aide de votre paquets. Vous pouvez aussi installer les fichiers de déclarations pour aider votre éditeur.

yarn add -D jest @types/jest

Vous pouvez aussi en profiter pour créer un fichier de configuration automatiquement avec la commande.

npx jest --init

Pour lancer les tests il vous suffit ensuite d'utiliser la commande jest ou d'utiliser le script test (si vous avez choisi de l'ajouter à votre package.json)

npx jest

Cette commande cherchera les fichiers se terminant par .test.js ou se trouvant dans le dossier __tests__ et essaiera de les éxécuter.

Structure de base

Contrairements aux autres frameworks de tests que l'on a vu jusqu'à maintenant. Jest intègre l'ensemble des fonctions nécessaires aux test.

  • describe() pour définir un scénario
  • it() ou test() pour décrire un test
  • expect() pour gérer les assertions

Il est intéréssant de noter que Jest supporte les tests asynchrones par défaut. Il suffit de déclarer le callback comme une fonction asynchrone pour ce genre de situation.

describe('Timer', function () {

  it.concurrent('should wait 3 seconds', async function () {
    const t = Date.now()
    await sleep(3)
    expect(Date.now() - t).toBeGreaterThanOrEqual(3000)
  })

  it.concurrent('should wait 2 seconds', async function () {
    const t = Date.now()
    await sleep(2)
    expect(Date.now() - t).toBeGreaterThanOrEqual(2000)
  })

})

Mocker pour mieux tester

Vous pouvez aussi créer des mock pour tester vos fonctions sans dépendre des composants tiers. Par exemple, si vous voulez tester une fonction de votre bot Discord il faut être capable de simuler les opérations.

Pour créer un mock il suffit d'utiliser la fonction Jest.fn(), cette fonction renvoie un mock qui est une fonction qui renvoie undefined si appellée. Il est possible ensuite d'inspecter les appels et de modifier les valeurs de retour si nécessaire.

import {ping} from '../src/discord.js'

describe('Discord', function () {

  it('should dm the user', async function () {
    const channelMock = {
      send: jest.fn()
    }
    const createDMMock = jest.fn().mockResolvedValue(channelMock)
    const message = {
      delete: jest.fn().mockResolvedValue({}),
      reply: jest.fn(),
      author: {
        createDM: createDMMock
      }
    }
    await ping(message)
    expect(message.delete).toHaveBeenCalled()
    expect(channelMock.send).toHaveBeenCalledWith('pong')
  })

  it('should reply to the user if dm are deactivated', async function () {
    const createDMMock = jest.fn().mockRejectedValue({})
    const message = {
      delete: jest.fn().mockResolvedValue({}),
      reply: jest.fn(),
      author: {
        createDM: createDMMock
      }
    }
    await ping(message)
    expect(message.delete).toHaveBeenCalled()
    expect(message.reply).toHaveBeenCalledWith('pong')
  })

})

En revanche, parfois le script à tester utilise une dépendance qui n'est pas exposée depuis l'extérieur (comme axios par exemple). Il est tout de même possible de tester les choses avec Jest.
Pour cela on utilisera la méthode jest.mock() qui remplacera la dépendance par un mock lorsqu'elle sera demandée (il faudra bien penser à nettoyer le mock avant chaque test).

import Users from '../src/users.js'
import axios from 'axios'

jest.mock('axios')

describe('Users', function () {

  beforeEach(() => {
    axios.mockClear()
  })

  const fakeResponse = [{name: 'John Doe'}]

  it ('should return last user', async () => {
    axios.get.mockResolvedValue({data: fakeResponse})
    expect(await Users.getLastUserName()).toBe('John Doe')
  })

})

Si votre code cible les navigateurs et que vous utilisez fetch() vous pourrez tout de même le mocker à l'aide du package jest-fetch-mock.

Tester le DOM sans navigateur via JSDOM

Enfin si votre librairie manipule le DOM il est possible de la tester sans forcément utiliser un navigateur. Pour cela Jest intègre jsdom qui implémente plusieurs standard web directement sur NodeJS.

test('displays content after click', function () {

  document.body.innerHTML = `<div>Voici mon <span class="spoiler">contenu caché</span></div>`
  require('../src/spoiler.js')
  const spoilerButton = document.querySelector('.spoiler button')
  const spoilerText = document.querySelector('.spoiler span')

  expect(spoilerButton).not.toBeNull()
  expect(spoilerText).not.toBeNull()
  expect(spoilerText).not.toHaveClass('visible')
  spoilerButton.click()
  expect(spoilerText).toHaveClass('visible')

})