mirror of
https://github.com/puppeteer/puppeteer
synced 2024-06-14 14:02:48 +00:00
Implement page.waitForFunction method
The page.waitForFunction method allows to wait for a general predicate. The predicate will be continiously polled for in page, until it either returns true or the timeout happens. The polling parameter could be one of the following: - 'raf' - to poll on every animation frame - 'mutation' - to poll on every dom mutation - <number> - to poll every X milliseconds References #91
This commit is contained in:
@@ -275,9 +275,9 @@ class Frame {
|
||||
* @return {!Promise}
|
||||
*/
|
||||
waitFor(selectorOrTimeout, options = {}) {
|
||||
if (typeof selectorOrTimeout === 'string' || selectorOrTimeout instanceof String)
|
||||
if (helper.isString(selectorOrTimeout))
|
||||
return this.waitForSelector(selectorOrTimeout, options);
|
||||
if (typeof selectorOrTimeout === 'number' || selectorOrTimeout instanceof Number)
|
||||
if (helper.isNumber(selectorOrTimeout))
|
||||
return new Promise(fulfill => setTimeout(fulfill, selectorOrTimeout));
|
||||
return Promise.reject(new Error('Unsupported target type: ' + (typeof selectorOrTimeout)));
|
||||
}
|
||||
@@ -290,8 +290,35 @@ class Frame {
|
||||
waitForSelector(selector, options = {}) {
|
||||
const timeout = options.timeout || 30000;
|
||||
const waitForVisible = !!options.visible;
|
||||
const pageScript = helper.evaluationString(waitForSelectorPageFunction, selector, waitForVisible, timeout);
|
||||
return new WaitTask(this, pageScript, timeout).promise;
|
||||
const polling = waitForVisible ? 'raf' : 'mutation';
|
||||
return this.waitForFunction(predicate, {timeout, polling}, selector, waitForVisible);
|
||||
|
||||
/**
|
||||
* @param {string} selector
|
||||
* @param {boolean} waitForVisible
|
||||
* @return {boolean}
|
||||
*/
|
||||
function predicate(selector, waitForVisible) {
|
||||
const node = document.querySelector(selector);
|
||||
if (!node)
|
||||
return false;
|
||||
if (!waitForVisible)
|
||||
return true;
|
||||
const style = window.getComputedStyle(node);
|
||||
return style && style.display !== 'none' && style.visibility !== 'hidden';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {function()} pageFunction
|
||||
* @param {!Object=} options
|
||||
* @return {!Promise}
|
||||
*/
|
||||
waitForFunction(pageFunction, options = {}, ...args) {
|
||||
const timeout = options.timeout || 30000;
|
||||
const polling = options.polling || 'raf';
|
||||
const predicateCode = 'return ' + helper.evaluationString(pageFunction, ...args);
|
||||
return new WaitTask(this, predicateCode, polling, timeout).promise;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -415,12 +442,20 @@ helper.tracePublicAPI(Frame);
|
||||
class WaitTask {
|
||||
/**
|
||||
* @param {!Frame} frame
|
||||
* @param {string} pageScript
|
||||
* @param {string} predicateBody
|
||||
* @param {string} polling
|
||||
* @param {number} timeout
|
||||
*/
|
||||
constructor(frame, pageScript, timeout) {
|
||||
constructor(frame, predicateBody, polling, timeout) {
|
||||
if (helper.isString(polling))
|
||||
console.assert(polling === 'raf' || polling === 'mutation', 'Unknown polling option: ' + polling);
|
||||
else if (helper.isNumber(polling))
|
||||
console.assert(polling > 0, 'Cannot poll with non-positive interval: ' + polling);
|
||||
else
|
||||
throw new Error('Unknown polling options: ' + polling);
|
||||
|
||||
this._frame = frame;
|
||||
this._pageScript = pageScript;
|
||||
this._pageScript = helper.evaluationString(waitForPredicatePageFunction, predicateBody, polling, timeout);
|
||||
this._runCount = 0;
|
||||
frame._waitTasks.add(this);
|
||||
this.promise = new Promise((resolve, reject) => {
|
||||
@@ -475,31 +510,34 @@ class WaitTask {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} selector
|
||||
* @param {boolean} waitForVisible
|
||||
* @param {string} predicateBody
|
||||
* @param {string} polling
|
||||
* @param {number} timeout
|
||||
* @return {!Promise<boolean>}
|
||||
*/
|
||||
async function waitForSelectorPageFunction(selector, visible, timeout) {
|
||||
async function waitForPredicatePageFunction(predicateBody, polling, timeout) {
|
||||
const predicate = new Function(predicateBody);
|
||||
let timedOut = false;
|
||||
setTimeout(() => timedOut = true, timeout);
|
||||
await waitForDOM();
|
||||
await waitForVisible();
|
||||
if (polling === 'raf')
|
||||
await pollRaf();
|
||||
else if (polling === 'mutation')
|
||||
await pollMutation();
|
||||
else if (typeof polling === 'number')
|
||||
await pollInterval(polling);
|
||||
return !timedOut;
|
||||
|
||||
/**
|
||||
* @return {!Promise<!Element>}
|
||||
*/
|
||||
function waitForDOM() {
|
||||
let node = document.querySelector(selector);
|
||||
if (node)
|
||||
function pollMutation() {
|
||||
if (predicate())
|
||||
return Promise.resolve();
|
||||
|
||||
let fulfill;
|
||||
const result = new Promise(x => fulfill = x);
|
||||
const observer = new MutationObserver(mutations => {
|
||||
const node = document.querySelector(selector);
|
||||
if (node || timedOut) {
|
||||
if (timedOut || predicate()) {
|
||||
observer.disconnect();
|
||||
fulfill();
|
||||
}
|
||||
@@ -512,26 +550,37 @@ async function waitForSelectorPageFunction(selector, visible, timeout) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {!Promise<!Element>}
|
||||
* @return {!Promise}
|
||||
*/
|
||||
function waitForVisible() {
|
||||
function pollRaf() {
|
||||
let fulfill;
|
||||
const result = new Promise(x => fulfill = x);
|
||||
onRaf();
|
||||
return result;
|
||||
|
||||
function onRaf() {
|
||||
if (timedOut) {
|
||||
if (timedOut || predicate())
|
||||
fulfill();
|
||||
return;
|
||||
}
|
||||
const node = document.querySelector(selector);
|
||||
const style = node ? window.getComputedStyle(node) : null;
|
||||
if (!style || style.display === 'none' || style.visibility === 'hidden') {
|
||||
else
|
||||
requestAnimationFrame(onRaf);
|
||||
return;
|
||||
}
|
||||
fulfill();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} pollInterval
|
||||
* @return {!Promise}
|
||||
*/
|
||||
function pollInterval(pollInterval) {
|
||||
let fulfill;
|
||||
const result = new Promise(x => fulfill = x);
|
||||
onTimeout();
|
||||
return result;
|
||||
|
||||
function onTimeout() {
|
||||
if (timedOut || predicate())
|
||||
fulfill();
|
||||
else
|
||||
setTimeout(onTimeout, pollInterval);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user