Repository navigation
Expand file tree
/
Copy pathwait-for.js
More file actions
135 lines (113 loc) Β· 3.55 KB
/
Copy pathwait-for.js
File metadata and controls
135 lines (113 loc) Β· 3.55 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
const defaults = {
delay: 100,
timeout: 4000,
};
/**
* Waits for specified function to resolve to a truthy value.
*
* @param {Function} fn function to be evaluated until truthy
* @param {*} arg optional argument to pass to `fn`
* @param {Object} options optional parameters
* @param {number} options.delay delay between fn invocations
* @param {number} options.timeout timeout in milliseconds
* @returns {Promise} promise which resolves to the truthy fn return value or
* rejects to an error object or last non-truthy fn return value
*/
function waitForFunction(fn, arg, options = {}) {
const settings = {
...defaults,
...options,
};
return new Promise((resolve, reject) => {
let timeElapsed = 0;
let lastError;
const int = setInterval(() => {
let result;
try {
result = fn(arg);
} catch (err) {
lastError = err;
}
if (result) {
clearInterval(int);
resolve(result);
}
timeElapsed += settings.delay;
if (timeElapsed >= settings.timeout) {
console.error(
`\nwaitForFunction did not return a truthy value within ${settings.timeout} ms.\n`,
);
reject(lastError || result);
}
}, settings.delay);
});
}
/**
* Waits for specified CSS selector to be located in the DOM
*
* @param {String} cssSelector CSS selector to query for
* @param {Object} options optional parameters
* @param {number} options.delay delay between checks
* @param {number} options.timeout timeout in milliseconds
* @returns {Promise} promise which resolves to first matching element
*/
function waitForSelector(cssSelector, options = {}) {
const settings = {
...defaults,
...options,
};
return new Promise((resolve, reject) => {
let timeElapsed = 0;
const int = setInterval(() => {
const elm = document.querySelector(cssSelector);
if (elm) {
clearInterval(int);
resolve(elm);
}
timeElapsed += settings.delay;
if (timeElapsed >= settings.timeout) {
const msg = `waitForSelector did not match CSS selector '${cssSelector}' (${settings.timeout} ms)`;
reject(msg);
}
}, settings.delay);
});
}
/**
* Waits for specified CSS selector to contain text content
*
* @param {String} cssSelector CSS selector to query for
* @param {String} text text to match
* @param {Object} options optional parameters
* @param {number} options.delay delay between checks
* @param {number} options.timeout timeout in milliseconds
* @returns {Promise} promise which resolves to first matching element that contains specified text
*/
function waitForText(cssSelector, text, options = {}) {
const settings = {
...defaults,
...options,
};
return new Promise((resolve, reject) => {
let timeElapsed = 0;
waitForSelector(cssSelector, settings)
.then(elm => {
const int = setInterval(() => {
const isMatch = elm.textContent.includes(text);
if (isMatch) {
clearInterval(int);
resolve(true);
}
timeElapsed += settings.delay;
if (timeElapsed >= settings.timeout) {
const msg = `waitForText did not find '${text}' in CSS selector '${cssSelector}' (${settings.timeout} ms): '${elm.textContent}'`;
reject(msg);
}
}, settings.delay);
})
.catch(() => {
const msg = `waitForText did not match CSS selector '${cssSelector}' (${settings.timeout} ms)`;
reject(msg);
});
});
}
export { waitForFunction, waitForSelector, waitForText };