(
expectation: () => T,
{
timeout = getConfig().asyncUtilTimeout,
interval = DEFAULT_INTERVAL,
stackTraceError,
onTimeout,
}: WaitForOptions,
)
| 22 | }; |
| 23 | |
| 24 | function waitForInternal<T>( |
| 25 | expectation: () => T, |
| 26 | { |
| 27 | timeout = getConfig().asyncUtilTimeout, |
| 28 | interval = DEFAULT_INTERVAL, |
| 29 | stackTraceError, |
| 30 | onTimeout, |
| 31 | }: WaitForOptions, |
| 32 | ): Promise<T> { |
| 33 | if (typeof expectation !== 'function') { |
| 34 | throw new TypeError('Received `expectation` arg must be a function'); |
| 35 | } |
| 36 | |
| 37 | // eslint-disable-next-line no-async-promise-executor |
| 38 | return new Promise(async (resolve, reject) => { |
| 39 | let lastError: unknown; |
| 40 | let intervalId: ReturnType<typeof setInterval> | null = null; |
| 41 | let finished = false; |
| 42 | let promiseStatus = 'idle'; |
| 43 | |
| 44 | let overallTimeoutTimer: ReturnType<typeof setTimeout> | null = null; |
| 45 | const cleanupQueueCallback = () => finalizeWaitFor({ rejectOnAbort: true }); |
| 46 | |
| 47 | const fakeTimersType = getJestFakeTimersType(); |
| 48 | |
| 49 | if (fakeTimersType) { |
| 50 | checkExpectation(); |
| 51 | // this is a dangerous rule to disable because it could lead to an |
| 52 | // infinite loop. However, eslint isn't smart enough to know that we're |
| 53 | // setting finished inside `onDone` which will be called when we're done |
| 54 | // waiting or when we've timed out. |
| 55 | let fakeTimeRemaining = timeout; |
| 56 | while (!finished) { |
| 57 | if (!jestFakeTimersAreEnabled()) { |
| 58 | const error = new Error( |
| 59 | `Changed from using fake timers to real timers while using waitFor. This is not allowed and will result in very strange behavior. Please ensure you're awaiting all async things your test is doing before changing to real timers. For more info, please go to https://github.com/testing-library/dom-testing-library/issues/830`, |
| 60 | ); |
| 61 | copyStackTraceIfNeeded(error, stackTraceError); |
| 62 | reject(error); |
| 63 | return; |
| 64 | } |
| 65 | |
| 66 | // when fake timers are used we want to simulate the interval time passing |
| 67 | if (fakeTimeRemaining <= 0) { |
| 68 | handleTimeout(); |
| 69 | return; |
| 70 | } else { |
| 71 | fakeTimeRemaining -= interval; |
| 72 | } |
| 73 | |
| 74 | // we *could* (maybe should?) use `advanceTimersToNextTimer` but it's |
| 75 | // possible that could make this loop go on forever if someone is using |
| 76 | // third party code that's setting up recursive timers so rapidly that |
| 77 | // the user's timer's don't get a chance to resolve. So we'll advance |
| 78 | // by an interval instead. (We have a test for this case). |
| 79 | await act(() => |
| 80 | fakeTimersType === 'modern' |
| 81 | ? jest.advanceTimersByTimeAsync(interval) |
no test coverage detected
searching dependent graphs…