addons/shared/__tests__/debounce.test.tsblame
View source
b69ab311/**
b69ab312 * Copyright (c) Meta Platforms, Inc. and affiliates.
b69ab313 *
b69ab314 * This source code is licensed under the MIT license found in the
b69ab315 * LICENSE file in the root directory of this source tree.
b69ab316 */
b69ab317
b69ab318import {debounce} from '../debounce';
b69ab319
b69ab3110describe('debounce', () => {
b69ab3111 let func1: jest.Mock<[number, string]>;
b69ab3112 const BUFFER = 10;
b69ab3113
b69ab3114 beforeEach(() => {
b69ab3115 jest.resetModules();
b69ab3116 func1 = jest.fn();
b69ab3117 jest.useFakeTimers();
b69ab3118 });
b69ab3119
b69ab3120 function argsEquivalent(args1: Array<unknown>, args2: Array<unknown>) {
b69ab3121 for (let i = 0; i < Math.max(args1.length, args2.length); i++) {
b69ab3122 if (args1[i] != args2[i]) {
b69ab3123 return false;
b69ab3124 }
b69ab3125 }
b69ab3126 return true;
b69ab3127 }
b69ab3128
b69ab3129 function assertCalledWith(...origargs: Array<unknown>) {
b69ab3130 const args = [].slice.call(origargs);
b69ab3131 expect(func1.mock.calls.some(call => argsEquivalent(args, call))).toBeTruthy();
b69ab3132 }
b69ab3133
b69ab3134 it('should not call until the wait is over', () => {
b69ab3135 const wait = 200;
b69ab3136 const debounced = debounce(func1, wait);
b69ab3137 debounced(1, 'a');
b69ab3138 expect(func1).not.toBeCalled();
b69ab3139
b69ab3140 jest.advanceTimersByTime(wait + BUFFER);
b69ab3141 assertCalledWith(1, 'a');
b69ab3142
b69ab3143 // make sure that subsequent function isn't called right away
b69ab3144 debounced(2, 'a');
b69ab3145 expect(func1.mock.calls.length).toBe(1);
b69ab3146 jest.clearAllTimers();
b69ab3147 });
b69ab3148
b69ab3149 it('should only call the last function per batch', () => {
b69ab3150 const wait = 200;
b69ab3151 const debounced = debounce(func1, wait);
b69ab3152 debounced(1, 'a');
b69ab3153 expect(func1).not.toBeCalled();
b69ab3154 jest.advanceTimersByTime(100);
b69ab3155 debounced(2, 'a');
b69ab3156 jest.advanceTimersByTime(100);
b69ab3157 debounced(3, 'a');
b69ab3158 jest.advanceTimersByTime(100);
b69ab3159 debounced(4, 'a');
b69ab3160 jest.advanceTimersByTime(100);
b69ab3161 debounced(5, 'a');
b69ab3162 expect(jest.getTimerCount()).toBe(1);
b69ab3163 jest.advanceTimersByTime(wait + BUFFER);
b69ab3164 assertCalledWith(5, 'a');
b69ab3165 debounced(6, 'a');
b69ab3166 debounced(7, 'a');
b69ab3167 jest.advanceTimersByTime(wait + BUFFER);
b69ab3168 assertCalledWith(7, 'a');
b69ab3169 expect(func1.mock.calls.length).toBe(2);
b69ab3170 });
b69ab3171
b69ab3172 it('should be reset-able', () => {
b69ab3173 const wait = 300;
b69ab3174 const debounced = debounce(func1, wait);
b69ab3175 debounced(1, 'a');
b69ab3176 debounced.reset();
b69ab3177 expect(jest.getTimerCount()).toBe(0);
b69ab3178 jest.runAllTimers();
b69ab3179 expect(func1).not.toBeCalled();
b69ab3180 });
b69ab3181
b69ab3182 it('should correctly show if the timeout is pending', () => {
b69ab3183 const wait = 300;
b69ab3184 const debounced = debounce(func1, wait);
b69ab3185 expect(debounced.isPending()).toBe(false);
b69ab3186 debounced(1, 'a');
b69ab3187 debounced(1, 'a');
b69ab3188 expect(debounced.isPending()).toBe(true);
b69ab3189 jest.runAllTimers();
b69ab3190 expect(func1.mock.calls.length).toBe(1);
b69ab3191 expect(debounced.isPending()).toBe(false);
b69ab3192 });
b69ab3193
b69ab3194 describe('leading', () => {
b69ab3195 it('should call the function immediately if able', () => {
b69ab3196 const wait = 300;
b69ab3197 const debounced = debounce(func1, wait, undefined, true);
b69ab3198 debounced(1, 'a');
b69ab3199 expect(func1).toBeCalled();
b69ab31100 });
b69ab31101 it('should gate consecutive calls within the wait time', () => {
b69ab31102 const wait = 300;
b69ab31103 const debounced = debounce(func1, wait, undefined, true);
b69ab31104 debounced(1, 'a');
b69ab31105 debounced(1, 'a');
b69ab31106 debounced(1, 'a');
b69ab31107 debounced(1, 'a');
b69ab31108 debounced(1, 'a');
b69ab31109 expect(func1).toBeCalledTimes(1);
b69ab31110 });
b69ab31111 it('should call the function immediately after the wait time', () => {
b69ab31112 const wait = 300;
b69ab31113 const debounced = debounce(func1, wait, undefined, true);
b69ab31114 debounced(1, 'a');
b69ab31115 debounced(1, 'a');
b69ab31116 debounced(1, 'a');
b69ab31117 debounced(1, 'a');
b69ab31118 debounced(1, 'a');
b69ab31119 expect(func1).toBeCalledTimes(1);
b69ab31120 jest.advanceTimersByTime(wait + BUFFER);
b69ab31121 debounced(1, 'a');
b69ab31122 debounced(1, 'a');
b69ab31123 debounced(1, 'a');
b69ab31124 debounced(1, 'a');
b69ab31125 debounced(1, 'a');
b69ab31126 expect(func1).toBeCalledTimes(2);
b69ab31127 });
b69ab31128 it('should extend the wait time whenever it is called within the wait time', () => {
b69ab31129 const wait = 300;
b69ab31130 const debounced = debounce(func1, wait, undefined, true);
b69ab31131 debounced(1, 'a');
b69ab31132 expect(func1).toBeCalledTimes(1);
b69ab31133 jest.advanceTimersByTime(wait - BUFFER);
b69ab31134 debounced(1, 'a');
b69ab31135 expect(func1).toBeCalledTimes(1);
b69ab31136 jest.advanceTimersByTime(wait - BUFFER);
b69ab31137 debounced(1, 'a');
b69ab31138 expect(func1).toBeCalledTimes(1);
b69ab31139 jest.advanceTimersByTime(wait + BUFFER);
b69ab31140 debounced(1, 'a');
b69ab31141 expect(func1).toBeCalledTimes(2);
b69ab31142 });
b69ab31143 });
b69ab31144});