2021-02-04 19:15:23 +01:00
|
|
|
const DEFAULT_TIMEOUT = 10000;
|
2020-12-04 18:17:57 +01:00
|
|
|
|
2020-10-30 15:17:36 +01:00
|
|
|
/**
|
2020-12-04 18:17:57 +01:00
|
|
|
* A function that wraps a sinon stub and returns an asynchronous function
|
|
|
|
* that resolves if the stubbed function was called enough times, or throws
|
|
|
|
* if the timeout is exceeded.
|
2020-10-30 15:17:36 +01:00
|
|
|
*
|
|
|
|
* The stub that has been passed in will be setup to call the wrapped function
|
2020-12-04 18:17:57 +01:00
|
|
|
* directly.
|
2020-10-30 15:17:36 +01:00
|
|
|
*
|
|
|
|
* WARNING: Any existing `callsFake` behavior will be overwritten.
|
|
|
|
*
|
|
|
|
* @param {import('sinon').stub} stub - A sinon stub of a function
|
2020-12-04 18:17:57 +01:00
|
|
|
* @param {unknown} [wrappedThis] - The object the stubbed function was called
|
|
|
|
* on, if any (i.e. the `this` value)
|
2022-08-24 20:57:47 +02:00
|
|
|
* @param {object} [options] - Optional configuration
|
2020-12-04 18:17:57 +01:00
|
|
|
* @param {number} [options.callCount] - The number of calls to wait for.
|
|
|
|
* @param {number|null} [options.timeout] - The timeout, in milliseconds. Pass
|
|
|
|
* in `null` to disable the timeout.
|
|
|
|
* @returns {Function} An asynchronous function that resolves when the stub is
|
|
|
|
* called enough times, or throws if the timeout is reached.
|
2020-10-30 15:17:36 +01:00
|
|
|
*/
|
2020-12-04 18:17:57 +01:00
|
|
|
function waitUntilCalled(
|
|
|
|
stub,
|
|
|
|
wrappedThis = null,
|
|
|
|
{ callCount = 1, timeout = DEFAULT_TIMEOUT } = {},
|
|
|
|
) {
|
2021-02-04 19:15:23 +01:00
|
|
|
let numCalls = 0;
|
|
|
|
let resolve;
|
|
|
|
let timeoutHandle;
|
2020-12-03 19:00:50 +01:00
|
|
|
const stubHasBeenCalled = new Promise((_resolve) => {
|
2021-02-04 19:15:23 +01:00
|
|
|
resolve = _resolve;
|
2020-12-04 18:17:57 +01:00
|
|
|
if (timeout !== null) {
|
|
|
|
timeoutHandle = setTimeout(
|
|
|
|
() => resolve(new Error('Timeout exceeded')),
|
|
|
|
timeout,
|
2021-02-04 19:15:23 +01:00
|
|
|
);
|
2020-12-04 18:17:57 +01:00
|
|
|
}
|
2021-02-04 19:15:23 +01:00
|
|
|
});
|
2020-10-30 15:17:36 +01:00
|
|
|
stub.callsFake((...args) => {
|
2020-12-03 19:00:50 +01:00
|
|
|
try {
|
|
|
|
if (stub.wrappedMethod) {
|
2021-02-04 19:15:23 +01:00
|
|
|
stub.wrappedMethod.call(wrappedThis, ...args);
|
2020-12-03 19:00:50 +01:00
|
|
|
}
|
|
|
|
} finally {
|
|
|
|
if (numCalls < callCount) {
|
2021-02-04 19:15:23 +01:00
|
|
|
numCalls += 1;
|
2020-12-03 19:00:50 +01:00
|
|
|
if (numCalls === callCount) {
|
2020-12-04 18:17:57 +01:00
|
|
|
if (timeoutHandle) {
|
2021-02-04 19:15:23 +01:00
|
|
|
clearTimeout(timeoutHandle);
|
2020-12-04 18:17:57 +01:00
|
|
|
}
|
2021-02-04 19:15:23 +01:00
|
|
|
resolve();
|
2020-12-03 19:00:50 +01:00
|
|
|
}
|
|
|
|
}
|
2020-10-30 15:17:36 +01:00
|
|
|
}
|
2021-02-04 19:15:23 +01:00
|
|
|
});
|
2020-12-04 18:17:57 +01:00
|
|
|
|
|
|
|
return async () => {
|
2021-02-04 19:15:23 +01:00
|
|
|
const error = await stubHasBeenCalled;
|
2020-12-04 18:17:57 +01:00
|
|
|
if (error) {
|
2021-02-04 19:15:23 +01:00
|
|
|
throw error;
|
2020-12-04 18:17:57 +01:00
|
|
|
}
|
2021-02-04 19:15:23 +01:00
|
|
|
};
|
2020-10-30 15:17:36 +01:00
|
|
|
}
|
2020-12-03 19:00:50 +01:00
|
|
|
|
2021-02-04 19:15:23 +01:00
|
|
|
module.exports = waitUntilCalled;
|