@stackbit/utils
Version:
Stackbit utilities
627 lines (524 loc) • 27.6 kB
text/typescript
import { jest, describe, expect, test, beforeEach, afterEach } from '@jest/globals';
import './test-utils/toBeWithinRange';
import { deferredPromise, deferWhileRunning } from '../src';
type MockFunction = (arg1: string, arg2: string, arg3: string) => Promise<string>;
function mockHelper(func?: MockFunction) {
return jest.fn(func);
}
function sleep(ms: number) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
describe('deferredPromise', () => {
test('resolves when resolve is called', async () => {
const deferred = deferredPromise();
deferred.resolve('test');
await expect(deferred.promise).resolves.toEqual('test');
});
test('rejects when reject is called', async () => {
const deferred = deferredPromise();
deferred.reject('error');
await expect(deferred.promise).rejects.toEqual('error');
});
});
describe('deferWhileRunning', () => {
beforeEach(() => {
jest.useFakeTimers();
jest.spyOn(global, 'setTimeout');
});
afterEach(() => {
(setTimeout as jest.MockedFunction<typeof setTimeout>).mockClear();
jest.useRealTimers();
});
test('invokes the function immediately if no previous calls were made and resolves with the resolved value', async () => {
const mockFn = mockHelper((arg1, arg2, arg3) => Promise.resolve(arg1 + arg2 + arg3));
const deferred = deferWhileRunning(mockFn);
const result = deferred('a', 'b', 'c');
expect(mockFn.mock.calls.length).toEqual(1);
expect(mockFn.mock.lastCall).toEqual(['a', 'b', 'c']);
await expect(result).resolves.toEqual('abc');
});
test('invokes the function immediately if no previous calls were made and rejects with the rejected value', async () => {
const mockFn = mockHelper((arg1, arg2, arg3) => Promise.reject({ error: arg1 + arg2 + arg3 }));
const deferred = deferWhileRunning(mockFn);
const result = deferred('a', 'b', 'c');
expect(mockFn.mock.calls.length).toEqual(1);
expect(mockFn.mock.lastCall).toEqual(['a', 'b', 'c']);
await expect(result).rejects.toEqual({ error: 'abc' });
});
test('invokes the function immediately if no previous calls were made and rejects with the thrown error', async () => {
const mockFn = mockHelper(async (arg1, arg2, arg3) => {
throw new Error(arg1 + arg2 + arg3);
});
const deferred = deferWhileRunning(mockFn);
const result = deferred('a', 'b', 'c');
expect(mockFn.mock.calls.length).toEqual(1);
expect(mockFn.mock.lastCall).toEqual(['a', 'b', 'c']);
try {
await result;
} catch (e: any) {
expect(e.message).toEqual('abc');
}
});
test('invokes the next function immediately if the previous invocation was resolved', async () => {
const mockFn = jest.fn(async (arg1: string, arg2: string, arg3: string) => arg1 + arg2 + arg3);
const deferred = deferWhileRunning(mockFn);
const result1 = deferred('a', 'b', 'c');
expect(mockFn.mock.calls.length).toEqual(1);
expect(mockFn.mock.lastCall).toEqual(['a', 'b', 'c']);
await expect(result1).resolves.toEqual('abc');
mockFn.mockClear();
const result2 = await deferred('d', 'e', 'f');
expect(mockFn.mock.calls.length).toEqual(1);
expect(mockFn.mock.lastCall).toEqual(['d', 'e', 'f']);
expect(result2).toEqual('def');
});
test('invokes the next function immediately if the previous invocation was rejected', async () => {
const mockFn = mockHelper()
.mockImplementationOnce(async (arg1: string, arg2: string, arg3: string) => {
return Promise.reject({ error: arg1 + arg2 + arg3 });
})
.mockImplementationOnce(async (arg1: string, arg2: string, arg3: string) => {
return arg1 + arg2 + arg3;
});
const deferred = deferWhileRunning(mockFn);
const result1 = deferred('a', 'b', 'c');
expect(mockFn.mock.calls.length).toEqual(1);
expect(mockFn.mock.lastCall).toEqual(['a', 'b', 'c']);
await expect(result1).rejects.toEqual({ error: 'abc' });
mockFn.mockClear();
const result2 = await deferred('d', 'e', 'f');
expect(mockFn.mock.calls.length).toEqual(1);
expect(mockFn.mock.lastCall).toEqual(['d', 'e', 'f']);
expect(result2).toEqual('def');
});
test('debounce the function call and resolves with the resolved value after debounce delay', async () => {
const mockFn = jest.fn(async (arg1: string, arg2: string, arg3: string) => {
return arg1 + arg2 + arg3;
});
const deferred = deferWhileRunning(mockFn, { debounceDelay: 100 });
const result = deferred('a', 'b', 'c');
expect(setTimeout).toHaveBeenCalledTimes(1);
expect(setTimeout).toHaveBeenLastCalledWith(expect.any(Function), 100);
expect(mockFn).not.toBeCalled();
jest.advanceTimersByTime(100);
await expect(result).resolves.toEqual('abc');
expect(mockFn.mock.calls.length).toEqual(1);
expect(mockFn.mock.lastCall).toEqual(['a', 'b', 'c']);
});
test('debounce the function call and rejects with the rejected value after debounce delay', async () => {
const mockFn = jest.fn(async (arg1: string, arg2: string, arg3: string) => {
return Promise.reject({ error: arg1 + arg2 + arg3 });
});
const deferred = deferWhileRunning(mockFn, { debounceDelay: 100 });
const result = deferred('a', 'b', 'c');
expect(setTimeout).toHaveBeenCalledTimes(1);
expect(setTimeout).toHaveBeenLastCalledWith(expect.any(Function), 100);
expect(mockFn).not.toBeCalled();
jest.advanceTimersByTime(100);
await expect(result).rejects.toEqual({ error: 'abc' });
expect(mockFn.mock.calls.length).toEqual(1);
expect(mockFn.mock.lastCall).toEqual(['a', 'b', 'c']);
});
test('debounce the function call and rejects with the thrown error after debounce delay', async () => {
const mockFn = jest.fn(async (arg1: string, arg2: string, arg3: string) => {
throw new Error(arg1 + arg2 + arg3);
});
const deferred = deferWhileRunning(mockFn, { debounceDelay: 100 });
const result = deferred('a', 'b', 'c');
expect(setTimeout).toHaveBeenCalledTimes(1);
expect(setTimeout).toHaveBeenLastCalledWith(expect.any(Function), 100);
expect(mockFn).not.toBeCalled();
jest.advanceTimersByTime(100);
await expect(result).rejects.toThrow('abc');
expect(mockFn.mock.calls.length).toEqual(1);
expect(mockFn.mock.lastCall).toEqual(['a', 'b', 'c']);
});
test('debounce the function three times then invokes the function with the last provided arguments and resolves all calls after debounce delay', async () => {
const mockFn = jest.fn(async (arg1: string) => arg1);
const deferred = deferWhileRunning(mockFn, { debounceDelay: 150 });
// first call is debounced for 150ms
const result1 = deferred('a');
expect(setTimeout).toHaveBeenCalledTimes(1);
expect(setTimeout).toHaveBeenLastCalledWith(expect.any(Function), 150);
expect(mockFn).not.toBeCalled();
jest.advanceTimersByTime(100);
// second call is made after 100ms, debounced for 150ms, and scheduled for 250ms (from start)
const result2 = deferred('b');
expect(setTimeout).toHaveBeenCalledTimes(2);
expect(setTimeout).toHaveBeenLastCalledWith(expect.any(Function), 150);
expect(mockFn).not.toBeCalled();
jest.advanceTimersByTime(100);
// third call is made after 200ms (from start), debounced for 150ms, and scheduled for 350ms (from start)
const result3 = deferred('c');
expect(setTimeout).toHaveBeenCalledTimes(3);
expect(setTimeout).toHaveBeenLastCalledWith(expect.any(Function), 150);
expect(mockFn).not.toBeCalled();
jest.advanceTimersByTime(150);
await expect(result1).resolves.toEqual('c');
await expect(result2).resolves.toEqual('c');
await expect(result3).resolves.toEqual('c');
expect(mockFn.mock.calls.length).toEqual(1);
expect(mockFn.mock.calls[0]).toEqual(['c']);
});
test('debounce the function twice then invokes the function due to debounceMaxDelay, then defers the third call until the previous invocation is resolved', async () => {
const mockFn = jest.fn(async (arg1: string) => {
await sleep(100);
return arg1;
});
const deferred = deferWhileRunning(mockFn, {
debounceDelay: 200,
debounceMaxDelay: 300
});
// const deferred = deferWhileRunning(mockFn);
//
// mockFn('b') mockFn('c')
// ↓ ↓
// o------ debounce delay -------●o========●o=========●
// o---------------------------------------●
// ↑ o------------------------●
// ↑ ↑ o---------------●
// ↑ ↑ ↑
// time:--0---------100--150--200-------300--350--400--------------->
// ↑ ↑ ↑
// deferred('a') deferred('b') deferred('c')
// first call is debounced for 300ms
const result1 = deferred('a');
expect(setTimeout).toHaveBeenCalledTimes(1);
expect(setTimeout).toHaveBeenLastCalledWith(expect.any(Function), 200);
expect(mockFn).not.toBeCalled();
// second call is made after 150ms, debounced for 150ms because max debounce delay is 300ms,
// and scheduled for 300ms (from start) and runs for 100ms
jest.advanceTimersByTime(150);
const result2 = deferred('b');
expect(setTimeout).toHaveBeenCalledTimes(2);
expect(setTimeout).toHaveBeenLastCalledWith(expect.any(Function), 150);
expect(mockFn).not.toBeCalled();
jest.advanceTimersByTime(150);
expect(mockFn).toHaveBeenCalledTimes(1);
expect(mockFn).toHaveBeenLastCalledWith('b');
// this setTimeout called from within the mocked function
expect(setTimeout).toHaveBeenCalledTimes(3);
expect(setTimeout).toHaveBeenLastCalledWith(expect.any(Function), 100);
// third call is made after 350ms (from start) while the second call is running,
// so this call will be deferred until after the second call invocation completes
// which will be at 400ms from the start
jest.advanceTimersByTime(50);
const result3 = deferred('c');
expect(mockFn).toHaveBeenCalledTimes(1);
expect(setTimeout).toHaveBeenCalledTimes(3);
jest.advanceTimersByTime(50);
await expect(result1).resolves.toEqual('b');
await expect(result2).resolves.toEqual('b');
expect(setTimeout).toHaveBeenCalledTimes(4);
expect(setTimeout).toHaveBeenLastCalledWith(expect.any(Function), 100);
jest.advanceTimersByTime(100);
expect(mockFn).toHaveBeenCalledTimes(2);
expect(mockFn).toHaveBeenLastCalledWith('c');
await expect(result3).resolves.toEqual('c');
});
test('debounce the function three times then invokes the function with arguments as defined by the argsResolver then resolves with the resolved value after debounce delay', async () => {
const mockFn = jest.fn(async (arg1: string, arg2: number) => {
return [arg1, arg2];
});
const deferred = deferWhileRunning(mockFn, {
debounceDelay: 200,
argsResolver: ({ nextArgs, prevArgs }) => {
return prevArgs ? ([prevArgs[0] + nextArgs[0], prevArgs[1] + nextArgs[1]] as [string, number]) : nextArgs;
}
});
// const deferred = deferWhileRunning(mockFn);
//
// mockFn('abc', 6)
// ↓
// o------ debounce delay -------●o===●
// o-----------------------------●
// ↑ o-------------------●
// ↑ ↑ o---------●
// ↑ ↑ ↑
// time:--0---------100-------200-------300----->
// ↑ ↑ ↑
// ↑ ↑ deferred('c', 3)
// ↑ deferred('a', 2)
// deferred('a', 1)
// first call is debounced for 200ms
const result1 = deferred('a', 1);
expect(setTimeout).toHaveBeenCalledTimes(1);
expect(setTimeout).toHaveBeenLastCalledWith(expect.any(Function), 200);
expect(mockFn).not.toBeCalled();
// second call is made after 100ms, debounced for 200ms, and scheduled for 300ms (from start)
jest.advanceTimersByTime(100);
const result2 = deferred('b', 2);
expect(setTimeout).toHaveBeenCalledTimes(2);
expect(setTimeout).toHaveBeenLastCalledWith(expect.any(Function), 200);
expect(mockFn).not.toBeCalled();
// third call is made after 200ms (from start), debounced for 200ms, and scheduled for 400ms (from start)
jest.advanceTimersByTime(100);
const result3 = deferred('c', 3);
expect(setTimeout).toHaveBeenCalledTimes(3);
expect(setTimeout).toHaveBeenLastCalledWith(expect.any(Function), 200);
expect(mockFn).not.toBeCalled();
jest.advanceTimersByTime(200);
await expect(result1).resolves.toEqual(['abc', 6]);
await expect(result2).resolves.toEqual(['abc', 6]);
await expect(result3).resolves.toEqual(['abc', 6]);
expect(mockFn.mock.calls.length).toEqual(1);
expect(mockFn.mock.calls[0]).toEqual(['abc', 6]);
});
test('defers the next function call until the previous invocation is resolved', async () => {
const wait = deferredPromise<void>();
const mockFn = jest.fn(async (arg1: string, arg2: string, arg3: string) => {
await wait.promise;
return arg1 + arg2 + arg3;
});
const deferred = deferWhileRunning(mockFn);
const result1 = deferred('a', 'b', 'c');
const result2 = deferred('d', 'e', 'f');
expect(mockFn.mock.calls.length).toEqual(1);
expect(mockFn.mock.lastCall).toEqual(['a', 'b', 'c']);
mockFn.mockClear();
wait.resolve();
await expect(result1).resolves.toEqual('abc');
await expect(result2).resolves.toEqual('def');
expect(mockFn.mock.calls.length).toEqual(1);
expect(mockFn.mock.lastCall).toEqual(['d', 'e', 'f']);
});
test('defers the next function call until the previous invocation is rejected', async () => {
const wait = deferredPromise<void>();
const mockFn = mockHelper()
.mockImplementationOnce(async (arg1: string, arg2: string, arg3: string) => {
await wait.promise;
return Promise.reject({ error: arg1 + arg2 + arg3 });
})
.mockImplementationOnce(async (arg1: string, arg2: string, arg3: string) => {
return arg1 + arg2 + arg3;
});
const deferred = deferWhileRunning(mockFn);
const result1 = deferred('a', 'b', 'c');
const result2 = deferred('d', 'e', 'f');
expect(mockFn.mock.calls.length).toEqual(1);
expect(mockFn.mock.lastCall).toEqual(['a', 'b', 'c']);
mockFn.mockClear();
wait.resolve();
await expect(result1).rejects.toEqual({ error: 'abc' });
await expect(result2).resolves.toEqual('def');
expect(mockFn.mock.calls.length).toEqual(1);
expect(mockFn.mock.lastCall).toEqual(['d', 'e', 'f']);
});
test('defers the next function call until the previous invocation throws', async () => {
const wait = deferredPromise<void>();
const mockFn = mockHelper()
.mockImplementationOnce(async (arg1: string, arg2: string, arg3: string) => {
await wait.promise;
throw new Error(arg1 + arg2 + arg3);
})
.mockImplementationOnce(async (arg1: string, arg2: string, arg3: string) => {
return arg1 + arg2 + arg3;
});
const deferred = deferWhileRunning(mockFn);
const result1 = deferred('a', 'b', 'c');
const result2 = deferred('d', 'e', 'f');
expect(mockFn.mock.calls.length).toEqual(1);
expect(mockFn.mock.lastCall).toEqual(['a', 'b', 'c']);
mockFn.mockClear();
wait.resolve();
try {
await result1;
} catch (e: any) {
expect(e.message).toEqual('abc');
}
await expect(result2).resolves.toEqual('def');
expect(mockFn.mock.calls.length).toEqual(1);
expect(mockFn.mock.lastCall).toEqual(['d', 'e', 'f']);
});
test(
'defers multiple function calls until the previous invocation is resolved,' +
'then invokes the function with the last provided arguments and resolves all calls',
async () => {
const wait = deferredPromise<void>();
const mockFn = jest.fn(async (arg1: string, arg2: string, arg3: string) => {
await wait.promise;
return arg1 + arg2 + arg3;
});
const deferred = deferWhileRunning(mockFn);
const result1 = deferred('a', 'b', 'c');
const result2 = deferred('d', 'e', 'f');
const result3 = deferred('g', 'h', 'i');
const result4 = deferred('j', 'k', 'l');
expect(mockFn.mock.calls.length).toEqual(1);
expect(mockFn.mock.lastCall).toEqual(['a', 'b', 'c']);
mockFn.mockClear();
wait.resolve();
await expect(result1).resolves.toEqual('abc');
await expect(result2).resolves.toEqual('jkl');
await expect(result3).resolves.toEqual('jkl');
await expect(result4).resolves.toEqual('jkl');
expect(mockFn.mock.calls.length).toEqual(1);
expect(mockFn.mock.lastCall).toEqual(['j', 'k', 'l']);
}
);
test(
'defers multiple function calls until the previous invocation is resolved,' +
'then invokes the function with the last provided arguments and rejects all calls',
async () => {
const wait = deferredPromise<void>();
const mockFn = mockHelper()
.mockImplementationOnce(async (arg1: string, arg2: string, arg3: string) => {
await wait.promise;
return arg1 + arg2 + arg3;
})
.mockImplementationOnce(async (arg1: string, arg2: string, arg3: string) => {
return Promise.reject({ error: arg1 + arg2 + arg3 });
});
const deferred = deferWhileRunning(mockFn);
const result1 = deferred('a', 'b', 'c');
const result2 = deferred('d', 'e', 'f');
const result3 = deferred('g', 'h', 'i');
const result4 = deferred('j', 'k', 'l');
expect(mockFn.mock.calls.length).toEqual(1);
expect(mockFn.mock.lastCall).toEqual(['a', 'b', 'c']);
mockFn.mockClear();
wait.resolve();
await expect(result1).resolves.toEqual('abc');
await expect(result2).rejects.toEqual({ error: 'jkl' });
await expect(result3).rejects.toEqual({ error: 'jkl' });
await expect(result4).rejects.toEqual({ error: 'jkl' });
expect(mockFn.mock.calls.length).toEqual(1);
expect(mockFn.mock.lastCall).toEqual(['j', 'k', 'l']);
}
);
test(
'defers multiple function calls until the previous invocation is rejected, ' +
'then invokes the function with the last provided arguments and resolves all calls',
async () => {
const wait = deferredPromise<void>();
const mockFn = mockHelper()
.mockImplementationOnce(async (arg1: string, arg2: string, arg3: string) => {
await wait.promise;
return Promise.reject({ error: arg1 + arg2 + arg3 });
})
.mockImplementationOnce(async (arg1: string, arg2: string, arg3: string) => {
return arg1 + arg2 + arg3;
});
const deferred = deferWhileRunning(mockFn);
const result1 = deferred('a', 'b', 'c');
const result2 = deferred('d', 'e', 'f');
const result3 = deferred('g', 'h', 'i');
const result4 = deferred('j', 'k', 'l');
expect(mockFn.mock.calls.length).toEqual(1);
expect(mockFn.mock.lastCall).toEqual(['a', 'b', 'c']);
mockFn.mockClear();
wait.resolve();
await expect(result1).rejects.toEqual({ error: 'abc' });
await expect(result2).resolves.toEqual('jkl');
await expect(result3).resolves.toEqual('jkl');
await expect(result4).resolves.toEqual('jkl');
expect(mockFn.mock.calls.length).toEqual(1);
expect(mockFn.mock.lastCall).toEqual(['j', 'k', 'l']);
}
);
test('invokes the function immediately if no previous calls in the same group made and resolves with the resolved value', async () => {
const mockFn = jest.fn(async (arg1: string, arg2: string, arg3: string) => {
return arg1 + '-' + arg2 + arg3;
});
const deferred = deferWhileRunning(mockFn, {
groupResolver: (group: string) => group
});
const result1 = deferred('group1', 'a', 'b');
const result2 = deferred('group2', 'c', 'd');
const result3 = deferred('group3', 'e', 'f');
expect(mockFn.mock.calls.length).toEqual(3);
expect(mockFn.mock.calls[0]).toEqual(['group1', 'a', 'b']);
expect(mockFn.mock.calls[1]).toEqual(['group2', 'c', 'd']);
expect(mockFn.mock.calls[2]).toEqual(['group3', 'e', 'f']);
await expect(result1).resolves.toEqual('group1-ab');
await expect(result2).resolves.toEqual('group2-cd');
await expect(result3).resolves.toEqual('group3-ef');
});
test(
'defers multiple function calls in a group until the previous invocation in the same group is resolved,' +
'then invokes the function with the last provided arguments to the group and resolves all group calls',
async () => {
const wait = deferredPromise<void>();
const mockFn = jest.fn(async (arg1: string, arg2: string, arg3: string) => {
await wait.promise;
return arg1 + '-' + arg2 + arg3;
});
const deferred = deferWhileRunning(mockFn, {
groupResolver: (group: string) => group
});
const result1a = deferred('group1', 'a', 'b');
const result1b = deferred('group1', 'c', 'd');
const result1c = deferred('group1', 'e', 'f');
const result2a = deferred('group2', 'a', 'b');
const result2b = deferred('group2', 'c', 'd');
const result2c = deferred('group2', 'e', 'f');
const result3a = deferred('group3', 'a', 'b');
const result3b = deferred('group3', 'c', 'd');
const result3c = deferred('group3', 'e', 'f');
expect(mockFn.mock.calls.length).toEqual(3);
expect(mockFn.mock.calls[0]).toEqual(['group1', 'a', 'b']);
expect(mockFn.mock.calls[1]).toEqual(['group2', 'a', 'b']);
expect(mockFn.mock.calls[2]).toEqual(['group3', 'a', 'b']);
wait.resolve();
await expect(result1a).resolves.toEqual('group1-ab');
await expect(result2a).resolves.toEqual('group2-ab');
await expect(result3a).resolves.toEqual('group3-ab');
await expect(result1b).resolves.toEqual('group1-ef');
await expect(result1c).resolves.toEqual('group1-ef');
await expect(result2b).resolves.toEqual('group2-ef');
await expect(result2c).resolves.toEqual('group2-ef');
await expect(result3b).resolves.toEqual('group3-ef');
await expect(result3c).resolves.toEqual('group3-ef');
expect(mockFn.mock.calls.length).toEqual(6);
expect(mockFn.mock.calls[3]).toEqual(['group1', 'e', 'f']);
expect(mockFn.mock.calls[4]).toEqual(['group2', 'e', 'f']);
expect(mockFn.mock.calls[5]).toEqual(['group3', 'e', 'f']);
}
);
test(
'defers multiple function calls in a group until the previous invocation in the same group is resolved,' +
'then invokes the function with arguments as defined by argsResolver to the group and resolves all group calls',
async () => {
const wait = deferredPromise<void>();
const mockFn = mockHelper(async (arg1: string, arg2: string, arg3: string) => {
await wait.promise;
return arg1 + '-' + arg2 + arg3;
});
const deferred = deferWhileRunning(mockFn, {
groupResolver: (group: string) => group,
argsResolver: ({ nextArgs, prevArgs }) => {
return [nextArgs[0], 'A', 'B'] as [string, string, string];
}
});
const result1a = deferred('group1', 'a', 'b');
const result1b = deferred('group1', 'c', 'd');
const result1c = deferred('group1', 'e', 'f');
const result2a = deferred('group2', 'a', 'b');
const result2b = deferred('group2', 'c', 'd');
const result2c = deferred('group2', 'e', 'f');
const result3a = deferred('group3', 'a', 'b');
const result3b = deferred('group3', 'c', 'd');
const result3c = deferred('group3', 'e', 'f');
expect(mockFn.mock.calls.length).toEqual(3);
expect(mockFn.mock.calls[0]).toEqual(['group1', 'a', 'b']);
expect(mockFn.mock.calls[1]).toEqual(['group2', 'a', 'b']);
expect(mockFn.mock.calls[2]).toEqual(['group3', 'a', 'b']);
wait.resolve();
await expect(result1a).resolves.toEqual('group1-ab');
await expect(result2a).resolves.toEqual('group2-ab');
await expect(result3a).resolves.toEqual('group3-ab');
await expect(result1b).resolves.toEqual('group1-AB');
await expect(result1c).resolves.toEqual('group1-AB');
await expect(result2b).resolves.toEqual('group2-AB');
await expect(result2c).resolves.toEqual('group2-AB');
await expect(result3b).resolves.toEqual('group3-AB');
await expect(result3c).resolves.toEqual('group3-AB');
expect(mockFn.mock.calls.length).toEqual(6);
expect(mockFn.mock.calls[3]).toEqual(['group1', 'A', 'B']);
expect(mockFn.mock.calls[4]).toEqual(['group2', 'A', 'B']);
expect(mockFn.mock.calls[5]).toEqual(['group3', 'A', 'B']);
}
);
});