Jest unit test for a debounce function

前端 未结 4 2018
萌比男神i
萌比男神i 2021-02-13 22:30

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:



        
相关标签:
4条回答
  • 2021-02-13 23:06

    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

    0 讨论(0)
  • 2021-02-13 23:08

    I like this similar version easier to have failing:

    jest.useFakeTimers();
    test('execute just once', () => {
        const func = jest.fn();
        const debouncedFunc = debounce(func, 500);
    
        // Execute for the first time
        debouncedFunc();
    
        // Move on the timer
        jest.advanceTimersByTime(250);
        // try to execute a 2nd time
        debouncedFunc();
    
        // Fast-forward time
        jest.runAllTimers();
    
        expect(func).toBeCalledTimes(1);
    });
    
    0 讨论(0)
  • 2021-02-13 23:23

    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
    });
    
    0 讨论(0)
  • 2021-02-13 23:24

    If in your code you are doing so:

    import debounce from 'lodash/debounce';
    
    myFunc = debounce(myFunc, 300);
    

    and you want to test the function myFunc or a function calling it, then in your test you can mock the implementation of debounce using jest to make it just return your function:

    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 to execute the function given to you
        // ...
    });
    

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

    0 讨论(0)
提交回复
热议问题