@augment-vir/assert
Version:
A collection of assertions for test and production code alike.
88 lines (87 loc) • 3.14 kB
JavaScript
import { ensureError, ensureErrorAndPrependMessage, wait, } from '@augment-vir/core';
import { convertDuration } from '@date-vir/duration';
export const defaultWaitUntilOptions = {
interval: {
milliseconds: 100,
},
timeout: {
seconds: 10,
},
};
const notSetSymbol = Symbol('not set');
export async function executeWaitUntil(assert, rawArgs, requireSynchronousResult) {
const { callback, extraAssertionArgs, failureMessage, options } = parseWaitUntilArgs(rawArgs);
const timeout = convertDuration(options.timeout, { milliseconds: true }).milliseconds;
const interval = convertDuration(options.interval, { milliseconds: true });
let lastCallbackOutput = notSetSymbol;
let lastError = undefined;
async function checkCondition() {
try {
lastCallbackOutput = requireSynchronousResult ? callback() : await callback();
assert(lastCallbackOutput, ...extraAssertionArgs);
}
catch (error) {
lastCallbackOutput = notSetSymbol;
lastError = ensureError(error);
}
}
const startTime = Date.now();
while (lastCallbackOutput === notSetSymbol) {
await checkCondition();
await wait(interval);
if (Date.now() - startTime >= timeout) {
const message = failureMessage ? `${failureMessage}: ` : '';
const preMessage = `${message}Timeout of '${timeout}' milliseconds exceeded waiting for callback value to match expectations`;
throw ensureErrorAndPrependMessage(lastError, preMessage);
}
}
return lastCallbackOutput;
}
export function createWaitUntil(assert, requireSynchronousResult = false) {
return ((...rawArgs) => {
return executeWaitUntil(assert, rawArgs, requireSynchronousResult);
});
}
export function parseWaitUntilArgs(rawArgs) {
const args = {
extraAssertionArgs: [],
options: undefined,
failureMessage: undefined,
};
rawArgs.toReversed().forEach((arg) => {
if (args.callback) {
args.extraAssertionArgs.push(arg);
}
else if (typeof arg === 'function') {
args.callback = arg;
}
else if (typeof arg === 'string') {
args.failureMessage = arg;
}
else if (typeof arg === 'object') {
args.options = arg;
}
else if (arg === undefined) {
/** Skip an undefined arg. */
return;
}
else {
throw new TypeError(`Unexpected waitUntil arg: ${JSON.stringify(arg)}`);
}
});
if (!args.callback) {
throw new TypeError('Missing waitUntil callback.');
}
return {
callback: args.callback,
options: parseWaitUntilOptions(args.options),
extraAssertionArgs: args.extraAssertionArgs.toReversed(),
failureMessage: args.failureMessage,
};
}
export function parseWaitUntilOptions(rawOptions) {
return {
interval: rawOptions?.interval || defaultWaitUntilOptions.interval,
timeout: rawOptions?.timeout || defaultWaitUntilOptions.timeout,
};
}