137 lines
3.7 KiB
JavaScript
137 lines
3.7 KiB
JavaScript
import waitForPromises from 'helpers/wait_for_promises';
|
|
import { ignoreWhilePending } from '~/lib/utils/ignore_while_pending';
|
|
|
|
const TEST_ARGS = [123, { foo: 'bar' }];
|
|
|
|
describe('~/lib/utils/ignore_while_pending', () => {
|
|
let spyResolve;
|
|
let spyReject;
|
|
let spy;
|
|
let subject;
|
|
|
|
beforeEach(() => {
|
|
spy = jest.fn().mockImplementation(
|
|
// NOTE: We can't pass an arrow function here...
|
|
function foo() {
|
|
return new Promise((resolve, reject) => {
|
|
spyResolve = resolve;
|
|
spyReject = reject;
|
|
});
|
|
},
|
|
);
|
|
});
|
|
|
|
describe('with non-instance method', () => {
|
|
beforeEach(() => {
|
|
subject = ignoreWhilePending(spy);
|
|
});
|
|
|
|
it('while pending, will ignore subsequent calls', () => {
|
|
subject(...TEST_ARGS);
|
|
subject();
|
|
subject();
|
|
subject();
|
|
|
|
expect(spy).toHaveBeenCalledTimes(1);
|
|
expect(spy).toHaveBeenCalledWith(...TEST_ARGS);
|
|
});
|
|
|
|
it.each`
|
|
desc | act
|
|
${'when resolved'} | ${() => spyResolve()}
|
|
${'when rejected'} | ${() => spyReject(new Error('foo'))}
|
|
`('$desc, can be triggered again', async ({ act }) => {
|
|
// We need the empty catch(), since we are testing rejecting the promise,
|
|
// which would otherwise cause the test to fail.
|
|
subject(...TEST_ARGS).catch(() => {});
|
|
subject();
|
|
subject();
|
|
subject();
|
|
|
|
act();
|
|
// We need waitForPromises, so that the underlying finally() runs.
|
|
await waitForPromises();
|
|
|
|
subject({ again: 'foo' });
|
|
|
|
expect(spy).toHaveBeenCalledTimes(2);
|
|
expect(spy).toHaveBeenCalledWith(...TEST_ARGS);
|
|
expect(spy).toHaveBeenCalledWith({ again: 'foo' });
|
|
});
|
|
|
|
it('while pending, returns empty resolutions for ignored calls', async () => {
|
|
subject(...TEST_ARGS);
|
|
|
|
await expect(subject(...TEST_ARGS)).resolves.toBeUndefined();
|
|
await expect(subject(...TEST_ARGS)).resolves.toBeUndefined();
|
|
});
|
|
|
|
it('when resolved, returns resolution for origin call', async () => {
|
|
const resolveValue = { original: 1 };
|
|
const result = subject(...TEST_ARGS);
|
|
|
|
spyResolve(resolveValue);
|
|
|
|
await expect(result).resolves.toEqual(resolveValue);
|
|
});
|
|
|
|
it('when rejected, returns rejection for original call', async () => {
|
|
const rejectedErr = new Error('original');
|
|
const result = subject(...TEST_ARGS);
|
|
|
|
spyReject(rejectedErr);
|
|
|
|
await expect(result).rejects.toEqual(rejectedErr);
|
|
});
|
|
});
|
|
|
|
describe('with instance method', () => {
|
|
let instance1;
|
|
let instance2;
|
|
|
|
beforeEach(() => {
|
|
// Let's capture the "this" for tests
|
|
subject = ignoreWhilePending(function instanceMethod(...args) {
|
|
return spy(this, ...args);
|
|
});
|
|
|
|
instance1 = {};
|
|
instance2 = {};
|
|
});
|
|
|
|
it('will not ignore calls across instances', () => {
|
|
subject.call(instance1, { context: 1 });
|
|
subject.call(instance1, {});
|
|
subject.call(instance1, {});
|
|
subject.call(instance2, { context: 2 });
|
|
subject.call(instance2, {});
|
|
|
|
expect(spy.mock.calls).toEqual([
|
|
[instance1, { context: 1 }],
|
|
[instance2, { context: 2 }],
|
|
]);
|
|
});
|
|
|
|
it('resolving one instance does not resolve other instances', async () => {
|
|
subject.call(instance1, { context: 1 });
|
|
|
|
// We need to save off spyResolve so it's not overwritten by next call
|
|
const instance1Resolve = spyResolve;
|
|
|
|
subject.call(instance2, { context: 2 });
|
|
|
|
instance1Resolve();
|
|
await waitForPromises();
|
|
|
|
subject.call(instance1, { context: 1 });
|
|
subject.call(instance2, { context: 2 });
|
|
|
|
expect(spy.mock.calls).toEqual([
|
|
[instance1, { context: 1 }],
|
|
[instance2, { context: 2 }],
|
|
[instance1, { context: 1 }],
|
|
]);
|
|
});
|
|
});
|
|
});
|