|
1 | | -import { |
2 | | - getDocument, |
3 | | - newMutationObserver, |
4 | | - setImmediate, |
5 | | - setTimeout, |
6 | | - clearTimeout, |
7 | | - runWithRealTimers, |
8 | | -} from './helpers' |
9 | | -import {getConfig} from './config' |
| 1 | +import {wait} from './wait' |
10 | 2 |
|
11 | | -function waitForElementToBeRemoved( |
12 | | - callback, |
13 | | - { |
14 | | - container = getDocument(), |
15 | | - timeout = getConfig().asyncUtilTimeout, |
16 | | - mutationObserverOptions = { |
17 | | - subtree: true, |
18 | | - childList: true, |
19 | | - attributes: true, |
20 | | - characterData: true, |
21 | | - }, |
22 | | - } = {}, |
23 | | -) { |
24 | | - return new Promise((resolve, reject) => { |
25 | | - if (typeof callback !== 'function') { |
26 | | - reject( |
27 | | - new Error( |
28 | | - 'waitForElementToBeRemoved requires a function as the first parameter', |
29 | | - ), |
30 | | - ) |
31 | | - } |
32 | | - const timer = setTimeout(onTimeout, timeout) |
33 | | - const observer = newMutationObserver(onMutation) |
| 3 | +const isRemoved = result => !result || (Array.isArray(result) && !result.length) |
| 4 | + |
| 5 | +async function waitForElementToBeRemoved(callback, options) { |
| 6 | + if (!callback) { |
| 7 | + return Promise.reject( |
| 8 | + new Error( |
| 9 | + 'waitForElementToBeRemoved requires a callback as the first parameter', |
| 10 | + ), |
| 11 | + ) |
| 12 | + } |
| 13 | + |
| 14 | + // Check if the element is not present synchronously, |
| 15 | + // As the name implies, waitForElementToBeRemoved should check `present` --> `removed` |
| 16 | + if (isRemoved(callback())) { |
| 17 | + throw new Error( |
| 18 | + 'The callback function which was passed did not return an element or non-empty array of elements. waitForElementToBeRemoved requires that the element(s) exist before waiting for removal.', |
| 19 | + ) |
| 20 | + } |
34 | 21 |
|
35 | | - // Check if the element is not present synchronously, |
36 | | - // As the name waitForElementToBeRemoved should check `present` --> `removed` |
| 22 | + return wait(() => { |
| 23 | + let result |
37 | 24 | try { |
38 | | - const result = callback() |
39 | | - if (!result || (Array.isArray(result) && !result.length)) { |
40 | | - onDone( |
41 | | - new Error( |
42 | | - 'The callback function which was passed did not return an element or non-empty array of elements. waitForElementToBeRemoved requires that the element(s) exist before waiting for removal.', |
43 | | - ), |
44 | | - ) |
45 | | - } else { |
46 | | - // Only observe for mutations only if there is element while checking synchronously |
47 | | - runWithRealTimers(() => |
48 | | - observer.observe(container, mutationObserverOptions), |
49 | | - ) |
50 | | - } |
| 25 | + result = callback() |
51 | 26 | } catch (error) { |
52 | | - onDone(error) |
53 | | - } |
54 | | - |
55 | | - function onDone(error, result) { |
56 | | - clearTimeout(timer) |
57 | | - setImmediate(() => observer.disconnect()) |
58 | | - if (error) { |
59 | | - reject(error) |
60 | | - } else { |
61 | | - resolve(result) |
62 | | - } |
63 | | - } |
64 | | - function onMutation() { |
65 | | - try { |
66 | | - const result = callback() |
67 | | - if (!result || (Array.isArray(result) && !result.length)) { |
68 | | - onDone(null, true) |
69 | | - } |
70 | | - // If `callback` returns truthy value, wait for the next mutation or timeout. |
71 | | - } catch (error) { |
72 | | - onDone(null, true) |
| 27 | + if (error.message && error.message.startsWith('Unable to find')) { |
| 28 | + // All of our get* queries throw an error that starts with "Unable to find" |
| 29 | + // when it fails to find an element. |
| 30 | + // TODO: make the queries throw a special kind of error |
| 31 | + // so we can be more explicit about the check. |
| 32 | + return true |
73 | 33 | } |
| 34 | + throw error |
74 | 35 | } |
75 | | - function onTimeout() { |
76 | | - onDone(new Error('Timed out in waitForElementToBeRemoved.'), null) |
| 36 | + if (!isRemoved(result)) { |
| 37 | + throw new Error('Timed out in waitForElementToBeRemoved.') |
77 | 38 | } |
78 | | - }) |
| 39 | + return true |
| 40 | + }, options) |
79 | 41 | } |
80 | 42 |
|
81 | | -function waitForElementToBeRemovedWrapper(...args) { |
82 | | - return getConfig().asyncWrapper(() => waitForElementToBeRemoved(...args)) |
83 | | -} |
| 43 | +export {waitForElementToBeRemoved} |
84 | 44 |
|
85 | | -export {waitForElementToBeRemovedWrapper as waitForElementToBeRemoved} |
| 45 | +/* |
| 46 | +eslint |
| 47 | + require-await: "off" |
| 48 | +*/ |
0 commit comments