gitlab-org--gitlab-foss/spec/frontend/lib/utils/ignore_while_pending_spec.js

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 }],
]);
});
});
});