Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
351 views
in Technique[技术] by (71.8m points)

javascript - How do I create a unit test case to get maximum code coverage for my debounce and throttle function using jest?

I need to write unit tests for the library to get maximum code coverage - both line coverage and branch coverage.

export const throttle = (fn, delay) => {
    let last = 0;
    return (...args) => {
        const now = new Date().getTime();
        if(now - last < delay) {
            return;
        }
        last = now;
        return fn(...args);
    }
}


export const debounce = ( fn, delay) => {
    let timeoutID;
    return function(...args){
        if (timeoutID){
            clearTimeout(timeoutID);
        }
        timeoutID = setTimeout( () => {
            fn(...args);  
        }, delay);
    };
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

You don't need DOM related thing for unit testing. For testing throttle, you should mock the Date. For testing debounce, you should use fake timers. Date and setTimeout have side effects, we should mock them to get rid of side effects.

throttle.js:

export const throttle = (fn, delay) => {
  let last = 0;
  return (...args) => {
    const now = new Date().getTime();
    if (now - last < delay) {
      return;
    }
    last = now;
    return fn(...args);
  };
};

throttle.test.js:

import { throttle } from './throttle';

describe('65593662', () => {
  describe('throttle', () => {
    afterEach(() => {
      jest.restoreAllMocks();
    });
    it('should call function if now - last > delay', () => {
      const fn = jest.fn();
      const throttledFn = throttle(fn, 1000);
      const getTimeSpy = jest.spyOn(Date.prototype, 'getTime').mockReturnValue(2000);
      throttledFn('param');
      expect(fn).toBeCalledWith('param');
      expect(getTimeSpy).toBeCalledTimes(1);
    });

    it('should call function if now - last = delay', () => {
      const fn = jest.fn();
      const throttledFn = throttle(fn, 1000);
      const getTimeSpy = jest.spyOn(Date.prototype, 'getTime').mockReturnValue(1000);
      throttledFn('param');
      expect(fn).toBeCalledWith('param');
      expect(getTimeSpy).toBeCalledTimes(1);
    });

    it('should not call function if now - last < delay', () => {
      const fn = jest.fn();
      const throttledFn = throttle(fn, 1000);
      const getTimeSpy = jest.spyOn(Date.prototype, 'getTime').mockReturnValue(100);
      throttledFn('param');
      expect(fn).not.toBeCalled();
      expect(getTimeSpy).toBeCalledTimes(1);
    });
  });
});

debounce.js:

export const debounce = (fn, delay) => {
  let timeoutID;
  return function (...args) {
    if (timeoutID) {
      clearTimeout(timeoutID);
    }
    timeoutID = setTimeout(() => {
      fn(...args);
    }, delay);
  };
};

debounce.test.js:

import { debounce } from './debounce';

jest.useFakeTimers();

describe('65593662', () => {
  describe('debounce', () => {
    it('should call function if timeoutID is undefined', () => {
      const fn = jest.fn();

      const debouncedFn = debounce(fn, 1000);
      debouncedFn('param');
      jest.advanceTimersByTime(1000);
      expect(fn).toBeCalledWith('param');
      expect(fn).toBeCalledTimes(1);
    });

    it('should not call function once if timeoutID exists', () => {
      const fn = jest.fn();

      const debouncedFn = debounce(fn, 1000);
      debouncedFn('param');
      debouncedFn('param');
      debouncedFn('param');
      jest.runAllTimers();
      expect(fn).toBeCalledWith('param');
      expect(fn).toBeCalledTimes(1);
    });
  });
});

unit test result:

 PASS  examples/65593662/throttle.test.ts
  65593662
    throttle
      ? should call function if now - last > delay (3 ms)
      ? should call function if now - last = delay
      ? should not call function if now - last < delay (1 ms)

 PASS  examples/65593662/debounce.test.ts
  65593662
    debounce
      ? should call function if timeoutID is undefined (5 ms)
      ? should not call function once if timeoutID exists (1 ms)

-------------|---------|----------|---------|---------|-------------------
File         | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-------------|---------|----------|---------|---------|-------------------
All files    |     100 |      100 |     100 |     100 |                   
 debounce.ts |     100 |      100 |     100 |     100 |                   
 throttle.ts |     100 |      100 |     100 |     100 |                   
-------------|---------|----------|---------|---------|-------------------
Test Suites: 2 passed, 2 total
Tests:       5 passed, 5 total
Snapshots:   0 total
Time:        4.168 s

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...