import { createDebounceManager } from '../createDebounceManager';

describe('Utils/Function/createDebounceManager', () => {
    it('invokeDebounced debounces the function (calls it once with the last arguments)', async () => {
        let callback = jest.fn();
        const syncPromise = new Promise(resolve => {
            callback.mockImplementation(resolve);
        });
        const debounceManager = createDebounceManager(callback, 100);
        setTimeout(() => debounceManager.invokeDebounced('call#1'), 50);
        setTimeout(() => debounceManager.invokeDebounced('call#2'), 100);
        setTimeout(() => debounceManager.invokeDebounced('call#3'), 150);
        await syncPromise;
        expect(callback).not.toHaveBeenCalledWith('call#1');
        expect(callback).not.toHaveBeenCalledWith('call#2');
        expect(callback).toHaveBeenCalledWith('call#3');
    });
    it('invokeSync calls the given function immediately and clears previous invocations', () => {
        let callback = jest.fn();
        const debounceManager = createDebounceManager(callback, 100);
        debounceManager.invokeDebounced('debounced');
        debounceManager.invokeSync('synced');
        expect(callback).not.toHaveBeenCalledWith('debounced');
        expect(callback).toHaveBeenCalledWith('synced');
    });
    it('sync calls the debounced function immediately', () => {
        let callback = jest.fn();
        const debounceManager = createDebounceManager(callback, 100);
        debounceManager.invokeDebounced('debounced');
        debounceManager.sync();
        expect(callback).toHaveBeenCalledWith('debounced');
    });
    it('sync and invokeSync forward the result of the callback function (eg. waiting for api request)', async () => {
        let callback = jest.fn();
        callback.mockImplementation(
            name =>
                new Promise(resolve => {
                    setTimeout(() => resolve('the loaded result ' + name), 300);
                })
        );
        const debounceManager = createDebounceManager(callback, 100);
        debounceManager.invokeDebounced('debounced');
        const resultSync = await debounceManager.sync();
        expect(callback).toHaveBeenCalledWith('debounced');
        expect(resultSync).toBe('the loaded result debounced');

        const resultInvokeSync = await debounceManager.invokeSync('synced');
        expect(callback).toHaveBeenCalledWith('synced');
        expect(resultInvokeSync).toBe('the loaded result synced');
    });
    it('sync does not call the callback before it was called with debounce', () => {
        let callback = jest.fn();
        const debounceManager = createDebounceManager(callback, 100);
        debounceManager.sync();
        expect(callback).not.toHaveBeenCalled();
    });
});
