Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jest unit test for a debounce function

Tags:

I am trying to write a unit test for a debounce function. I'm having a hard time thinking about it.

This is the 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);   }; } 

How should I start?

like image 388
RecipeCreator Avatar asked Sep 07 '18 14:09

RecipeCreator


People also ask

How do you mock debounce in jest?

You can test that a function is debounced by using a mock to track function calls and fake timers to simulate the passage of time. is there a way to make it done without sinon? using Jest Timers Mocks (jestjs.io/docs/en/timer-mocks)?

How do you use debounce function?

The debounce() function forces a function to wait a certain amount of time before running again. The function is built to limit the number of times a function is called. The Send Request() function is debounced. Requests are sent only after fixed time intervals regardless of how many times the user presses the button.

Can jest be used for unit testing?

Jest JavaScript resting framework with a focus on simplicity. Jest was created by Facebook engineers for its React project. Unit testing is a software testing where individual units (components) of a software are tested. The purpose of unit testing is to validate that each unit of the software performs as designed.


2 Answers

Actually, you don't need to use Sinon to test debounces. Jest can mock all timers in JavaScript code.

Check out following code (it's TypeScript, but you can easily translate it to JavaScript):

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);     }); }); 

More information: Timer Mocks

like image 71
tswistak Avatar answered Sep 20 '22 17:09

tswistak


You will probably want to check the logic in your debouncer function:

  • timeout will always be set by that last if() statement
  • this will always be undefined since arrow functions use "the this value of the enclosing lexical context" and debouncer() is designed to be used as a stand-alone function.

Having said that, it sounds like your real question is about testing debounced functions.

Testing debounced functions

You can test that a function is debounced by using a mock to track function calls and fake timers to simulate the passage of time.

Here is a simple example using a Jest Mock Function and Sinon fake timers of a function debounced using debounce() from 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 }); 
like image 22
Brian Adams Avatar answered Sep 24 '22 17:09

Brian Adams