web-dev-qa-db-fra.com

Test unitaire Jest pour une fonction anti-rebond

J'essaie d'écrire un test unitaire pour la fonction anti-rebond. J'ai du mal à y penser.

Voici le code:

function debouncer(func, wait, immediate) {
  let timeout;

  return (...args) => {
    clearTimeout(timeout);

    timeout = setTimeout(() => {
      timeout = null;
      if (!immediate) func.apply(this, args);
    }, wait);

    if (immediate && !timeout) func.apply(this, args);
  };
}

Comment dois-je commencer?

6
RecipeCreator

Vous voudrez probablement vérifier la logique de votre fonction anti-rebond:

Cela dit, il semble que votre vraie question concerne le test des fonctions anti-rebond.

Test des fonctions anti-rebond

Vous pouvez tester qu'une fonction est anti-rebond en utilisant une maquette pour suivre les appels de fonction et de faux minuteries pour simuler le passage du temps.

Voici un exemple simple utilisant une fonction Jest Mock Function et Sinon fake timers d'une fonction rebondie en utilisant debounce() de Lodash :

const _ = require('lodash');
import * as sinon from 'sinon';

let clock;

beforeEach(() => {
  clock = sinon.useFakeTimers();
});

afterEach(() => {
  clock.restore();
});

test('debounce', () => {
  const func = jest.fn();
  const debouncedFunc = _.debounce(func, 1000);

  // Call it immediately
  debouncedFunc();
  expect(func).toHaveBeenCalledTimes(0); // func not called

  // Call it several times with 500ms between each call
  for(let i = 0; i < 10; i++) {
    clock.tick(500);
    debouncedFunc();
  }
  expect(func).toHaveBeenCalledTimes(0); // func not called

  // wait 1000ms
  clock.tick(1000);
  expect(func).toHaveBeenCalledTimes(1);  // func called
});
10
Brian Adams

En fait, vous n'avez pas besoin d'utiliser Sinon pour tester les rebonds. Jest peut se moquer de tous les temporisateurs en code JS.

Consultez le code suivant (c'est TypeScript, mais vous pouvez facilement le traduire en JS):

import * as _ from 'lodash';

// tell jest to mock all timeout functions
jest.useFakeTimers();

describe('debounce', () => {

    let func: jest.Mock;
    let debouncedFunc: Function;

    beforeEach(() => {
        func = jest.fn();
        debouncedFunc = _.debounce(func, 1000);
    });

    test('execute just once', () => {
        for (let i = 0; i < 100; i++) {
            debouncedFunc();
        }

        // fast-forward time
        jest.runAllTimers();

        expect(func).toBeCalledTimes(1);
    });
});

Plus d'informations: https://jestjs.io/docs/en/timer-mocks.html

4
tswistak

Si dans votre code vous le faites:

import debounce from 'lodash/debounce';

myFunc = debounce(myFunc, 300);

et vous voulez tester la fonction myFunc ou une fonction qui l'appelle, alors dans votre test vous pouvez vous moquer de l'implémentation de debounce en utilisant jest pour qu'elle revienne simplement à votre fonction:

import debounce from 'lodash/debounce';

// Tell jest to mock this import
jest.mock('lodash/debounce');

it('my test', () => {
    // ...
    debounce.mockImplementation(fn => fn); // Assign the import a new implementation, in this case it's execute the function given to you
    // ...
});

Source: https://Gist.github.com/apieceofbart/d28690d52c46848c39d904ce8968bb27

3
Mis94

Je ne sais pas comment cela fonctionnerait avec Jest puisque j'utilise du moka, mais pour tous ceux qui recherchent une solution simple:

it('debounce.spec', done => {
    // Arrange
    const log = sinon.spy();
    const search = debounce(log, 100);

    // Act
    search();

    // Assert
    setTimeout(() => {
      expect(log.called).to.be.true;
      done();
    }, 100);
  });
0
marrion luaka