UNPKG

leadfoot

Version:

Leadfoot. A JavaScript client library that brings cross-platform consistency to the Selenium WebDriver API.

134 lines (121 loc) 4.01 kB
/** * @module leadfoot/helpers/pollUntil */ var util = require('../lib/util'); /** * A {@link module:leadfoot/Command} helper that polls for a value within the client environment until the value exists * or a timeout is reached. * * @param {Function|string} poller * The poller function to execute on an interval. The function should return `null` or `undefined` if there is not a * result. If the poller function throws, polling will halt. * * @param {Array.<any>=} args * An array of arguments to pass to the poller function when it is invoked. Only values that can be serialised to JSON, * plus {@link module:leadfoot/Element} objects, can be specified as arguments. * * @param {number=} timeout * The maximum amount of time to wait for a successful result, in milliseconds. If not specified, the current * `executeAsync` maximum timeout for the session will be used. * * @param {number=} pollInterval * The amount of time to wait between calls to the poller function, in milliseconds. If not specified, defaults to 67ms. * * @returns {function(): Promise.<any>} * A {@link module:leadfoot/Command#then} callback function that, when called, returns a promise that resolves to the * value returned by the poller function on success and rejects on failure. * * @example * var Command = require('leadfoot/Command'); * var pollUntil = require('leadfoot/helpers/pollUntil'); * * new Command(session) * .get('http://example.com') * .then(pollUntil('return document.getElementById("a");', 1000)) * .then(function (elementA) { * // element was found * }, function (error) { * // element was not found * }); * * @example * var Command = require('leadfoot/Command'); * var pollUntil = require('leadfoot/helpers/pollUntil'); * * new Command(session) * .get('http://example.com') * .then(pollUntil(function (value) { * var element = document.getElementById('a'); * return element && element.value === value ? true : null; * }, [ 'foo' ], 1000)) * .then(function () { * // value was set to 'foo' * }, function (error) { * // value was never set * }); */ module.exports = function (poller, args, timeout, pollInterval) { if (typeof args === 'number') { pollInterval = timeout; timeout = args; args = []; } args = args || []; pollInterval = pollInterval || 67; return function () { var session = this.session; var originalTimeout; return session.getExecuteAsyncTimeout().then(function () { function storeResult(result) { resultOrError = result; } if (!isNaN(timeout)) { originalTimeout = arguments[0]; } else { timeout = arguments[0]; } var resultOrError; return session.setExecuteAsyncTimeout(timeout) .then(function () { /* jshint maxlen:140 */ return session.executeAsync(/* istanbul ignore next */ function (poller, args, timeout, pollInterval, done) { /* jshint evil:true */ poller = new Function(poller); var endTime = Number(new Date()) + timeout; (function poll() { var result = poller.apply(this, args); /*jshint evil:true */ if (result != null) { done(result); } else if (Number(new Date()) < endTime) { setTimeout(poll, pollInterval); } else { done(null); } })(); }, [ util.toExecuteString(poller), args, timeout, pollInterval ]); }) .then(storeResult, storeResult) .finally(function () { function finish() { if (resultOrError instanceof Error) { throw resultOrError; } if (resultOrError === null) { var error = new Error('Polling timed out with no result'); error.name = 'ScriptTimeout'; throw error; } return resultOrError; } if (!isNaN(originalTimeout)) { return session.setExecuteAsyncTimeout(originalTimeout).then(finish); } return finish(); }); }); }; };