import * as SchedulerMock from 'scheduler/unstable_mock';
import {diff} from 'jest-diff';
import {equals} from '@jest/expect-utils';
import enqueueTask from './enqueueTask';
export {act} from './internalAct';
function assertYieldsWereCleared(caller) {
const actualYields = SchedulerMock.unstable_clearLog();
if (actualYields.length !== 0) {
const error = Error(
'The event log is not empty. Call assertLog(...) first.',
);
Error.captureStackTrace(error, caller);
throw error;
}
}
export async function waitForMicrotasks() {
return new Promise(resolve => {
enqueueTask(() => resolve());
});
}
export async function waitFor(expectedLog, options) {
assertYieldsWereCleared(waitFor);
const error = new Error();
Error.captureStackTrace(error, waitFor);
const stopAfter = expectedLog.length;
const actualLog = [];
do {
await waitForMicrotasks();
if (SchedulerMock.unstable_hasPendingWork()) {
SchedulerMock.unstable_flushNumberOfYields(stopAfter - actualLog.length);
actualLog.push(...SchedulerMock.unstable_clearLog());
if (stopAfter > actualLog.length) {
} else {
await waitForMicrotasks();
actualLog.push(...SchedulerMock.unstable_clearLog());
break;
}
} else {
break;
}
} while (true);
if (options && options.additionalLogsAfterAttemptingToYield) {
expectedLog = expectedLog.concat(
options.additionalLogsAfterAttemptingToYield,
);
}
if (equals(actualLog, expectedLog)) {
return;
}
error.message = `
Expected sequence of events did not occur.
${diff(expectedLog, actualLog)}
`;
throw error;
}
export async function waitForAll(expectedLog) {
assertYieldsWereCleared(waitForAll);
const error = new Error();
Error.captureStackTrace(error, waitForAll);
do {
await waitForMicrotasks();
if (!SchedulerMock.unstable_hasPendingWork()) {
break;
}
SchedulerMock.unstable_flushAllWithoutAsserting();
} while (true);
const actualLog = SchedulerMock.unstable_clearLog();
if (equals(actualLog, expectedLog)) {
return;
}
error.message = `
Expected sequence of events did not occur.
${diff(expectedLog, actualLog)}
`;
throw error;
}
export async function waitForThrow(expectedError: mixed): mixed {
assertYieldsWereCleared(waitForThrow);
const error = new Error();
Error.captureStackTrace(error, waitForThrow);
do {
await waitForMicrotasks();
if (!SchedulerMock.unstable_hasPendingWork()) {
error.message = 'Expected something to throw, but nothing did.';
throw error;
}
try {
SchedulerMock.unstable_flushAllWithoutAsserting();
} catch (x) {
if (expectedError === undefined) {
return x;
}
if (equals(x, expectedError)) {
return x;
}
if (
typeof expectedError === 'string' &&
typeof x === 'object' &&
x !== null &&
typeof x.message === 'string'
) {
if (x.message.includes(expectedError)) {
return x;
} else {
error.message = `
Expected error was not thrown.
${diff(expectedError, x.message)}
`;
throw error;
}
}
error.message = `
Expected error was not thrown.
${diff(expectedError, x)}
`;
throw error;
}
} while (true);
}
export async function unstable_waitForExpired(expectedLog): mixed {
assertYieldsWereCleared(unstable_waitForExpired);
const error = new Error();
Error.captureStackTrace(error, unstable_waitForExpired);
await waitForMicrotasks();
SchedulerMock.unstable_flushExpired();
const actualLog = SchedulerMock.unstable_clearLog();
if (equals(actualLog, expectedLog)) {
return;
}
error.message = `
Expected sequence of events did not occur.
${diff(expectedLog, actualLog)}
`;
throw error;
}
export async function waitForPaint(expectedLog) {
assertYieldsWereCleared(waitForPaint);
const error = new Error();
Error.captureStackTrace(error, waitForPaint);
await waitForMicrotasks();
if (SchedulerMock.unstable_hasPendingWork()) {
SchedulerMock.unstable_flushUntilNextPaint();
await waitForMicrotasks();
}
const actualLog = SchedulerMock.unstable_clearLog();
if (equals(actualLog, expectedLog)) {
return;
}
error.message = `
Expected sequence of events did not occur.
${diff(expectedLog, actualLog)}
`;
throw error;
}
export async function waitForDiscrete(expectedLog) {
assertYieldsWereCleared(waitForDiscrete);
const error = new Error();
Error.captureStackTrace(error, waitForDiscrete);
await waitForMicrotasks();
const actualLog = SchedulerMock.unstable_clearLog();
if (equals(actualLog, expectedLog)) {
return;
}
error.message = `
Expected sequence of events did not occur.
${diff(expectedLog, actualLog)}
`;
throw error;
}
export function assertLog(expectedLog) {
const actualLog = SchedulerMock.unstable_clearLog();
if (equals(actualLog, expectedLog)) {
return;
}
const error = new Error(`
Expected sequence of events did not occur.
${diff(expectedLog, actualLog)}
`);
Error.captureStackTrace(error, assertLog);
throw error;
}