Socket
Socket
Sign inDemoInstall

bluefox

Package Overview
Dependencies
0
Maintainers
1
Versions
8
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 1.0.2 to 1.1.0

139

lib/actions.js

@@ -12,4 +12,5 @@ 'use strict';

documentReadyState,
hasFormattingBox,
} = require('./dom');
const {resultToArray, resultCount, executeSuccess, executePendingTag} = require('./result');
const {resultToArray, resultCount, executeSuccess, executePendingTag, executeFatalFailureTag} = require('./result');

@@ -25,2 +26,5 @@ const freezeCopyIfArray = value => {

const RIGHT_QUOTE = '\u201d';
const HORIZONTAL_ELLIPSIS = '\u2026';
const EMPTY_FROZEN_ARRAY = Object.freeze([]);
const CALLBACK_DESCRIPTION_MAX_LENGTH = 64;

@@ -39,8 +43,18 @@ exports.parseTimeoutArgument = timeout => {

exports.describeCallback = func => {
const funcString = func.toString();
if (funcString.length <= CALLBACK_DESCRIPTION_MAX_LENGTH) {
return funcString;
}
return funcString.slice(0, CALLBACK_DESCRIPTION_MAX_LENGTH - 1) + HORIZONTAL_ELLIPSIS;
};
class Action {
/**
* @param {?Window|Node|Array.<(Window|Node)>} currentResult
* @param {Object} metaData
* @return {{status: string, reasonStrings: string[], reasonValues: string[], value: (?Window|Node|Array.<(Window|Node)>)}}
*/
execute(currentResult) {
execute(currentResult, metaData) {
return executeSuccess(currentResult);

@@ -73,2 +87,10 @@ }

}
/**
* Schedule an additional check after this many milliseconds have passed since the start of the expression
* @return {number[]}
*/
get additionalCheckTimeout() {
return EMPTY_FROZEN_ARRAY;
}
}

@@ -106,3 +128,3 @@

if (!isResultItem(result)) {
return executePendingTag`a value that is not a Window nor a Node was set as the target`;
return executeFatalFailureTag`a value that is not a WindowProxy nor a HTMLDocument, nor an Element was set as the target`;
}

@@ -118,3 +140,3 @@ }

if (typeof results === 'function' && !isDOMNode(results)) {
return 'sets the target using a callback';
return `sets the target using a callback: \`${exports.describeCallback(results)}\``;
}

@@ -226,3 +248,4 @@

if (typeof this.expression === 'function') {
return `finds the first descendant element matching a CSS selector from a callback`;
return `finds the first descendant element matching a CSS selector from ` +
`a callback: \`${exports.describeCallback(this.expression)}\``;
}

@@ -261,3 +284,4 @@

if (typeof this.expression === 'function') {
return `finds all descendant elements matching a CSS selector from a callback`;
return `finds all descendant elements matching a CSS selector from a callback: ` +
`\`${exports.describeCallback(this.expression)}\``;
}

@@ -286,2 +310,6 @@

if (result && !isResultItem(result)) {
return executeFatalFailureTag`a value that is not an Element was returned by the XPath expression`;
}
if (result) {

@@ -297,3 +325,4 @@ return executeSuccess(result);

if (typeof this.expression === 'function') {
return `finds the first element matching a XPath expression from a callback`;
return `finds the first element matching a XPath expression from a callback: ` +
`\`${exports.describeCallback(this.expression)}\``;
}

@@ -327,2 +356,9 @@

Object.freeze(value);
for (const resultItem of value) {
if (!isResultItem(resultItem)) {
return executeFatalFailureTag`a value that is not an Element was returned by the XPath expression`;
}
}
return executeSuccess(value);

@@ -333,3 +369,4 @@ }

if (typeof this.expression === 'function') {
return `finds all elements matching a XPath expression from a callback`;
return `finds all elements matching a XPath expression from a callback: ` +
`\`${exports.describeCallback(this.expression)}\``;
}

@@ -396,2 +433,85 @@

class Delay extends Action {
constructor(timeout) {
super();
this.delayMs = exports.parseTimeoutArgument(timeout);
Object.freeze(this);
}
execute(currentResult, {executionStart, checkStart}) {
const {delayMs} = this;
const timeSinceStart = checkStart - executionStart;
if (timeSinceStart < delayMs) {
// eslint-disable-next-line max-len
return executePendingTag`the delay of ${delayMs / 1000} seconds has not yet elapsed, only ${timeSinceStart / 1000} seconds have elapsed so far`;
}
return executeSuccess(currentResult);
}
describe() {
return `waits until ${this.delayMs / 1000} seconds have elapsed since the start of the execution`;
}
get additionalCheckTimeout() {
return Object.freeze([this.delayMs]);
}
}
class IsDisplayed extends Action {
constructor() {
super();
Object.freeze(this);
}
execute(currentResult) {
if (!currentResult) {
return executeSuccess(currentResult);
}
if (Array.isArray(currentResult)) {
const result = currentResult.filter(object => hasFormattingBox(object));
return executeSuccess(Object.freeze(result));
}
const result = hasFormattingBox(currentResult) ? currentResult : null;
return executeSuccess(result);
}
describe() {
return `but only including elements which are displayed on the page`;
}
}
class Check extends Action {
constructor(callback) {
if (typeof callback !== 'function') {
throw Error('.check(callback): callback must be a function');
}
super();
this.callback = callback;
Object.freeze(this);
}
execute(currentResult) {
if (!currentResult) {
return executeSuccess(currentResult);
}
if (Array.isArray(currentResult)) {
const result = currentResult.filter(object => this.callback(object));
return executeSuccess(Object.freeze(result));
}
const result = this.callback(currentResult) ? currentResult : null;
return executeSuccess(result);
}
describe() {
return `but only including results that match a callback: \`${exports.describeCallback(this.callback)}\``;
}
}
const DEFAULT_AMOUNT_ACTION = new Amount(1, Infinity);

@@ -410,1 +530,4 @@

exports.DocumentComplete = DocumentComplete;
exports.Delay = Delay;
exports.IsDisplayed = IsDisplayed;
exports.Check = Check;

@@ -129,2 +129,11 @@ 'use strict';

/**
* @param {Window|Node} object
* @return {?HTMLHtmlElement}
*/
dom.resultItemToDocumentElement = object => {
const document = dom.resultItemToDocument(object);
return dom.findPropertyInChain(document, 'documentElement').get.call(document);
};
/**
* Find the closest object that implements the `ParentElement` interface, for the given result item

@@ -151,3 +160,20 @@ * @param {Window|Node} object

/**
* Find the closest object that implements the `Element` interface, for the given result item
* @param {Window|Node} object
* @return {Element}
*/
dom.resultItemToElement = object => {
if (dom.isDOMWindow(object) || dom.isDOMDocument(object)) {
return dom.resultItemToDocumentElement(object);
}
if (dom.isDOMElement(object)) {
return object;
}
throw Error('dom.resultItemToElement(): Invalid argument');
};
/**
* @param {Window|Node} object
* @return {string}

@@ -265,1 +291,20 @@ */

};
/**
* @param {Element} element
* @return {DOMRect}
*/
dom.getBoundingClientRect = element => {
const getBoundingClientRect = dom.findPropertyInChain(element, 'getBoundingClientRect');
return getBoundingClientRect.value.call(element);
};
/**
* @param {Window|Node} object
* @return {boolean}
*/
dom.hasFormattingBox = object => {
const element = dom.resultItemToElement(object);
const rect = dom.getBoundingClientRect(element);
return rect.width > 0 && rect.height > 0;
};

34

lib/Execution.js

@@ -21,4 +21,4 @@ 'use strict';

this.registeredDocuments = new Set();
this.timeoutTimers = new Map();
this._handleTimeoutTimer = this._handleTimeoutTimer.bind(this);
this.additionalCheckTimers = new Map();
this._handleAdditionalCheckTimer = this._handleAdditionalCheckTimer.bind(this);
this.createTimer = (timeout, handler) => new Timer(timeout, handler);

@@ -47,8 +47,9 @@ this.now = () => Date.now();

for (const expression of this.expressionChain) {
const {timeout} = expression.configuration;
if (!this.timeoutTimers.has(timeout)) {
const timer = this.createTimer(timeout, this._handleTimeoutTimer);
timer.schedule();
this.timeoutTimers.set(timeout, timer);
const {additionalCheckTimeout} = expression.configuration;
for (const timeout of additionalCheckTimeout) {
if (!this.additionalCheckTimers.has(timeout)) {
const timer = this.createTimer(timeout, this._handleAdditionalCheckTimer);
timer.schedule();
this.additionalCheckTimers.set(timeout, timer);
}
}

@@ -77,4 +78,5 @@ }

const now = this.now();
const currentDuration = now - this.executionStart;
const {executionStart} = this;
const checkStart = this.now();
const currentDuration = checkStart - executionStart;
const result = new ResultWrapper();

@@ -85,3 +87,7 @@ const documents = new Set();

for (const expression of this.expressionChain) {
const resultStatus = result.runAction(expression.configuration.action);
const metaData = Object.freeze({
executionStart,
checkStart,
});
const resultStatus = result.runAction(expression.configuration.action, metaData);

@@ -154,6 +160,6 @@ if (resultStatus === RESULT_STATUS_PENDING) {

for (const timer of this.timeoutTimers.values()) {
for (const timer of this.additionalCheckTimers.values()) {
timer.cancel();
}
this.timeoutTimers.clear();
this.additionalCheckTimers.clear();
}

@@ -176,3 +182,3 @@

_handleTimeoutTimer() {
_handleAdditionalCheckTimer() {
this.check();

@@ -179,0 +185,0 @@ }

@@ -47,2 +47,3 @@ 'use strict';

timeout,
additionalCheckTimeout: Object.freeze([timeout, ...action.additionalCheckTimeout]),
_executor: prevConfig ? prevConfig._executor : executor,

@@ -49,0 +50,0 @@ wantsDefaultAmountCheck,

@@ -93,4 +93,27 @@ 'use strict';

}
/**
* @param {number|string} timeout string in the format of "10s" to specify seconds or a number to specify milliseconds
* @return {ExpressionChainable}
*/
delay(timeout) {
return this.createNextExpression(new actions.Delay(timeout));
}
/**
* @return {ExpressionChainable}
*/
isDisplayed() {
return this.createNextExpression(new actions.IsDisplayed());
}
/**
* @param {function} callback
* @return {ExpressionChainable}
*/
check(callback) {
return this.createNextExpression(new actions.Check(callback));
}
}
module.exports = ExpressionChainable;

@@ -24,5 +24,5 @@ 'use strict';

runAction(action) {
runAction(action, metaData) {
try {
const {status, value, reasonStrings, reasonValues} = action.execute(this.value);
const {status, value, reasonStrings, reasonValues} = action.execute(this.value, metaData);

@@ -29,0 +29,0 @@ if (status !== RESULT_STATUS_SUCCESS && status !== RESULT_STATUS_PENDING && status !== RESULT_STATUS_FATAL_FAILURE) {

{
"name": "bluefox",
"version": "1.0.2",
"version": "1.1.0",
"description": "The bluefox library lets you be notified when a DOM tree has reached a specific condition, using a convenient syntax. It has been designed for high accuracy and low overhead.",

@@ -5,0 +5,0 @@ "main": "lib/bluefox.js",

@@ -11,5 +11,10 @@ # Bluefox

## Examples
```
npm i bluefox
```
### Webpack / Browserify
```javascript
const Bluefox = require('bluefox'); // browserify / webpack
// browserify / webpack / jsdom
const Bluefox = require('bluefox');
const wait = new Bluefox().target(window);

@@ -23,2 +28,3 @@ wait.timeout('5s').selector('section#main > div.contactInformation > a.viewProfile').then(link => {

### HTML Document
```html

@@ -30,2 +36,3 @@ <!DOCTYPE html>

<script src="node_modules/bluefox/standalone.js"></script>
<!-- <script src="node_modules/bluefox/standalone.min.js"></script> -->
<script>

@@ -55,3 +62,164 @@ (async () => {

```
### WebDriver
```javascript
const bluefoxString = require('bluefox/standalone.string.js');
// const bluefoxString = require('bluefox/standalone.min.string.js');
const wd = require('wd');
const browser = wd.promiseRemote('http://localhost:9515');
(async () => {
await browser.init({pageLoadStrategy: 'none'});
await browser.setAsyncScriptTimeout(30000);
await browser.get(`http://example.com`);
await browser.execute(bluefoxString);
await browser.execute(`wait = new Bluefox().target(window).timeout('10s')`);
const result = await browser.executeAsync(`
const resolve = arguments[arguments.length - 1];
wait.documentComplete().selector('p > a[href]')
.then(() => resolve({okay: true}))
.catch(err => resolve({error: err.toString()}))
`);
console.log('result:', result);
})();
```
## API
TODO
First, this library must by instantiated by calling its constructor:
```javascript
const Bluefox = require('bluefox');
const wait = new Bluefox();
```
Wait conditions are then defined by chaining together `actions` to form an `expression`. An `expression` is executed by consuming it as a Promise (`expression.then(...)`, `await expression`, etc).
During execution the `current value` is consumed and/or modified by the actions that make up the expression; the output of an action is used as the input of the next action. The `current value` must be either:
* `null`
* A `WindowProxy` instance
* A `HTMLDocument` instance
* An `Element` instance
* An array of `WindowProxy`, `HTMLDocument`, `Element` instances
For example the expression `await wait.target(document.body).selector('div').selector('p')` returns the first `<p>` element that is a descendant of the first `<div>` element that is the first descendant of the document's `<body>` element.
Some actions may cause the execution to remain pending based on their input value. For example `await wait.target(document).documentInteractive()` delays the fulfillment of the execution until the HTML of the document has been completely parsed (DOMContentLoaded).
An expression is immutable. This lets you execute it multiple times or base a new expression of an existing one.
### Available actions
#### .timeout(duration)
This action sets the timeout for all subsequent actions. If the timeout duration is reached, the Promise of the `execution` rejects with an `Error`. If this action is not specified, a default timeout of 30 seconds is used.
```javascript
await wait.target(document).documentComplete(); // 30 second timeout
await wait.target(document).timeout('1s').documentComplete(); // 1 second timeout
await wait.target(document).timeout(1500).documentComplete(); // 1.5 second timeout
```
#### .target(value)
The target action is used to simply set the `current value`. It is almost always used as the first action in the chain.
```javascript
await wait.target(window).selector('html')
await wait.target(document).documentInteractive()
await wait.target(document.body).check(body => body.classList.contains('foo'))
await wait.target([someElement, anotherElement]).selectorAll('p')
```
#### .amount(minimum, maximum)
This action causes the execution to remain pending if the `current value` has less than `minimum` or more than `maximum` objects. If this action is not specified, the execution waits until `current value` contains 1 or more objects. The `current value` is not modified by this action.
```javascript
await wait.target(window).selectorAll('img.thumbnail') // 1 or more
await wait.target(window).selectorAll('img.thumbnail').amount(1, Infinity) // 1 or more
await wait.target(window).selectorAll('img.thumbnail').amount(1) // exactly 1
await wait.target(window).selectorAll('img.thumbnail').amount(0) // exactly 0
await wait.target(window).selectorAll('img.thumbnail').amount(2, 4) // 2 or 3 or 4
```
#### .selector(cssSelector)
Return the first `Element` (or `null`) that matches the given CSS selector and is a descendant of any objects in `current value`.
```javascript
const link = await wait.target(window).selector('a.someLink');
link.click();
const anotherLink = await wait.target([someElement, anotherElement]).selector('a.someLink');
anotherLink.click();
```
#### .selectorAll(cssSelector)
Return all `Element` instances (as an array) that match the given CSS selector and are a descendant of any objects in `current value`.
```javascript
const links = await wait.target(window).selectorAll('.todoList a');
links.forEach(link => link.click());
```
#### .xpath(expression)
Execute the given XPath `expression` setting the `current value` as the XPath `context node` and return the first `Element` instance that matches. A result that is _not_ an `Element` will result in an error.
```javascript
await wait.target(window).xpath(`.//h1[./@id = 'introduction']`);
await wait.target(document.body).xpath(`./p`);
```
_Note: XPath expressions often cause more overhead than CSS Selectors._
#### .xpathAll(expression)
Execute the given XPath `expression` setting the `current value` as the XPath `context node` and return the all `Element` instances that match. A result that is _not_ an `Element` will result in an error.
```javascript
await wait.target(window).xpathAll(`.//a[@href]`).amount(10, Infinity);
await wait.target(document.body).xpathAll(`./p`).amount(0);
```
_Note: XPath expressions often cause more overhead than CSS Selectors._
#### .documentInteractive()
This action causes the execution to remain pending if any of the `HTMLDocument` instances in `current value` have a `readyState` that is not `"interative"` nor `"complete"`. If the `current value` contains any `Element` instances, the check will be performed on their `ownerDocument`. The `current value` is not modified by this action.
```javascript
window.addEventListener('DOMContentLoaded',
() => console.log('documentInteractive!')
);
await wait.target(document).documentInteractive();
await wait.target(document.body).documentInteractive();
```
#### .documentComplete()
This action causes the execution to remain pending if any of the `HTMLDocument` instances in `current value` have a `readyState` that is not `"complete"`. If the `current value` contains any `Element` instances, the check will be performed on their `ownerDocument`. The `current value` is not modified by this action.
```javascript
window.addEventListener('load',
() => console.log('documentComplete!')
);
await wait.target(document).documentComplete();
await wait.target(document.body).documentComplete();
```
#### .delay(duration)
This action causes the execution to remain pending until the given `duration` has passed (since the start of the execution).
```javascript
await wait.delay('2s'); // 2000ms
await wait.delay(2000); // 2000ms
```
#### .isDisplayed()
This action removes all elements from `current value` that are not currently displayed on the page. An element is "displayed" if it influences the rendering of the page. _(Specifically, `element.getBoundingClientRect()` returns a non zero `width` and `height`)._
```javascript
await wait.selector('.submitButton').isDisplayed()
await wait.selectorAll('.gallery img').isDisplayed().amount(10, 50);
```
#### .check(callback)
This action calls the given `callback` function for each item in `current value` and removes all items for which the callback returns `false`.
```javascript
await wait.selector('p.introduction').check(n => /hello/.test(n.textContent))
await wait.selector('img').check(n => img.complete).amount(10, Infinity)
```

@@ -285,4 +285,4 @@ (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Bluefox = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){

this.registeredDocuments = new Set();
this.timeoutTimers = new Map();
this._handleTimeoutTimer = this._handleTimeoutTimer.bind(this);
this.additionalCheckTimers = new Map();
this._handleAdditionalCheckTimer = this._handleAdditionalCheckTimer.bind(this);
this.createTimer = (timeout, handler) => new Timer(timeout, handler);

@@ -311,8 +311,9 @@ this.now = () => Date.now();

for (const expression of this.expressionChain) {
const {timeout} = expression.configuration;
if (!this.timeoutTimers.has(timeout)) {
const timer = this.createTimer(timeout, this._handleTimeoutTimer);
timer.schedule();
this.timeoutTimers.set(timeout, timer);
const {additionalCheckTimeout} = expression.configuration;
for (const timeout of additionalCheckTimeout) {
if (!this.additionalCheckTimers.has(timeout)) {
const timer = this.createTimer(timeout, this._handleAdditionalCheckTimer);
timer.schedule();
this.additionalCheckTimers.set(timeout, timer);
}
}

@@ -341,4 +342,5 @@ }

const now = this.now();
const currentDuration = now - this.executionStart;
const {executionStart} = this;
const checkStart = this.now();
const currentDuration = checkStart - executionStart;
const result = new ResultWrapper();

@@ -349,3 +351,7 @@ const documents = new Set();

for (const expression of this.expressionChain) {
const resultStatus = result.runAction(expression.configuration.action);
const metaData = Object.freeze({
executionStart,
checkStart,
});
const resultStatus = result.runAction(expression.configuration.action, metaData);

@@ -418,6 +424,6 @@ if (resultStatus === RESULT_STATUS_PENDING) {

for (const timer of this.timeoutTimers.values()) {
for (const timer of this.additionalCheckTimers.values()) {
timer.cancel();
}
this.timeoutTimers.clear();
this.additionalCheckTimers.clear();
}

@@ -440,3 +446,3 @@

_handleTimeoutTimer() {
_handleAdditionalCheckTimer() {
this.check();

@@ -495,2 +501,3 @@ }

timeout,
additionalCheckTimeout: Object.freeze([timeout, ...action.additionalCheckTimeout]),
_executor: prevConfig ? prevConfig._executor : executor,

@@ -674,2 +681,25 @@ wantsDefaultAmountCheck,

}
/**
* @param {number|string} timeout string in the format of "10s" to specify seconds or a number to specify milliseconds
* @return {ExpressionChainable}
*/
delay(timeout) {
return this.createNextExpression(new actions.Delay(timeout));
}
/**
* @return {ExpressionChainable}
*/
isDisplayed() {
return this.createNextExpression(new actions.IsDisplayed());
}
/**
* @param {function} callback
* @return {ExpressionChainable}
*/
check(callback) {
return this.createNextExpression(new actions.Check(callback));
}
}

@@ -737,4 +767,5 @@

documentReadyState,
hasFormattingBox,
} = require('./dom');
const {resultToArray, resultCount, executeSuccess, executePendingTag} = require('./result');
const {resultToArray, resultCount, executeSuccess, executePendingTag, executeFatalFailureTag} = require('./result');

@@ -750,2 +781,5 @@ const freezeCopyIfArray = value => {

const RIGHT_QUOTE = '\u201d';
const HORIZONTAL_ELLIPSIS = '\u2026';
const EMPTY_FROZEN_ARRAY = Object.freeze([]);
const CALLBACK_DESCRIPTION_MAX_LENGTH = 64;

@@ -764,8 +798,18 @@ exports.parseTimeoutArgument = timeout => {

exports.describeCallback = func => {
const funcString = func.toString();
if (funcString.length <= CALLBACK_DESCRIPTION_MAX_LENGTH) {
return funcString;
}
return funcString.slice(0, CALLBACK_DESCRIPTION_MAX_LENGTH - 1) + HORIZONTAL_ELLIPSIS;
};
class Action {
/**
* @param {?Window|Node|Array.<(Window|Node)>} currentResult
* @param {Object} metaData
* @return {{status: string, reasonStrings: string[], reasonValues: string[], value: (?Window|Node|Array.<(Window|Node)>)}}
*/
execute(currentResult) {
execute(currentResult, metaData) {
return executeSuccess(currentResult);

@@ -798,2 +842,10 @@ }

}
/**
* Schedule an additional check after this many milliseconds have passed since the start of the expression
* @return {number[]}
*/
get additionalCheckTimeout() {
return EMPTY_FROZEN_ARRAY;
}
}

@@ -831,3 +883,3 @@

if (!isResultItem(result)) {
return executePendingTag`a value that is not a Window nor a Node was set as the target`;
return executeFatalFailureTag`a value that is not a WindowProxy nor a HTMLDocument, nor an Element was set as the target`;
}

@@ -843,3 +895,3 @@ }

if (typeof results === 'function' && !isDOMNode(results)) {
return 'sets the target using a callback';
return `sets the target using a callback: \`${exports.describeCallback(results)}\``;
}

@@ -951,3 +1003,4 @@

if (typeof this.expression === 'function') {
return `finds the first descendant element matching a CSS selector from a callback`;
return `finds the first descendant element matching a CSS selector from ` +
`a callback: \`${exports.describeCallback(this.expression)}\``;
}

@@ -986,3 +1039,4 @@

if (typeof this.expression === 'function') {
return `finds all descendant elements matching a CSS selector from a callback`;
return `finds all descendant elements matching a CSS selector from a callback: ` +
`\`${exports.describeCallback(this.expression)}\``;
}

@@ -1011,2 +1065,6 @@

if (result && !isResultItem(result)) {
return executeFatalFailureTag`a value that is not an Element was returned by the XPath expression`;
}
if (result) {

@@ -1022,3 +1080,4 @@ return executeSuccess(result);

if (typeof this.expression === 'function') {
return `finds the first element matching a XPath expression from a callback`;
return `finds the first element matching a XPath expression from a callback: ` +
`\`${exports.describeCallback(this.expression)}\``;
}

@@ -1052,2 +1111,9 @@

Object.freeze(value);
for (const resultItem of value) {
if (!isResultItem(resultItem)) {
return executeFatalFailureTag`a value that is not an Element was returned by the XPath expression`;
}
}
return executeSuccess(value);

@@ -1058,3 +1124,4 @@ }

if (typeof this.expression === 'function') {
return `finds all elements matching a XPath expression from a callback`;
return `finds all elements matching a XPath expression from a callback: ` +
`\`${exports.describeCallback(this.expression)}\``;
}

@@ -1121,2 +1188,85 @@

class Delay extends Action {
constructor(timeout) {
super();
this.delayMs = exports.parseTimeoutArgument(timeout);
Object.freeze(this);
}
execute(currentResult, {executionStart, checkStart}) {
const {delayMs} = this;
const timeSinceStart = checkStart - executionStart;
if (timeSinceStart < delayMs) {
// eslint-disable-next-line max-len
return executePendingTag`the delay of ${delayMs / 1000} seconds has not yet elapsed, only ${timeSinceStart / 1000} seconds have elapsed so far`;
}
return executeSuccess(currentResult);
}
describe() {
return `waits until ${this.delayMs / 1000} seconds have elapsed since the start of the execution`;
}
get additionalCheckTimeout() {
return Object.freeze([this.delayMs]);
}
}
class IsDisplayed extends Action {
constructor() {
super();
Object.freeze(this);
}
execute(currentResult) {
if (!currentResult) {
return executeSuccess(currentResult);
}
if (Array.isArray(currentResult)) {
const result = currentResult.filter(object => hasFormattingBox(object));
return executeSuccess(Object.freeze(result));
}
const result = hasFormattingBox(currentResult) ? currentResult : null;
return executeSuccess(result);
}
describe() {
return `but only including elements which are displayed on the page`;
}
}
class Check extends Action {
constructor(callback) {
if (typeof callback !== 'function') {
throw Error('.check(callback): callback must be a function');
}
super();
this.callback = callback;
Object.freeze(this);
}
execute(currentResult) {
if (!currentResult) {
return executeSuccess(currentResult);
}
if (Array.isArray(currentResult)) {
const result = currentResult.filter(object => this.callback(object));
return executeSuccess(Object.freeze(result));
}
const result = this.callback(currentResult) ? currentResult : null;
return executeSuccess(result);
}
describe() {
return `but only including results that match a callback: \`${exports.describeCallback(this.callback)}\``;
}
}
const DEFAULT_AMOUNT_ACTION = new Amount(1, Infinity);

@@ -1135,2 +1285,5 @@

exports.DocumentComplete = DocumentComplete;
exports.Delay = Delay;
exports.IsDisplayed = IsDisplayed;
exports.Check = Check;

@@ -1266,2 +1419,11 @@ },{"./dom":9,"./result":10}],9:[function(require,module,exports){

/**
* @param {Window|Node} object
* @return {?HTMLHtmlElement}
*/
dom.resultItemToDocumentElement = object => {
const document = dom.resultItemToDocument(object);
return dom.findPropertyInChain(document, 'documentElement').get.call(document);
};
/**
* Find the closest object that implements the `ParentElement` interface, for the given result item

@@ -1288,3 +1450,20 @@ * @param {Window|Node} object

/**
* Find the closest object that implements the `Element` interface, for the given result item
* @param {Window|Node} object
* @return {Element}
*/
dom.resultItemToElement = object => {
if (dom.isDOMWindow(object) || dom.isDOMDocument(object)) {
return dom.resultItemToDocumentElement(object);
}
if (dom.isDOMElement(object)) {
return object;
}
throw Error('dom.resultItemToElement(): Invalid argument');
};
/**
* @param {Window|Node} object
* @return {string}

@@ -1403,2 +1582,21 @@ */

/**
* @param {Element} element
* @return {DOMRect}
*/
dom.getBoundingClientRect = element => {
const getBoundingClientRect = dom.findPropertyInChain(element, 'getBoundingClientRect');
return getBoundingClientRect.value.call(element);
};
/**
* @param {Window|Node} object
* @return {boolean}
*/
dom.hasFormattingBox = object => {
const element = dom.resultItemToElement(object);
const rect = dom.getBoundingClientRect(element);
return rect.width > 0 && rect.height > 0;
};
},{}],10:[function(require,module,exports){

@@ -1428,5 +1626,5 @@ 'use strict';

runAction(action) {
runAction(action, metaData) {
try {
const {status, value, reasonStrings, reasonValues} = action.execute(this.value);
const {status, value, reasonStrings, reasonValues} = action.execute(this.value, metaData);

@@ -1433,0 +1631,0 @@ if (status !== RESULT_STATUS_SUCCESS && status !== RESULT_STATUS_PENDING && status !== RESULT_STATUS_FATAL_FAILURE) {

@@ -1,1 +0,1 @@

!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var t;(t="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this).Bluefox=e()}}(function(){var e,t,n;return function e(t,n,i){function r(o,u){if(!n[o]){if(!t[o]){var c="function"==typeof require&&require;if(!u&&c)return c(o,!0);if(s)return s(o,!0);var a=new Error("Cannot find module '"+o+"'");throw a.code="MODULE_NOT_FOUND",a}var h=n[o]={exports:{}};t[o][0].call(h.exports,function(e){var n=t[o][1][e];return r(n||e)},h,h.exports,e,t,n,i)}return n[o].exports}for(var s="function"==typeof require&&require,o=0;o<i.length;o++)r(i[o]);return r}({1:[function(e,t,n){"use strict";const i=e("./ExpressionChainable"),r=e("./Expression"),s=e("./Execution"),o=e("./DocumentObservers"),u=e("./Timer");class c extends i{static setTimerFunctions(e,t){u.setTimeout=e,u.clearTimeout=t}constructor(){super(),this._expressionExecutor=this._expressionExecutor.bind(this),this._documentObservers=new o,this._nextExecutionId=0,this.onExecuteBegin=null,this.onExecuteEnd=null,this.onCheckBegin=null,this.onCheckEnd=null}createNextExpression(e,t=3e4){return new r(null,e,t,this._expressionExecutor)}runAllChecks(e){this._documentObservers.runAllChecks(e)}runAllChecksDeferred(e){this._documentObservers.runAllChecksDeferred(e)}async _expressionExecutor(e){const t=new s(e,this._documentObservers,this._nextExecutionId++),{onExecuteBegin:n,onExecuteEnd:i,onCheckBegin:r,onCheckEnd:o}=this;t.onCheckBegin=r,t.onCheckEnd=o,n&&n({expression:e,executionId:t.id,resultPromise:t.executionPromise});try{return await t.execute()}finally{i&&i({expression:e,executionId:t.id,resultPromise:t.executionPromise})}}}t.exports=c},{"./DocumentObservers":3,"./Execution":4,"./Expression":5,"./ExpressionChainable":6,"./Timer":7}],2:[function(e,t,n){"use strict";const{getDOMDocumentWindow:i,isDOMWindow:r,isDOMDocument:s,addEventListener:o,removeEventListener:u}=e("./dom"),c=e("./Timer");class a{constructor(e){if(!s(e))throw Error("new DocumentObserver(document): Invalid argument `document`");const t=i(e);if(!r(t))throw Error("new DocumentObserver(document): The given `document` must have a browsing context (a window)");this.document=e,this.window=t,this._handleChange=this._handleChange.bind(this),this._handleChangeDeferred=this._handleChangeDeferred.bind(this),this._handleDeferrals=this._handleDeferrals.bind(this),this._pendingExecutions=new Set,this._registeredListeners=!1,this._mutationObserver=null,this._hasDeferredChange=!1,this._removeListenersTimer=new c(0,()=>this.removeListeners()),this._deferralsTimer=new c(0,this._handleDeferrals)}get hasPendingExecutions(){return this._pendingExecutions.size>0}get hasRegisteredListeners(){return this._registeredListeners}register(e){this._pendingExecutions.add(e),this.registerListeners()}unregister(e){this._pendingExecutions.delete(e),this.hasPendingExecutions||this._removeListenersTimer.reschedule()}registerListeners(){if(this._removeListenersTimer.cancel(),this.hasRegisteredListeners)return;this._registeredListeners=!0;const{window:e,document:t}=this;o(e,"DOMContentLoaded",this._handleChange,!0),o(e,"load",this._handleChange,!0),o(t,"load",this._handleChangeDeferred,!0),o(t,"error",this._handleChangeDeferred,!0),this._mutationObserver=new this.window.MutationObserver(this._handleChangeDeferred),this._mutationObserver.observe(t,{attributeOldValue:!1,attributes:!0,characterData:!0,characterDataOldValue:!1,childList:!0,subtree:!0})}removeListeners(){if(!this.hasRegisteredListeners)return;const{window:e,document:t}=this;this._removeListenersTimer.cancel(),u(e,"DOMContentLoaded",this._handleChange,!0),u(e,"load",this._handleChange,!0),u(t,"load",this._handleChangeDeferred,!0),u(t,"error",this._handleChangeDeferred,!0),this._mutationObserver.disconnect(),this._mutationObserver=null,this._deferralsTimer.cancel(),this._registeredListeners=!1}runChecks(){this._hasDeferredChange=!1,this._deferralsTimer.cancel();for(const e of this._pendingExecutions)e.check()}runChecksDeferred(){this._hasDeferredChange=!0,this._deferralsTimer.schedule()}drainDeferrals(){this._handleDeferrals()}_handleChange(){this.runChecks()}_handleChangeDeferred(){this._hasDeferredChange=!0,this._deferralsTimer.schedule()}_handleDeferrals(){this._hasDeferredChange&&(this._hasDeferredChange=!1,this.runChecks())}}t.exports=a},{"./Timer":7,"./dom":9}],3:[function(e,t,n){"use strict";const i=e("./DocumentObserver");class r{constructor(){this._documentToObserver=new WeakMap}_getOrCreate(e){let t=this._documentToObserver.get(e);return t||(t=new i(e),this._documentToObserver.set(e,t)),t}registerExecution(e,t){this._getOrCreate(e).register(t)}unregisterExecution(e,t){const n=this._documentToObserver.get(e);n&&n.unregister(t)}runAllChecks(e){const t=this._documentToObserver.get(e);t&&t.runChecks()}runAllChecksDeferred(e){const t=this._documentToObserver.get(e);t&&t.runChecksDeferred()}drainDeferrals(e){const t=this._documentToObserver.get(e);t&&t.drainDeferrals()}}t.exports=r},{"./DocumentObserver":2}],4:[function(e,t,n){"use strict";const{ResultWrapper:i,RESULT_STATUS_SUCCESS:r,RESULT_STATUS_PENDING:s}=e("./result"),o=e("./Timer");class u{constructor(e,t,n){this.expression=e,this.expressionChain=e.getExpressionChain(),this.documentObservers=t,this.id=n,this.onCheckBegin=null,this.onCheckEnd=null,this.executionPromise=new Promise((e,t)=>{this.executionResolve=e;this.executionReject=t}),this.executionStart=null,this.didFirstCheck=!1,this.fulfilled=!1,this.registeredDocuments=new Set,this.timeoutTimers=new Map,this._handleTimeoutTimer=this._handleTimeoutTimer.bind(this),this.createTimer=((e,t)=>new o(e,t)),this.now=(()=>Date.now())}async execute(){return this.didFirstCheck||this.firstCheck(),this.executionPromise}firstCheck(){if(this.didFirstCheck)throw Error("Invalid state");this.didFirstCheck=!0,this.executionStart=this.now();for(const e of this.expressionChain){const{timeout:t}=e.configuration;if(!this.timeoutTimers.has(t)){const e=this.createTimer(t,this._handleTimeoutTimer);e.schedule(),this.timeoutTimers.set(t,e)}}this.check()}check(){if(!this.didFirstCheck)throw Error("Execution#check(): This execution has not been started");if(this.fulfilled)throw Error("Execution#check(): This execution has already been fulfilled");const{onCheckBegin:e,onCheckEnd:t}=this;e&&e({expression:this.expression,executionId:this.id,resultPromise:this.executionPromise});const n=this.now()-this.executionStart,o=new i,u=new Set;let c=!1;for(const e of this.expressionChain){const t=o.runAction(e.configuration.action);if(t===s&&(c=e),t!==r)break;o.addDOMDocumentsToSet(u)}if(c){const{timeout:e}=c.configuration;n>=e?(this.fulfilled=!0,this.cleanup(),this.executionReject(this.timeoutError(e,o,c))):this.updateDocumentRegistrations(u)}else this.fulfill(o);t&&t({expression:this.expression,executionId:this.id,resultPromise:this.executionPromise})}timeoutError(e,t,n){const i=t.failureString(),r=`Wait expression timed out after ${e/1e3} seconds because ${i}. `+n.describe(),s=new Error(r);return s.timeout=e,s.actionFailure=i,s.expression=n,s.fullExpression=this.expression,s}updateDocumentRegistrations(e){for(const t of this.registeredDocuments)e.has(t)||this.documentObservers.unregisterExecution(t,this);for(const t of e)this.documentObservers.registerExecution(t,this);this.registeredDocuments=e}cleanup(){for(const e of this.registeredDocuments)this.documentObservers.unregisterExecution(e,this);this.registeredDocuments.clear();for(const e of this.timeoutTimers.values())e.cancel();this.timeoutTimers.clear()}fulfill(e){if(this.fulfilled=!0,this.cleanup(),e.lastResultStatus===r)this.executionResolve(e.value);else{const t=e.errorObject?e.errorObject:Error(e.failureString());this.executionReject(t)}}_handleTimeoutTimer(){this.check()}}t.exports=u},{"./Timer":7,"./result":10}],5:[function(e,t,n){"use strict";const i=e("./ExpressionChainable"),{DEFAULT_AMOUNT_ACTION:r}=e("./actions");if(!r.appliesAmountCheck)throw Error("Assertion Error");class s extends i{constructor(e,t,n,i){if(super(),null!==e&&!(e instanceof s))throw Error("Invalid argument `previous`");if(Boolean(e)===Boolean(i))throw Error("`executor` must (only) be set for the root Expression");if(!t||"object"!=typeof t||"function"!=typeof t.execute||"function"!=typeof t.describe)throw Error("Invalid argument `action`");if("number"!=typeof n)throw Error("Invalid argument `timeout`");const o=e&&e.configuration,u=(o&&o.wantsDefaultAmountCheck||t.wantsDefaultAmountCheck)&&!t.appliesAmountCheck;Object.defineProperty(this,"configuration",{value:{previous:e,depth:o?o.depth+1:0,action:t,timeout:n,_executor:o?o._executor:i,wantsDefaultAmountCheck:u,_defaultAmountExpression:null}}),this.configuration._defaultAmountExpression=u?new s(this,r,n):null,Object.freeze(this.configuration),Object.freeze(this)}getExpressionChain(){const{_defaultAmountExpression:e}=this.configuration;if(e)return e.getExpressionChain();const t=this.configuration.depth+1,n=new Array(t);let i=this;for(let e=t-1;e>=0;--e){n[e]=i;const{previous:t}=i.configuration;i=t}if(i)throw Error("Assertion Error");return n}createNextExpression(e,t=this.configuration.timeout){return new s(this,e,t)}describe(){const e=[];for(const t of this.getExpressionChain()){const{configuration:n}=t,i=n.action.describe(n.timeout);i&&e.push(i)}return`The expression ${e.join(", ")}.`}async execute(){return await this.configuration._executor(this)}then(...e){return this.execute().then(...e)}catch(...e){return this.execute().catch(...e)}finally(e){return this.then(t=>Promise.resolve(e()).then(()=>t),t=>Promise.resolve(e()).then(()=>Promise.reject(t)))}}t.exports=s},{"./ExpressionChainable":6,"./actions":8}],6:[function(e,t,n){"use strict";const i=e("./actions");class r{action(e){return this.createNextExpression(e)}target(e){return this.createNextExpression(new i.Target(e))}timeout(e){const t=i.parseTimeoutArgument(e);return this.createNextExpression(new i.Noop,t)}amount(e,t){return this.createNextExpression(new i.Amount(e,t))}selector(e){return this.createNextExpression(new i.Selector(e))}selectorAll(e){return this.createNextExpression(new i.SelectorAll(e))}xpath(e){return this.createNextExpression(new i.XPath(e))}xpathAll(e){return this.createNextExpression(new i.XPathAll(e))}documentInteractive(){return this.createNextExpression(new i.DocumentInteractive)}documentComplete(){return this.createNextExpression(new i.DocumentComplete)}}t.exports=r},{"./actions":8}],7:[function(e,t,n){"use strict";class i{constructor(e,t){this._id=0,this.delay=e,this.callback=t,this.setTimeout=i.setTimeout,this.clearTimeout=i.clearTimeout,this._timerCallback=(()=>{this._id=0;this.callback.call(null)})}get isScheduled(){return Boolean(this._id)}schedule(){this._id||(this._id=this.setTimeout(this._timerCallback,this.delay))}cancel(){this.isScheduled&&(this.clearTimeout(this._id),this._id=0)}reschedule(){this.cancel(),this.schedule()}}i.setTimeout=((e,t)=>setTimeout(e,t)),i.clearTimeout=(e=>clearTimeout(e)),t.exports=i},{}],8:[function(e,t,n){"use strict";const{isResultItem:i,isDOMNode:r,describeDOMObject:s,cssSelectorFirst:o,cssSelectorArray:u,xpathFirst:c,xpathArray:a,resultItemToDocument:h,documentReadyState:f}=e("./dom"),{resultToArray:l,resultCount:m,executeSuccess:d,executePendingTag:p}=e("./result"),x=e=>{if(Array.isArray(e))return Object.freeze(e.slice());return e},g=e=>"function"==typeof e?e():e,b="“",O="”";n.parseTimeoutArgument=(e=>{if("string"==typeof e&&/^([\d.]+)s$/.test(e))return 1e3*parseFloat(e);if("number"==typeof e)return e;throw Error("Invalid timeout argument, expected a number or a duration string")});class D{execute(e){return d(e)}describe(e){return""}get wantsDefaultAmountCheck(){return!1}get appliesAmountCheck(){return!1}}class E extends D{constructor(){super(),Object.freeze(this)}execute(e){return d(e)}describe(){return""}}class T extends D{constructor(e){super(),this.results=x(e),Object.freeze(this)}execute(e){const t=x(g(this.results));for(const e of l(t))if(!i(e))return p`a value that is not a Window nor a Node was set as the target`;return d(t)}describe(){const e=this.results;if("function"==typeof e&&!r(e))return"sets the target using a callback";if(Array.isArray(e)){const t=[];for(const n of e){if(t.length>=5){t.push("…");break}t.push(s(n))}return`sets the target to [${t.join(", ")}]`}return`sets the target to ${s(e)}`}}class v extends D{constructor(e,t=e){if(super(),this.minimum=e,this.maximum=t,"number"!=typeof this.minimum)throw Error(".amount(minimum, maximum): minimum must be a number");if("number"!=typeof this.maximum)throw Error(".amount(minimum, maximum): maximum must be a number");if(this.minimum>this.maximum)throw Error(".amount(minimum, maximum): maximum must be greater than or equal to minimum");Object.freeze(this)}execute(e){const t=m(e);return t<this.minimum?0===t?p`no results were found, instead of a minimum of ${this.minimum} results`:p`only ${t} results were found, instead of a minimum of ${this.minimum} results`:t>this.maximum?p`${t} results were found, instead of a maximum of ${this.maximum} results`:d(e)}describe(e){const t=`waits up to ${e/1e3} seconds until`;return this.minimum===this.maximum?`${t} exactly ${this.minimum} results are found`:1===this.minimum&&this.maximum===1/0?`${t} a result is found`:this.maximum===1/0?`${t} ${this.minimum} or more results are found`:`${t} between ${this.minimum} and ${this.maximum} (inclusive) results are found`}get appliesAmountCheck(){return!0}}class w extends D{constructor(e){super(),this.expression=e,Object.freeze(this)}execute(e){const t=g(this.expression);for(const n of l(e)){const e=o(n,t);if(e)return d(e)}return d(null)}describe(){return"function"==typeof this.expression?`finds the first descendant element matching a CSS selector from a callback`:`finds the first descendant element matching the CSS selector ${b}${this.expression}${O}`}get wantsDefaultAmountCheck(){return!0}}class _ extends D{constructor(e){super(),this.expression=e,Object.freeze(this)}execute(e){const t=g(this.expression),n=[];for(const i of l(e)){const e=u(i,t);n.push(e)}const i=[].concat(...n);return Object.freeze(i),d(i)}describe(){return"function"==typeof this.expression?`finds all descendant elements matching a CSS selector from a callback`:`finds all descendant elements matching the CSS selector ${b}${this.expression}${O}`}get wantsDefaultAmountCheck(){return!0}}class C extends D{constructor(e){super(),this.expression=e,Object.freeze(this)}execute(e){const t=g(this.expression);for(const n of l(e)){const e=c(n,t);if(e)return d(e)}return d(null)}describe(){return"function"==typeof this.expression?`finds the first element matching a XPath expression from a callback`:`finds the first element matching the XPath expression ${b}${this.expression}${O}`}get wantsDefaultAmountCheck(){return!0}}class y extends D{constructor(e){super(),this.expression=e,Object.freeze(this)}execute(e){const t=g(this.expression),n=[];for(const i of l(e)){const e=a(i,t);n.push(e)}const i=[].concat(...n);return Object.freeze(i),d(i)}describe(){return"function"==typeof this.expression?`finds all elements matching a XPath expression from a callback`:`finds all elements matching the XPath expression ${b}${this.expression}${O}`}get wantsDefaultAmountCheck(){return!0}}class S extends D{constructor(){super(),Object.freeze(this)}execute(e){for(const t of l(e)){const e=h(t);if("loading"===f(e))return p`the HTML document has not yet been parsed`}return d(e)}describe(e){return`waits up to ${e/1e3} seconds until the HTML document has finished parsing`}}class A extends D{constructor(){super(),Object.freeze(this)}execute(e){for(const t of l(e)){const e=h(t),n=f(e);if("loading"===n)return p`the HTML document has not yet been parsed`;if("interactive"===n)return p`the HTML document has not yet been loaded`}return d(e)}describe(e){return`waits up to ${e/1e3} seconds until all synchronous resources of the HTML document have been loaded`}}const I=new v(1,1/0);n.Action=D,n.Noop=E,n.Target=T,n.Amount=v,n.DEFAULT_AMOUNT_ACTION=I,n.Selector=w,n.SelectorAll=_,n.XPath=C,n.XPathAll=y,n.DocumentInteractive=S,n.DocumentComplete=A},{"./dom":9,"./result":10}],9:[function(e,t,n){"use strict";const i=1,r=7,s=9,o=n,u=e=>Object.prototype.toString.call(e);o.findPropertyInChain=((e,t)=>{let n=Object.getPrototypeOf(e);for(;n;){const e=Object.getOwnPropertyDescriptor(n,t);if(e)return e;n=Object.getPrototypeOf(n)}return null}),o.isDOMWindow=(e=>Boolean(e&&e.window===e&&e.self===e&&o.isDOMDocument(e.document))),o.isDOMNode=(e=>Boolean(e&&("object"==typeof e||"function"==typeof e)&&"nodeType"in e&&"nodeName"in e&&"ownerDocument"in e&&"parentNode"in e)),o.isDOMDocument=(e=>Boolean(o.isDOMNode(e)&&"defaultView"in e&&("[object HTMLDocument]"===u(e)||"[object Document]"===u(e)))),o.isDOMElement=(e=>Boolean(o.isDOMNode(e)&&(1===e.nodeType||"[object HTMLFormElement]"===u(e))&&"tagName"in e)),o.getDOMDocumentWindow=(e=>{const t=o.findPropertyInChain(e,"defaultView");return t.get.call(e)}),o.isResultItem=(e=>Boolean(o.isDOMWindow(e)||o.isDOMDocument(e)||o.isDOMElement(e))),o.resultItemToWindow=(e=>{if(o.isDOMWindow(e))return e;if(o.isDOMDocument(e))return o.getDOMDocumentWindow(e);if(o.isDOMNode(e)){const t=o.findPropertyInChain(e,"ownerDocument");return o.getDOMDocumentWindow(t.get.call(e))}throw Error("dom.resultItemToWindow(): Invalid argument")}),o.resultItemToDocument=(e=>{if(o.isDOMWindow(e))return e.document;if(o.isDOMDocument(e))return e;if(o.isDOMNode(e)){const t=o.findPropertyInChain(e,"ownerDocument");return t.get.call(e)}throw Error("dom.resultItemToDocument(): Invalid argument")}),o.resultItemToParentNode=(e=>{if(o.isDOMWindow(e))return e.document;if(o.isDOMDocument(e))return e;if(o.isDOMElement(e))return e;throw Error("dom.resultItemToParentNode(): Invalid argument")}),o.describeDOMObject=(e=>{if(void 0===e)return"<#undefined>";if(null===e)return"<#null>";if(o.isDOMWindow(e))return"<#window>";if(o.isDOMDocument(e))return"<#document>";if("[object HTMLFormElement]"===u(e))return"<form>";if(o.isDOMNode(e))return`<${e.nodeName.toLowerCase()}>`;return"<???>"}),o.cssSelectorFirst=((e,t)=>{const n=o.resultItemToParentNode(e);const i=o.findPropertyInChain(n,"querySelector").value;return i.call(n,t)}),o.cssSelectorArray=((e,t)=>{const n=o.resultItemToParentNode(e);const i=o.findPropertyInChain(n,"querySelectorAll").value;return Array.from(i.call(n,t))}),o.xpathFirst=((e,t)=>{const n=o.resultItemToDocument(e);const i=o.resultItemToParentNode(e);const r=o.findPropertyInChain(n,"evaluate").value;const s=r.call(n,t,i,null,9,null);return s.singleNodeValue}),o.xpathArray=((e,t)=>{const n=o.resultItemToDocument(e);const i=o.resultItemToParentNode(e);const r=o.findPropertyInChain(n,"evaluate").value;const s=r.call(n,t,i,null,7,null);const u=new Array(s.snapshotLength);for(let e=0;e<u.length;++e)u[e]=s.snapshotItem(e);return u}),o.documentReadyState=(e=>{const t=o.findPropertyInChain(e,"readyState");return t.get.call(e)}),o.addEventListener=((e,...t)=>{if(o.isDOMNode(e)){const n=o.findPropertyInChain(e,"addEventListener");return n.value.apply(e,t)}return e.addEventListener(...t)}),o.removeEventListener=((e,...t)=>{if(o.isDOMNode(e)){const n=o.findPropertyInChain(e,"removeEventListener");return n.value.apply(e,t)}return e.removeEventListener(...t)})},{}],10:[function(e,t,n){"use strict";const{resultItemToDocument:i}=e("./dom"),r="success",s="pending",o="fatal failure";n.ResultWrapper=class e{constructor(){this.value=null,this.reasonStrings=null,this.reasonValues=null,this.errorObject=null,this.lastResultStatus=null}runAction(e){try{const{status:t,value:n,reasonStrings:i,reasonValues:u}=e.execute(this.value);if(t!==r&&t!==s&&t!==o)throw Error('runAction: Invalid "status" value returned from action.execute()');return this.value=n,this.lastResultStatus=t,t===r?(this.reasonStrings=null,this.reasonValues=null,this.errorObject=null,this.lastResultStatus):(this.reasonStrings=i,this.reasonValues=u,this.lastResultStatus)}catch(e){return this.value=null,this.reasonStrings=null,this.reasonValues=null,this.errorObject=e,this.lastResultStatus=o,this.lastResultStatus}}addDOMDocumentsToSet(e){if(Array.isArray(this.value))for(const t of this.value)e.add(i(t));else this.value&&e.add(i(this.value))}failureString(){return this.reasonStrings?n.buildStringFromTagValues(this.reasonStrings,this.reasonValues):this.errorObject?this.errorObject.toString():null}},n.resultToArray=(e=>{if(Array.isArray(e))return e;if(void 0===e||null===e)return[];return[e]}),n.resultCount=(e=>{if(Array.isArray(e))return e.length;if(void 0===e||null===e)return 0;return 1}),n.buildStringFromTagValues=((e,t)=>{let n=e[0];for(let i=1;i<e.length;++i)n+=String(t[i-1]),n+=e[i];return n}),n.executeSuccess=(e=>Object.freeze({status:r,value:e})),n.executePendingTag=((e,...t)=>Object.freeze({status:s,reasonStrings:Object.freeze(e),reasonValues:Object.freeze(t),value:null})),n.executeFatalFailureTag=((e,...t)=>Object.freeze({status:o,reasonStrings:Object.freeze(e),reasonValues:Object.freeze(t),value:null})),n.RESULT_STATUS_SUCCESS=r,n.RESULT_STATUS_PENDING=s,n.RESULT_STATUS_FATAL_FAILURE=o},{"./dom":9}]},{},[1])(1)});
!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var t;(t="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this).Bluefox=e()}}(function(){var e,t,n;return function e(t,n,i){function r(o,u){if(!n[o]){if(!t[o]){var c="function"==typeof require&&require;if(!u&&c)return c(o,!0);if(s)return s(o,!0);var a=new Error("Cannot find module '"+o+"'");throw a.code="MODULE_NOT_FOUND",a}var h=n[o]={exports:{}};t[o][0].call(h.exports,function(e){var n=t[o][1][e];return r(n||e)},h,h.exports,e,t,n,i)}return n[o].exports}for(var s="function"==typeof require&&require,o=0;o<i.length;o++)r(i[o]);return r}({1:[function(e,t,n){"use strict";const i=e("./ExpressionChainable"),r=e("./Expression"),s=e("./Execution"),o=e("./DocumentObservers"),u=e("./Timer");class c extends i{static setTimerFunctions(e,t){u.setTimeout=e,u.clearTimeout=t}constructor(){super(),this._expressionExecutor=this._expressionExecutor.bind(this),this._documentObservers=new o,this._nextExecutionId=0,this.onExecuteBegin=null,this.onExecuteEnd=null,this.onCheckBegin=null,this.onCheckEnd=null}createNextExpression(e,t=3e4){return new r(null,e,t,this._expressionExecutor)}runAllChecks(e){this._documentObservers.runAllChecks(e)}runAllChecksDeferred(e){this._documentObservers.runAllChecksDeferred(e)}async _expressionExecutor(e){const t=new s(e,this._documentObservers,this._nextExecutionId++),{onExecuteBegin:n,onExecuteEnd:i,onCheckBegin:r,onCheckEnd:o}=this;t.onCheckBegin=r,t.onCheckEnd=o,n&&n({expression:e,executionId:t.id,resultPromise:t.executionPromise});try{return await t.execute()}finally{i&&i({expression:e,executionId:t.id,resultPromise:t.executionPromise})}}}t.exports=c},{"./DocumentObservers":3,"./Execution":4,"./Expression":5,"./ExpressionChainable":6,"./Timer":7}],2:[function(e,t,n){"use strict";const{getDOMDocumentWindow:i,isDOMWindow:r,isDOMDocument:s,addEventListener:o,removeEventListener:u}=e("./dom"),c=e("./Timer");class a{constructor(e){if(!s(e))throw Error("new DocumentObserver(document): Invalid argument `document`");const t=i(e);if(!r(t))throw Error("new DocumentObserver(document): The given `document` must have a browsing context (a window)");this.document=e,this.window=t,this._handleChange=this._handleChange.bind(this),this._handleChangeDeferred=this._handleChangeDeferred.bind(this),this._handleDeferrals=this._handleDeferrals.bind(this),this._pendingExecutions=new Set,this._registeredListeners=!1,this._mutationObserver=null,this._hasDeferredChange=!1,this._removeListenersTimer=new c(0,()=>this.removeListeners()),this._deferralsTimer=new c(0,this._handleDeferrals)}get hasPendingExecutions(){return this._pendingExecutions.size>0}get hasRegisteredListeners(){return this._registeredListeners}register(e){this._pendingExecutions.add(e),this.registerListeners()}unregister(e){this._pendingExecutions.delete(e),this.hasPendingExecutions||this._removeListenersTimer.reschedule()}registerListeners(){if(this._removeListenersTimer.cancel(),this.hasRegisteredListeners)return;this._registeredListeners=!0;const{window:e,document:t}=this;o(e,"DOMContentLoaded",this._handleChange,!0),o(e,"load",this._handleChange,!0),o(t,"load",this._handleChangeDeferred,!0),o(t,"error",this._handleChangeDeferred,!0),this._mutationObserver=new this.window.MutationObserver(this._handleChangeDeferred),this._mutationObserver.observe(t,{attributeOldValue:!1,attributes:!0,characterData:!0,characterDataOldValue:!1,childList:!0,subtree:!0})}removeListeners(){if(!this.hasRegisteredListeners)return;const{window:e,document:t}=this;this._removeListenersTimer.cancel(),u(e,"DOMContentLoaded",this._handleChange,!0),u(e,"load",this._handleChange,!0),u(t,"load",this._handleChangeDeferred,!0),u(t,"error",this._handleChangeDeferred,!0),this._mutationObserver.disconnect(),this._mutationObserver=null,this._deferralsTimer.cancel(),this._registeredListeners=!1}runChecks(){this._hasDeferredChange=!1,this._deferralsTimer.cancel();for(const e of this._pendingExecutions)e.check()}runChecksDeferred(){this._hasDeferredChange=!0,this._deferralsTimer.schedule()}drainDeferrals(){this._handleDeferrals()}_handleChange(){this.runChecks()}_handleChangeDeferred(){this._hasDeferredChange=!0,this._deferralsTimer.schedule()}_handleDeferrals(){this._hasDeferredChange&&(this._hasDeferredChange=!1,this.runChecks())}}t.exports=a},{"./Timer":7,"./dom":9}],3:[function(e,t,n){"use strict";const i=e("./DocumentObserver");class r{constructor(){this._documentToObserver=new WeakMap}_getOrCreate(e){let t=this._documentToObserver.get(e);return t||(t=new i(e),this._documentToObserver.set(e,t)),t}registerExecution(e,t){this._getOrCreate(e).register(t)}unregisterExecution(e,t){const n=this._documentToObserver.get(e);n&&n.unregister(t)}runAllChecks(e){const t=this._documentToObserver.get(e);t&&t.runChecks()}runAllChecksDeferred(e){const t=this._documentToObserver.get(e);t&&t.runChecksDeferred()}drainDeferrals(e){const t=this._documentToObserver.get(e);t&&t.drainDeferrals()}}t.exports=r},{"./DocumentObserver":2}],4:[function(e,t,n){"use strict";const{ResultWrapper:i,RESULT_STATUS_SUCCESS:r,RESULT_STATUS_PENDING:s}=e("./result"),o=e("./Timer");class u{constructor(e,t,n){this.expression=e,this.expressionChain=e.getExpressionChain(),this.documentObservers=t,this.id=n,this.onCheckBegin=null,this.onCheckEnd=null,this.executionPromise=new Promise((e,t)=>{this.executionResolve=e;this.executionReject=t}),this.executionStart=null,this.didFirstCheck=!1,this.fulfilled=!1,this.registeredDocuments=new Set,this.additionalCheckTimers=new Map,this._handleAdditionalCheckTimer=this._handleAdditionalCheckTimer.bind(this),this.createTimer=((e,t)=>new o(e,t)),this.now=(()=>Date.now())}async execute(){return this.didFirstCheck||this.firstCheck(),this.executionPromise}firstCheck(){if(this.didFirstCheck)throw Error("Invalid state");this.didFirstCheck=!0,this.executionStart=this.now();for(const e of this.expressionChain){const{additionalCheckTimeout:t}=e.configuration;for(const e of t)if(!this.additionalCheckTimers.has(e)){const t=this.createTimer(e,this._handleAdditionalCheckTimer);t.schedule(),this.additionalCheckTimers.set(e,t)}}this.check()}check(){if(!this.didFirstCheck)throw Error("Execution#check(): This execution has not been started");if(this.fulfilled)throw Error("Execution#check(): This execution has already been fulfilled");const{onCheckBegin:e,onCheckEnd:t}=this;e&&e({expression:this.expression,executionId:this.id,resultPromise:this.executionPromise});const{executionStart:n}=this,o=this.now(),u=o-n,c=new i,a=new Set;let h=!1;for(const e of this.expressionChain){const t=Object.freeze({executionStart:n,checkStart:o}),i=c.runAction(e.configuration.action,t);if(i===s&&(h=e),i!==r)break;c.addDOMDocumentsToSet(a)}if(h){const{timeout:e}=h.configuration;u>=e?(this.fulfilled=!0,this.cleanup(),this.executionReject(this.timeoutError(e,c,h))):this.updateDocumentRegistrations(a)}else this.fulfill(c);t&&t({expression:this.expression,executionId:this.id,resultPromise:this.executionPromise})}timeoutError(e,t,n){const i=t.failureString(),r=`Wait expression timed out after ${e/1e3} seconds because ${i}. `+n.describe(),s=new Error(r);return s.timeout=e,s.actionFailure=i,s.expression=n,s.fullExpression=this.expression,s}updateDocumentRegistrations(e){for(const t of this.registeredDocuments)e.has(t)||this.documentObservers.unregisterExecution(t,this);for(const t of e)this.documentObservers.registerExecution(t,this);this.registeredDocuments=e}cleanup(){for(const e of this.registeredDocuments)this.documentObservers.unregisterExecution(e,this);this.registeredDocuments.clear();for(const e of this.additionalCheckTimers.values())e.cancel();this.additionalCheckTimers.clear()}fulfill(e){if(this.fulfilled=!0,this.cleanup(),e.lastResultStatus===r)this.executionResolve(e.value);else{const t=e.errorObject?e.errorObject:Error(e.failureString());this.executionReject(t)}}_handleAdditionalCheckTimer(){this.check()}}t.exports=u},{"./Timer":7,"./result":10}],5:[function(e,t,n){"use strict";const i=e("./ExpressionChainable"),{DEFAULT_AMOUNT_ACTION:r}=e("./actions");if(!r.appliesAmountCheck)throw Error("Assertion Error");class s extends i{constructor(e,t,n,i){if(super(),null!==e&&!(e instanceof s))throw Error("Invalid argument `previous`");if(Boolean(e)===Boolean(i))throw Error("`executor` must (only) be set for the root Expression");if(!t||"object"!=typeof t||"function"!=typeof t.execute||"function"!=typeof t.describe)throw Error("Invalid argument `action`");if("number"!=typeof n)throw Error("Invalid argument `timeout`");const o=e&&e.configuration,u=(o&&o.wantsDefaultAmountCheck||t.wantsDefaultAmountCheck)&&!t.appliesAmountCheck;Object.defineProperty(this,"configuration",{value:{previous:e,depth:o?o.depth+1:0,action:t,timeout:n,additionalCheckTimeout:Object.freeze([n,...t.additionalCheckTimeout]),_executor:o?o._executor:i,wantsDefaultAmountCheck:u,_defaultAmountExpression:null}}),this.configuration._defaultAmountExpression=u?new s(this,r,n):null,Object.freeze(this.configuration),Object.freeze(this)}getExpressionChain(){const{_defaultAmountExpression:e}=this.configuration;if(e)return e.getExpressionChain();const t=this.configuration.depth+1,n=new Array(t);let i=this;for(let e=t-1;e>=0;--e){n[e]=i;const{previous:t}=i.configuration;i=t}if(i)throw Error("Assertion Error");return n}createNextExpression(e,t=this.configuration.timeout){return new s(this,e,t)}describe(){const e=[];for(const t of this.getExpressionChain()){const{configuration:n}=t,i=n.action.describe(n.timeout);i&&e.push(i)}return`The expression ${e.join(", ")}.`}async execute(){return await this.configuration._executor(this)}then(...e){return this.execute().then(...e)}catch(...e){return this.execute().catch(...e)}finally(e){return this.then(t=>Promise.resolve(e()).then(()=>t),t=>Promise.resolve(e()).then(()=>Promise.reject(t)))}}t.exports=s},{"./ExpressionChainable":6,"./actions":8}],6:[function(e,t,n){"use strict";const i=e("./actions");class r{action(e){return this.createNextExpression(e)}target(e){return this.createNextExpression(new i.Target(e))}timeout(e){const t=i.parseTimeoutArgument(e);return this.createNextExpression(new i.Noop,t)}amount(e,t){return this.createNextExpression(new i.Amount(e,t))}selector(e){return this.createNextExpression(new i.Selector(e))}selectorAll(e){return this.createNextExpression(new i.SelectorAll(e))}xpath(e){return this.createNextExpression(new i.XPath(e))}xpathAll(e){return this.createNextExpression(new i.XPathAll(e))}documentInteractive(){return this.createNextExpression(new i.DocumentInteractive)}documentComplete(){return this.createNextExpression(new i.DocumentComplete)}delay(e){return this.createNextExpression(new i.Delay(e))}isDisplayed(){return this.createNextExpression(new i.IsDisplayed)}check(e){return this.createNextExpression(new i.Check(e))}}t.exports=r},{"./actions":8}],7:[function(e,t,n){"use strict";class i{constructor(e,t){this._id=0,this.delay=e,this.callback=t,this.setTimeout=i.setTimeout,this.clearTimeout=i.clearTimeout,this._timerCallback=(()=>{this._id=0;this.callback.call(null)})}get isScheduled(){return Boolean(this._id)}schedule(){this._id||(this._id=this.setTimeout(this._timerCallback,this.delay))}cancel(){this.isScheduled&&(this.clearTimeout(this._id),this._id=0)}reschedule(){this.cancel(),this.schedule()}}i.setTimeout=((e,t)=>setTimeout(e,t)),i.clearTimeout=(e=>clearTimeout(e)),t.exports=i},{}],8:[function(e,t,n){"use strict";const{isResultItem:i,isDOMNode:r,describeDOMObject:s,cssSelectorFirst:o,cssSelectorArray:u,xpathFirst:c,xpathArray:a,resultItemToDocument:h,documentReadyState:l,hasFormattingBox:f}=e("./dom"),{resultToArray:m,resultCount:d,executeSuccess:p,executePendingTag:x,executeFatalFailureTag:g}=e("./result"),b=e=>{if(Array.isArray(e))return Object.freeze(e.slice());return e},O=e=>"function"==typeof e?e():e,D="“",E="”",T="…",C=Object.freeze([]),w=64;n.parseTimeoutArgument=(e=>{if("string"==typeof e&&/^([\d.]+)s$/.test(e))return 1e3*parseFloat(e);if("number"==typeof e)return e;throw Error("Invalid timeout argument, expected a number or a duration string")}),n.describeCallback=(e=>{const t=e.toString();if(t.length<=64)return t;return t.slice(0,63)+"…"});class v{execute(e,t){return p(e)}describe(e){return""}get wantsDefaultAmountCheck(){return!1}get appliesAmountCheck(){return!1}get additionalCheckTimeout(){return C}}class _ extends v{constructor(){super(),Object.freeze(this)}execute(e){return p(e)}describe(){return""}}class y extends v{constructor(e){super(),this.results=b(e),Object.freeze(this)}execute(e){const t=b(O(this.results));for(const e of m(t))if(!i(e))return g`a value that is not a WindowProxy nor a HTMLDocument, nor an Element was set as the target`;return p(t)}describe(){const e=this.results;if("function"==typeof e&&!r(e))return`sets the target using a callback: \`${n.describeCallback(e)}\``;if(Array.isArray(e)){const t=[];for(const n of e){if(t.length>=5){t.push("…");break}t.push(s(n))}return`sets the target to [${t.join(", ")}]`}return`sets the target to ${s(e)}`}}class S extends v{constructor(e,t=e){if(super(),this.minimum=e,this.maximum=t,"number"!=typeof this.minimum)throw Error(".amount(minimum, maximum): minimum must be a number");if("number"!=typeof this.maximum)throw Error(".amount(minimum, maximum): maximum must be a number");if(this.minimum>this.maximum)throw Error(".amount(minimum, maximum): maximum must be greater than or equal to minimum");Object.freeze(this)}execute(e){const t=d(e);return t<this.minimum?0===t?x`no results were found, instead of a minimum of ${this.minimum} results`:x`only ${t} results were found, instead of a minimum of ${this.minimum} results`:t>this.maximum?x`${t} results were found, instead of a maximum of ${this.maximum} results`:p(e)}describe(e){const t=`waits up to ${e/1e3} seconds until`;return this.minimum===this.maximum?`${t} exactly ${this.minimum} results are found`:1===this.minimum&&this.maximum===1/0?`${t} a result is found`:this.maximum===1/0?`${t} ${this.minimum} or more results are found`:`${t} between ${this.minimum} and ${this.maximum} (inclusive) results are found`}get appliesAmountCheck(){return!0}}class k extends v{constructor(e){super(),this.expression=e,Object.freeze(this)}execute(e){const t=O(this.expression);for(const n of m(e)){const e=o(n,t);if(e)return p(e)}return p(null)}describe(){return"function"==typeof this.expression?`finds the first descendant element matching a CSS selector from `+`a callback: \`${n.describeCallback(this.expression)}\``:`finds the first descendant element matching the CSS selector ${D}${this.expression}${E}`}get wantsDefaultAmountCheck(){return!0}}class A extends v{constructor(e){super(),this.expression=e,Object.freeze(this)}execute(e){const t=O(this.expression),n=[];for(const i of m(e)){const e=u(i,t);n.push(e)}const i=[].concat(...n);return Object.freeze(i),p(i)}describe(){return"function"==typeof this.expression?`finds all descendant elements matching a CSS selector from a callback: `+`\`${n.describeCallback(this.expression)}\``:`finds all descendant elements matching the CSS selector ${D}${this.expression}${E}`}get wantsDefaultAmountCheck(){return!0}}class I extends v{constructor(e){super(),this.expression=e,Object.freeze(this)}execute(e){const t=O(this.expression);for(const n of m(e)){const e=c(n,t);if(e&&!i(e))return g`a value that is not an Element was returned by the XPath expression`;if(e)return p(e)}return p(null)}describe(){return"function"==typeof this.expression?`finds the first element matching a XPath expression from a callback: `+`\`${n.describeCallback(this.expression)}\``:`finds the first element matching the XPath expression ${D}${this.expression}${E}`}get wantsDefaultAmountCheck(){return!0}}class j extends v{constructor(e){super(),this.expression=e,Object.freeze(this)}execute(e){const t=O(this.expression),n=[];for(const i of m(e)){const e=a(i,t);n.push(e)}const r=[].concat(...n);Object.freeze(r);for(const e of r)if(!i(e))return g`a value that is not an Element was returned by the XPath expression`;return p(r)}describe(){return"function"==typeof this.expression?`finds all elements matching a XPath expression from a callback: `+`\`${n.describeCallback(this.expression)}\``:`finds all elements matching the XPath expression ${D}${this.expression}${E}`}get wantsDefaultAmountCheck(){return!0}}class M extends v{constructor(){super(),Object.freeze(this)}execute(e){for(const t of m(e)){const e=h(t);if("loading"===l(e))return x`the HTML document has not yet been parsed`}return p(e)}describe(e){return`waits up to ${e/1e3} seconds until the HTML document has finished parsing`}}class P extends v{constructor(){super(),Object.freeze(this)}execute(e){for(const t of m(e)){const e=h(t),n=l(e);if("loading"===n)return x`the HTML document has not yet been parsed`;if("interactive"===n)return x`the HTML document has not yet been loaded`}return p(e)}describe(e){return`waits up to ${e/1e3} seconds until all synchronous resources of the HTML document have been loaded`}}class N extends v{constructor(e){super(),this.delayMs=n.parseTimeoutArgument(e),Object.freeze(this)}execute(e,{executionStart:t,checkStart:n}){const{delayMs:i}=this,r=n-t;return r<i?x`the delay of ${i/1e3} seconds has not yet elapsed, only ${r/1e3} seconds have elapsed so far`:p(e)}describe(){return`waits until ${this.delayMs/1e3} seconds have elapsed since the start of the execution`}get additionalCheckTimeout(){return Object.freeze([this.delayMs])}}class L extends v{constructor(){super(),Object.freeze(this)}execute(e){if(!e)return p(e);if(Array.isArray(e)){const t=e.filter(e=>f(e));return p(Object.freeze(t))}const t=f(e)?e:null;return p(t)}describe(){return`but only including elements which are displayed on the page`}}class z extends v{constructor(e){if("function"!=typeof e)throw Error(".check(callback): callback must be a function");super(),this.callback=e,Object.freeze(this)}execute(e){if(!e)return p(e);if(Array.isArray(e)){const t=e.filter(e=>this.callback(e));return p(Object.freeze(t))}const t=this.callback(e)?e:null;return p(t)}describe(){return`but only including results that match a callback: \`${n.describeCallback(this.callback)}\``}}const R=new S(1,1/0);n.Action=v,n.Noop=_,n.Target=y,n.Amount=S,n.DEFAULT_AMOUNT_ACTION=R,n.Selector=k,n.SelectorAll=A,n.XPath=I,n.XPathAll=j,n.DocumentInteractive=M,n.DocumentComplete=P,n.Delay=N,n.IsDisplayed=L,n.Check=z},{"./dom":9,"./result":10}],9:[function(e,t,n){"use strict";const i=1,r=7,s=9,o=n,u=e=>Object.prototype.toString.call(e);o.findPropertyInChain=((e,t)=>{let n=Object.getPrototypeOf(e);for(;n;){const e=Object.getOwnPropertyDescriptor(n,t);if(e)return e;n=Object.getPrototypeOf(n)}return null}),o.isDOMWindow=(e=>Boolean(e&&e.window===e&&e.self===e&&o.isDOMDocument(e.document))),o.isDOMNode=(e=>Boolean(e&&("object"==typeof e||"function"==typeof e)&&"nodeType"in e&&"nodeName"in e&&"ownerDocument"in e&&"parentNode"in e)),o.isDOMDocument=(e=>Boolean(o.isDOMNode(e)&&"defaultView"in e&&("[object HTMLDocument]"===u(e)||"[object Document]"===u(e)))),o.isDOMElement=(e=>Boolean(o.isDOMNode(e)&&(1===e.nodeType||"[object HTMLFormElement]"===u(e))&&"tagName"in e)),o.getDOMDocumentWindow=(e=>{const t=o.findPropertyInChain(e,"defaultView");return t.get.call(e)}),o.isResultItem=(e=>Boolean(o.isDOMWindow(e)||o.isDOMDocument(e)||o.isDOMElement(e))),o.resultItemToWindow=(e=>{if(o.isDOMWindow(e))return e;if(o.isDOMDocument(e))return o.getDOMDocumentWindow(e);if(o.isDOMNode(e)){const t=o.findPropertyInChain(e,"ownerDocument");return o.getDOMDocumentWindow(t.get.call(e))}throw Error("dom.resultItemToWindow(): Invalid argument")}),o.resultItemToDocument=(e=>{if(o.isDOMWindow(e))return e.document;if(o.isDOMDocument(e))return e;if(o.isDOMNode(e)){const t=o.findPropertyInChain(e,"ownerDocument");return t.get.call(e)}throw Error("dom.resultItemToDocument(): Invalid argument")}),o.resultItemToDocumentElement=(e=>{const t=o.resultItemToDocument(e);return o.findPropertyInChain(t,"documentElement").get.call(t)}),o.resultItemToParentNode=(e=>{if(o.isDOMWindow(e))return e.document;if(o.isDOMDocument(e))return e;if(o.isDOMElement(e))return e;throw Error("dom.resultItemToParentNode(): Invalid argument")}),o.resultItemToElement=(e=>{if(o.isDOMWindow(e)||o.isDOMDocument(e))return o.resultItemToDocumentElement(e);if(o.isDOMElement(e))return e;throw Error("dom.resultItemToElement(): Invalid argument")}),o.describeDOMObject=(e=>{if(void 0===e)return"<#undefined>";if(null===e)return"<#null>";if(o.isDOMWindow(e))return"<#window>";if(o.isDOMDocument(e))return"<#document>";if("[object HTMLFormElement]"===u(e))return"<form>";if(o.isDOMNode(e))return`<${e.nodeName.toLowerCase()}>`;return"<???>"}),o.cssSelectorFirst=((e,t)=>{const n=o.resultItemToParentNode(e);const i=o.findPropertyInChain(n,"querySelector").value;return i.call(n,t)}),o.cssSelectorArray=((e,t)=>{const n=o.resultItemToParentNode(e);const i=o.findPropertyInChain(n,"querySelectorAll").value;return Array.from(i.call(n,t))}),o.xpathFirst=((e,t)=>{const n=o.resultItemToDocument(e);const i=o.resultItemToParentNode(e);const r=o.findPropertyInChain(n,"evaluate").value;const s=r.call(n,t,i,null,9,null);return s.singleNodeValue}),o.xpathArray=((e,t)=>{const n=o.resultItemToDocument(e);const i=o.resultItemToParentNode(e);const r=o.findPropertyInChain(n,"evaluate").value;const s=r.call(n,t,i,null,7,null);const u=new Array(s.snapshotLength);for(let e=0;e<u.length;++e)u[e]=s.snapshotItem(e);return u}),o.documentReadyState=(e=>{const t=o.findPropertyInChain(e,"readyState");return t.get.call(e)}),o.addEventListener=((e,...t)=>{if(o.isDOMNode(e)){const n=o.findPropertyInChain(e,"addEventListener");return n.value.apply(e,t)}return e.addEventListener(...t)}),o.removeEventListener=((e,...t)=>{if(o.isDOMNode(e)){const n=o.findPropertyInChain(e,"removeEventListener");return n.value.apply(e,t)}return e.removeEventListener(...t)}),o.getBoundingClientRect=(e=>{const t=o.findPropertyInChain(e,"getBoundingClientRect");return t.value.call(e)}),o.hasFormattingBox=(e=>{const t=o.resultItemToElement(e);const n=o.getBoundingClientRect(t);return n.width>0&&n.height>0})},{}],10:[function(e,t,n){"use strict";const{resultItemToDocument:i}=e("./dom"),r="success",s="pending",o="fatal failure";n.ResultWrapper=class e{constructor(){this.value=null,this.reasonStrings=null,this.reasonValues=null,this.errorObject=null,this.lastResultStatus=null}runAction(e,t){try{const{status:n,value:i,reasonStrings:u,reasonValues:c}=e.execute(this.value,t);if(n!==r&&n!==s&&n!==o)throw Error('runAction: Invalid "status" value returned from action.execute()');return this.value=i,this.lastResultStatus=n,n===r?(this.reasonStrings=null,this.reasonValues=null,this.errorObject=null,this.lastResultStatus):(this.reasonStrings=u,this.reasonValues=c,this.lastResultStatus)}catch(e){return this.value=null,this.reasonStrings=null,this.reasonValues=null,this.errorObject=e,this.lastResultStatus=o,this.lastResultStatus}}addDOMDocumentsToSet(e){if(Array.isArray(this.value))for(const t of this.value)e.add(i(t));else this.value&&e.add(i(this.value))}failureString(){return this.reasonStrings?n.buildStringFromTagValues(this.reasonStrings,this.reasonValues):this.errorObject?this.errorObject.toString():null}},n.resultToArray=(e=>{if(Array.isArray(e))return e;if(void 0===e||null===e)return[];return[e]}),n.resultCount=(e=>{if(Array.isArray(e))return e.length;if(void 0===e||null===e)return 0;return 1}),n.buildStringFromTagValues=((e,t)=>{let n=e[0];for(let i=1;i<e.length;++i)n+=String(t[i-1]),n+=e[i];return n}),n.executeSuccess=(e=>Object.freeze({status:r,value:e})),n.executePendingTag=((e,...t)=>Object.freeze({status:s,reasonStrings:Object.freeze(e),reasonValues:Object.freeze(t),value:null})),n.executeFatalFailureTag=((e,...t)=>Object.freeze({status:o,reasonStrings:Object.freeze(e),reasonValues:Object.freeze(t),value:null})),n.RESULT_STATUS_SUCCESS=r,n.RESULT_STATUS_PENDING=s,n.RESULT_STATUS_FATAL_FAILURE=o},{"./dom":9}]},{},[1])(1)});

@@ -1,1 +0,1 @@

module.exports="!function(e){if(\"object\"==typeof exports&&\"undefined\"!=typeof module)module.exports=e();else if(\"function\"==typeof define&&define.amd)define([],e);else{var t;(t=\"undefined\"!=typeof window?window:\"undefined\"!=typeof global?global:\"undefined\"!=typeof self?self:this).Bluefox=e()}}(function(){var e,t,n;return function e(t,n,i){function r(o,u){if(!n[o]){if(!t[o]){var c=\"function\"==typeof require&&require;if(!u&&c)return c(o,!0);if(s)return s(o,!0);var a=new Error(\"Cannot find module '\"+o+\"'\");throw a.code=\"MODULE_NOT_FOUND\",a}var h=n[o]={exports:{}};t[o][0].call(h.exports,function(e){var n=t[o][1][e];return r(n||e)},h,h.exports,e,t,n,i)}return n[o].exports}for(var s=\"function\"==typeof require&&require,o=0;o<i.length;o++)r(i[o]);return r}({1:[function(e,t,n){\"use strict\";const i=e(\"./ExpressionChainable\"),r=e(\"./Expression\"),s=e(\"./Execution\"),o=e(\"./DocumentObservers\"),u=e(\"./Timer\");class c extends i{static setTimerFunctions(e,t){u.setTimeout=e,u.clearTimeout=t}constructor(){super(),this._expressionExecutor=this._expressionExecutor.bind(this),this._documentObservers=new o,this._nextExecutionId=0,this.onExecuteBegin=null,this.onExecuteEnd=null,this.onCheckBegin=null,this.onCheckEnd=null}createNextExpression(e,t=3e4){return new r(null,e,t,this._expressionExecutor)}runAllChecks(e){this._documentObservers.runAllChecks(e)}runAllChecksDeferred(e){this._documentObservers.runAllChecksDeferred(e)}async _expressionExecutor(e){const t=new s(e,this._documentObservers,this._nextExecutionId++),{onExecuteBegin:n,onExecuteEnd:i,onCheckBegin:r,onCheckEnd:o}=this;t.onCheckBegin=r,t.onCheckEnd=o,n&&n({expression:e,executionId:t.id,resultPromise:t.executionPromise});try{return await t.execute()}finally{i&&i({expression:e,executionId:t.id,resultPromise:t.executionPromise})}}}t.exports=c},{\"./DocumentObservers\":3,\"./Execution\":4,\"./Expression\":5,\"./ExpressionChainable\":6,\"./Timer\":7}],2:[function(e,t,n){\"use strict\";const{getDOMDocumentWindow:i,isDOMWindow:r,isDOMDocument:s,addEventListener:o,removeEventListener:u}=e(\"./dom\"),c=e(\"./Timer\");class a{constructor(e){if(!s(e))throw Error(\"new DocumentObserver(document): Invalid argument `document`\");const t=i(e);if(!r(t))throw Error(\"new DocumentObserver(document): The given `document` must have a browsing context (a window)\");this.document=e,this.window=t,this._handleChange=this._handleChange.bind(this),this._handleChangeDeferred=this._handleChangeDeferred.bind(this),this._handleDeferrals=this._handleDeferrals.bind(this),this._pendingExecutions=new Set,this._registeredListeners=!1,this._mutationObserver=null,this._hasDeferredChange=!1,this._removeListenersTimer=new c(0,()=>this.removeListeners()),this._deferralsTimer=new c(0,this._handleDeferrals)}get hasPendingExecutions(){return this._pendingExecutions.size>0}get hasRegisteredListeners(){return this._registeredListeners}register(e){this._pendingExecutions.add(e),this.registerListeners()}unregister(e){this._pendingExecutions.delete(e),this.hasPendingExecutions||this._removeListenersTimer.reschedule()}registerListeners(){if(this._removeListenersTimer.cancel(),this.hasRegisteredListeners)return;this._registeredListeners=!0;const{window:e,document:t}=this;o(e,\"DOMContentLoaded\",this._handleChange,!0),o(e,\"load\",this._handleChange,!0),o(t,\"load\",this._handleChangeDeferred,!0),o(t,\"error\",this._handleChangeDeferred,!0),this._mutationObserver=new this.window.MutationObserver(this._handleChangeDeferred),this._mutationObserver.observe(t,{attributeOldValue:!1,attributes:!0,characterData:!0,characterDataOldValue:!1,childList:!0,subtree:!0})}removeListeners(){if(!this.hasRegisteredListeners)return;const{window:e,document:t}=this;this._removeListenersTimer.cancel(),u(e,\"DOMContentLoaded\",this._handleChange,!0),u(e,\"load\",this._handleChange,!0),u(t,\"load\",this._handleChangeDeferred,!0),u(t,\"error\",this._handleChangeDeferred,!0),this._mutationObserver.disconnect(),this._mutationObserver=null,this._deferralsTimer.cancel(),this._registeredListeners=!1}runChecks(){this._hasDeferredChange=!1,this._deferralsTimer.cancel();for(const e of this._pendingExecutions)e.check()}runChecksDeferred(){this._hasDeferredChange=!0,this._deferralsTimer.schedule()}drainDeferrals(){this._handleDeferrals()}_handleChange(){this.runChecks()}_handleChangeDeferred(){this._hasDeferredChange=!0,this._deferralsTimer.schedule()}_handleDeferrals(){this._hasDeferredChange&&(this._hasDeferredChange=!1,this.runChecks())}}t.exports=a},{\"./Timer\":7,\"./dom\":9}],3:[function(e,t,n){\"use strict\";const i=e(\"./DocumentObserver\");class r{constructor(){this._documentToObserver=new WeakMap}_getOrCreate(e){let t=this._documentToObserver.get(e);return t||(t=new i(e),this._documentToObserver.set(e,t)),t}registerExecution(e,t){this._getOrCreate(e).register(t)}unregisterExecution(e,t){const n=this._documentToObserver.get(e);n&&n.unregister(t)}runAllChecks(e){const t=this._documentToObserver.get(e);t&&t.runChecks()}runAllChecksDeferred(e){const t=this._documentToObserver.get(e);t&&t.runChecksDeferred()}drainDeferrals(e){const t=this._documentToObserver.get(e);t&&t.drainDeferrals()}}t.exports=r},{\"./DocumentObserver\":2}],4:[function(e,t,n){\"use strict\";const{ResultWrapper:i,RESULT_STATUS_SUCCESS:r,RESULT_STATUS_PENDING:s}=e(\"./result\"),o=e(\"./Timer\");class u{constructor(e,t,n){this.expression=e,this.expressionChain=e.getExpressionChain(),this.documentObservers=t,this.id=n,this.onCheckBegin=null,this.onCheckEnd=null,this.executionPromise=new Promise((e,t)=>{this.executionResolve=e;this.executionReject=t}),this.executionStart=null,this.didFirstCheck=!1,this.fulfilled=!1,this.registeredDocuments=new Set,this.timeoutTimers=new Map,this._handleTimeoutTimer=this._handleTimeoutTimer.bind(this),this.createTimer=((e,t)=>new o(e,t)),this.now=(()=>Date.now())}async execute(){return this.didFirstCheck||this.firstCheck(),this.executionPromise}firstCheck(){if(this.didFirstCheck)throw Error(\"Invalid state\");this.didFirstCheck=!0,this.executionStart=this.now();for(const e of this.expressionChain){const{timeout:t}=e.configuration;if(!this.timeoutTimers.has(t)){const e=this.createTimer(t,this._handleTimeoutTimer);e.schedule(),this.timeoutTimers.set(t,e)}}this.check()}check(){if(!this.didFirstCheck)throw Error(\"Execution#check(): This execution has not been started\");if(this.fulfilled)throw Error(\"Execution#check(): This execution has already been fulfilled\");const{onCheckBegin:e,onCheckEnd:t}=this;e&&e({expression:this.expression,executionId:this.id,resultPromise:this.executionPromise});const n=this.now()-this.executionStart,o=new i,u=new Set;let c=!1;for(const e of this.expressionChain){const t=o.runAction(e.configuration.action);if(t===s&&(c=e),t!==r)break;o.addDOMDocumentsToSet(u)}if(c){const{timeout:e}=c.configuration;n>=e?(this.fulfilled=!0,this.cleanup(),this.executionReject(this.timeoutError(e,o,c))):this.updateDocumentRegistrations(u)}else this.fulfill(o);t&&t({expression:this.expression,executionId:this.id,resultPromise:this.executionPromise})}timeoutError(e,t,n){const i=t.failureString(),r=`Wait expression timed out after ${e/1e3} seconds because ${i}. `+n.describe(),s=new Error(r);return s.timeout=e,s.actionFailure=i,s.expression=n,s.fullExpression=this.expression,s}updateDocumentRegistrations(e){for(const t of this.registeredDocuments)e.has(t)||this.documentObservers.unregisterExecution(t,this);for(const t of e)this.documentObservers.registerExecution(t,this);this.registeredDocuments=e}cleanup(){for(const e of this.registeredDocuments)this.documentObservers.unregisterExecution(e,this);this.registeredDocuments.clear();for(const e of this.timeoutTimers.values())e.cancel();this.timeoutTimers.clear()}fulfill(e){if(this.fulfilled=!0,this.cleanup(),e.lastResultStatus===r)this.executionResolve(e.value);else{const t=e.errorObject?e.errorObject:Error(e.failureString());this.executionReject(t)}}_handleTimeoutTimer(){this.check()}}t.exports=u},{\"./Timer\":7,\"./result\":10}],5:[function(e,t,n){\"use strict\";const i=e(\"./ExpressionChainable\"),{DEFAULT_AMOUNT_ACTION:r}=e(\"./actions\");if(!r.appliesAmountCheck)throw Error(\"Assertion Error\");class s extends i{constructor(e,t,n,i){if(super(),null!==e&&!(e instanceof s))throw Error(\"Invalid argument `previous`\");if(Boolean(e)===Boolean(i))throw Error(\"`executor` must (only) be set for the root Expression\");if(!t||\"object\"!=typeof t||\"function\"!=typeof t.execute||\"function\"!=typeof t.describe)throw Error(\"Invalid argument `action`\");if(\"number\"!=typeof n)throw Error(\"Invalid argument `timeout`\");const o=e&&e.configuration,u=(o&&o.wantsDefaultAmountCheck||t.wantsDefaultAmountCheck)&&!t.appliesAmountCheck;Object.defineProperty(this,\"configuration\",{value:{previous:e,depth:o?o.depth+1:0,action:t,timeout:n,_executor:o?o._executor:i,wantsDefaultAmountCheck:u,_defaultAmountExpression:null}}),this.configuration._defaultAmountExpression=u?new s(this,r,n):null,Object.freeze(this.configuration),Object.freeze(this)}getExpressionChain(){const{_defaultAmountExpression:e}=this.configuration;if(e)return e.getExpressionChain();const t=this.configuration.depth+1,n=new Array(t);let i=this;for(let e=t-1;e>=0;--e){n[e]=i;const{previous:t}=i.configuration;i=t}if(i)throw Error(\"Assertion Error\");return n}createNextExpression(e,t=this.configuration.timeout){return new s(this,e,t)}describe(){const e=[];for(const t of this.getExpressionChain()){const{configuration:n}=t,i=n.action.describe(n.timeout);i&&e.push(i)}return`The expression ${e.join(\", \")}.`}async execute(){return await this.configuration._executor(this)}then(...e){return this.execute().then(...e)}catch(...e){return this.execute().catch(...e)}finally(e){return this.then(t=>Promise.resolve(e()).then(()=>t),t=>Promise.resolve(e()).then(()=>Promise.reject(t)))}}t.exports=s},{\"./ExpressionChainable\":6,\"./actions\":8}],6:[function(e,t,n){\"use strict\";const i=e(\"./actions\");class r{action(e){return this.createNextExpression(e)}target(e){return this.createNextExpression(new i.Target(e))}timeout(e){const t=i.parseTimeoutArgument(e);return this.createNextExpression(new i.Noop,t)}amount(e,t){return this.createNextExpression(new i.Amount(e,t))}selector(e){return this.createNextExpression(new i.Selector(e))}selectorAll(e){return this.createNextExpression(new i.SelectorAll(e))}xpath(e){return this.createNextExpression(new i.XPath(e))}xpathAll(e){return this.createNextExpression(new i.XPathAll(e))}documentInteractive(){return this.createNextExpression(new i.DocumentInteractive)}documentComplete(){return this.createNextExpression(new i.DocumentComplete)}}t.exports=r},{\"./actions\":8}],7:[function(e,t,n){\"use strict\";class i{constructor(e,t){this._id=0,this.delay=e,this.callback=t,this.setTimeout=i.setTimeout,this.clearTimeout=i.clearTimeout,this._timerCallback=(()=>{this._id=0;this.callback.call(null)})}get isScheduled(){return Boolean(this._id)}schedule(){this._id||(this._id=this.setTimeout(this._timerCallback,this.delay))}cancel(){this.isScheduled&&(this.clearTimeout(this._id),this._id=0)}reschedule(){this.cancel(),this.schedule()}}i.setTimeout=((e,t)=>setTimeout(e,t)),i.clearTimeout=(e=>clearTimeout(e)),t.exports=i},{}],8:[function(e,t,n){\"use strict\";const{isResultItem:i,isDOMNode:r,describeDOMObject:s,cssSelectorFirst:o,cssSelectorArray:u,xpathFirst:c,xpathArray:a,resultItemToDocument:h,documentReadyState:f}=e(\"./dom\"),{resultToArray:l,resultCount:m,executeSuccess:d,executePendingTag:p}=e(\"./result\"),x=e=>{if(Array.isArray(e))return Object.freeze(e.slice());return e},g=e=>\"function\"==typeof e?e():e,b=\"“\",O=\"”\";n.parseTimeoutArgument=(e=>{if(\"string\"==typeof e&&/^([\\d.]+)s$/.test(e))return 1e3*parseFloat(e);if(\"number\"==typeof e)return e;throw Error(\"Invalid timeout argument, expected a number or a duration string\")});class D{execute(e){return d(e)}describe(e){return\"\"}get wantsDefaultAmountCheck(){return!1}get appliesAmountCheck(){return!1}}class E extends D{constructor(){super(),Object.freeze(this)}execute(e){return d(e)}describe(){return\"\"}}class T extends D{constructor(e){super(),this.results=x(e),Object.freeze(this)}execute(e){const t=x(g(this.results));for(const e of l(t))if(!i(e))return p`a value that is not a Window nor a Node was set as the target`;return d(t)}describe(){const e=this.results;if(\"function\"==typeof e&&!r(e))return\"sets the target using a callback\";if(Array.isArray(e)){const t=[];for(const n of e){if(t.length>=5){t.push(\"…\");break}t.push(s(n))}return`sets the target to [${t.join(\", \")}]`}return`sets the target to ${s(e)}`}}class v extends D{constructor(e,t=e){if(super(),this.minimum=e,this.maximum=t,\"number\"!=typeof this.minimum)throw Error(\".amount(minimum, maximum): minimum must be a number\");if(\"number\"!=typeof this.maximum)throw Error(\".amount(minimum, maximum): maximum must be a number\");if(this.minimum>this.maximum)throw Error(\".amount(minimum, maximum): maximum must be greater than or equal to minimum\");Object.freeze(this)}execute(e){const t=m(e);return t<this.minimum?0===t?p`no results were found, instead of a minimum of ${this.minimum} results`:p`only ${t} results were found, instead of a minimum of ${this.minimum} results`:t>this.maximum?p`${t} results were found, instead of a maximum of ${this.maximum} results`:d(e)}describe(e){const t=`waits up to ${e/1e3} seconds until`;return this.minimum===this.maximum?`${t} exactly ${this.minimum} results are found`:1===this.minimum&&this.maximum===1/0?`${t} a result is found`:this.maximum===1/0?`${t} ${this.minimum} or more results are found`:`${t} between ${this.minimum} and ${this.maximum} (inclusive) results are found`}get appliesAmountCheck(){return!0}}class w extends D{constructor(e){super(),this.expression=e,Object.freeze(this)}execute(e){const t=g(this.expression);for(const n of l(e)){const e=o(n,t);if(e)return d(e)}return d(null)}describe(){return\"function\"==typeof this.expression?`finds the first descendant element matching a CSS selector from a callback`:`finds the first descendant element matching the CSS selector ${b}${this.expression}${O}`}get wantsDefaultAmountCheck(){return!0}}class _ extends D{constructor(e){super(),this.expression=e,Object.freeze(this)}execute(e){const t=g(this.expression),n=[];for(const i of l(e)){const e=u(i,t);n.push(e)}const i=[].concat(...n);return Object.freeze(i),d(i)}describe(){return\"function\"==typeof this.expression?`finds all descendant elements matching a CSS selector from a callback`:`finds all descendant elements matching the CSS selector ${b}${this.expression}${O}`}get wantsDefaultAmountCheck(){return!0}}class C extends D{constructor(e){super(),this.expression=e,Object.freeze(this)}execute(e){const t=g(this.expression);for(const n of l(e)){const e=c(n,t);if(e)return d(e)}return d(null)}describe(){return\"function\"==typeof this.expression?`finds the first element matching a XPath expression from a callback`:`finds the first element matching the XPath expression ${b}${this.expression}${O}`}get wantsDefaultAmountCheck(){return!0}}class y extends D{constructor(e){super(),this.expression=e,Object.freeze(this)}execute(e){const t=g(this.expression),n=[];for(const i of l(e)){const e=a(i,t);n.push(e)}const i=[].concat(...n);return Object.freeze(i),d(i)}describe(){return\"function\"==typeof this.expression?`finds all elements matching a XPath expression from a callback`:`finds all elements matching the XPath expression ${b}${this.expression}${O}`}get wantsDefaultAmountCheck(){return!0}}class S extends D{constructor(){super(),Object.freeze(this)}execute(e){for(const t of l(e)){const e=h(t);if(\"loading\"===f(e))return p`the HTML document has not yet been parsed`}return d(e)}describe(e){return`waits up to ${e/1e3} seconds until the HTML document has finished parsing`}}class A extends D{constructor(){super(),Object.freeze(this)}execute(e){for(const t of l(e)){const e=h(t),n=f(e);if(\"loading\"===n)return p`the HTML document has not yet been parsed`;if(\"interactive\"===n)return p`the HTML document has not yet been loaded`}return d(e)}describe(e){return`waits up to ${e/1e3} seconds until all synchronous resources of the HTML document have been loaded`}}const I=new v(1,1/0);n.Action=D,n.Noop=E,n.Target=T,n.Amount=v,n.DEFAULT_AMOUNT_ACTION=I,n.Selector=w,n.SelectorAll=_,n.XPath=C,n.XPathAll=y,n.DocumentInteractive=S,n.DocumentComplete=A},{\"./dom\":9,\"./result\":10}],9:[function(e,t,n){\"use strict\";const i=1,r=7,s=9,o=n,u=e=>Object.prototype.toString.call(e);o.findPropertyInChain=((e,t)=>{let n=Object.getPrototypeOf(e);for(;n;){const e=Object.getOwnPropertyDescriptor(n,t);if(e)return e;n=Object.getPrototypeOf(n)}return null}),o.isDOMWindow=(e=>Boolean(e&&e.window===e&&e.self===e&&o.isDOMDocument(e.document))),o.isDOMNode=(e=>Boolean(e&&(\"object\"==typeof e||\"function\"==typeof e)&&\"nodeType\"in e&&\"nodeName\"in e&&\"ownerDocument\"in e&&\"parentNode\"in e)),o.isDOMDocument=(e=>Boolean(o.isDOMNode(e)&&\"defaultView\"in e&&(\"[object HTMLDocument]\"===u(e)||\"[object Document]\"===u(e)))),o.isDOMElement=(e=>Boolean(o.isDOMNode(e)&&(1===e.nodeType||\"[object HTMLFormElement]\"===u(e))&&\"tagName\"in e)),o.getDOMDocumentWindow=(e=>{const t=o.findPropertyInChain(e,\"defaultView\");return t.get.call(e)}),o.isResultItem=(e=>Boolean(o.isDOMWindow(e)||o.isDOMDocument(e)||o.isDOMElement(e))),o.resultItemToWindow=(e=>{if(o.isDOMWindow(e))return e;if(o.isDOMDocument(e))return o.getDOMDocumentWindow(e);if(o.isDOMNode(e)){const t=o.findPropertyInChain(e,\"ownerDocument\");return o.getDOMDocumentWindow(t.get.call(e))}throw Error(\"dom.resultItemToWindow(): Invalid argument\")}),o.resultItemToDocument=(e=>{if(o.isDOMWindow(e))return e.document;if(o.isDOMDocument(e))return e;if(o.isDOMNode(e)){const t=o.findPropertyInChain(e,\"ownerDocument\");return t.get.call(e)}throw Error(\"dom.resultItemToDocument(): Invalid argument\")}),o.resultItemToParentNode=(e=>{if(o.isDOMWindow(e))return e.document;if(o.isDOMDocument(e))return e;if(o.isDOMElement(e))return e;throw Error(\"dom.resultItemToParentNode(): Invalid argument\")}),o.describeDOMObject=(e=>{if(void 0===e)return\"<#undefined>\";if(null===e)return\"<#null>\";if(o.isDOMWindow(e))return\"<#window>\";if(o.isDOMDocument(e))return\"<#document>\";if(\"[object HTMLFormElement]\"===u(e))return\"<form>\";if(o.isDOMNode(e))return`<${e.nodeName.toLowerCase()}>`;return\"<???>\"}),o.cssSelectorFirst=((e,t)=>{const n=o.resultItemToParentNode(e);const i=o.findPropertyInChain(n,\"querySelector\").value;return i.call(n,t)}),o.cssSelectorArray=((e,t)=>{const n=o.resultItemToParentNode(e);const i=o.findPropertyInChain(n,\"querySelectorAll\").value;return Array.from(i.call(n,t))}),o.xpathFirst=((e,t)=>{const n=o.resultItemToDocument(e);const i=o.resultItemToParentNode(e);const r=o.findPropertyInChain(n,\"evaluate\").value;const s=r.call(n,t,i,null,9,null);return s.singleNodeValue}),o.xpathArray=((e,t)=>{const n=o.resultItemToDocument(e);const i=o.resultItemToParentNode(e);const r=o.findPropertyInChain(n,\"evaluate\").value;const s=r.call(n,t,i,null,7,null);const u=new Array(s.snapshotLength);for(let e=0;e<u.length;++e)u[e]=s.snapshotItem(e);return u}),o.documentReadyState=(e=>{const t=o.findPropertyInChain(e,\"readyState\");return t.get.call(e)}),o.addEventListener=((e,...t)=>{if(o.isDOMNode(e)){const n=o.findPropertyInChain(e,\"addEventListener\");return n.value.apply(e,t)}return e.addEventListener(...t)}),o.removeEventListener=((e,...t)=>{if(o.isDOMNode(e)){const n=o.findPropertyInChain(e,\"removeEventListener\");return n.value.apply(e,t)}return e.removeEventListener(...t)})},{}],10:[function(e,t,n){\"use strict\";const{resultItemToDocument:i}=e(\"./dom\"),r=\"success\",s=\"pending\",o=\"fatal failure\";n.ResultWrapper=class e{constructor(){this.value=null,this.reasonStrings=null,this.reasonValues=null,this.errorObject=null,this.lastResultStatus=null}runAction(e){try{const{status:t,value:n,reasonStrings:i,reasonValues:u}=e.execute(this.value);if(t!==r&&t!==s&&t!==o)throw Error('runAction: Invalid \"status\" value returned from action.execute()');return this.value=n,this.lastResultStatus=t,t===r?(this.reasonStrings=null,this.reasonValues=null,this.errorObject=null,this.lastResultStatus):(this.reasonStrings=i,this.reasonValues=u,this.lastResultStatus)}catch(e){return this.value=null,this.reasonStrings=null,this.reasonValues=null,this.errorObject=e,this.lastResultStatus=o,this.lastResultStatus}}addDOMDocumentsToSet(e){if(Array.isArray(this.value))for(const t of this.value)e.add(i(t));else this.value&&e.add(i(this.value))}failureString(){return this.reasonStrings?n.buildStringFromTagValues(this.reasonStrings,this.reasonValues):this.errorObject?this.errorObject.toString():null}},n.resultToArray=(e=>{if(Array.isArray(e))return e;if(void 0===e||null===e)return[];return[e]}),n.resultCount=(e=>{if(Array.isArray(e))return e.length;if(void 0===e||null===e)return 0;return 1}),n.buildStringFromTagValues=((e,t)=>{let n=e[0];for(let i=1;i<e.length;++i)n+=String(t[i-1]),n+=e[i];return n}),n.executeSuccess=(e=>Object.freeze({status:r,value:e})),n.executePendingTag=((e,...t)=>Object.freeze({status:s,reasonStrings:Object.freeze(e),reasonValues:Object.freeze(t),value:null})),n.executeFatalFailureTag=((e,...t)=>Object.freeze({status:o,reasonStrings:Object.freeze(e),reasonValues:Object.freeze(t),value:null})),n.RESULT_STATUS_SUCCESS=r,n.RESULT_STATUS_PENDING=s,n.RESULT_STATUS_FATAL_FAILURE=o},{\"./dom\":9}]},{},[1])(1)});";
module.exports="!function(e){if(\"object\"==typeof exports&&\"undefined\"!=typeof module)module.exports=e();else if(\"function\"==typeof define&&define.amd)define([],e);else{var t;(t=\"undefined\"!=typeof window?window:\"undefined\"!=typeof global?global:\"undefined\"!=typeof self?self:this).Bluefox=e()}}(function(){var e,t,n;return function e(t,n,i){function r(o,u){if(!n[o]){if(!t[o]){var c=\"function\"==typeof require&&require;if(!u&&c)return c(o,!0);if(s)return s(o,!0);var a=new Error(\"Cannot find module '\"+o+\"'\");throw a.code=\"MODULE_NOT_FOUND\",a}var h=n[o]={exports:{}};t[o][0].call(h.exports,function(e){var n=t[o][1][e];return r(n||e)},h,h.exports,e,t,n,i)}return n[o].exports}for(var s=\"function\"==typeof require&&require,o=0;o<i.length;o++)r(i[o]);return r}({1:[function(e,t,n){\"use strict\";const i=e(\"./ExpressionChainable\"),r=e(\"./Expression\"),s=e(\"./Execution\"),o=e(\"./DocumentObservers\"),u=e(\"./Timer\");class c extends i{static setTimerFunctions(e,t){u.setTimeout=e,u.clearTimeout=t}constructor(){super(),this._expressionExecutor=this._expressionExecutor.bind(this),this._documentObservers=new o,this._nextExecutionId=0,this.onExecuteBegin=null,this.onExecuteEnd=null,this.onCheckBegin=null,this.onCheckEnd=null}createNextExpression(e,t=3e4){return new r(null,e,t,this._expressionExecutor)}runAllChecks(e){this._documentObservers.runAllChecks(e)}runAllChecksDeferred(e){this._documentObservers.runAllChecksDeferred(e)}async _expressionExecutor(e){const t=new s(e,this._documentObservers,this._nextExecutionId++),{onExecuteBegin:n,onExecuteEnd:i,onCheckBegin:r,onCheckEnd:o}=this;t.onCheckBegin=r,t.onCheckEnd=o,n&&n({expression:e,executionId:t.id,resultPromise:t.executionPromise});try{return await t.execute()}finally{i&&i({expression:e,executionId:t.id,resultPromise:t.executionPromise})}}}t.exports=c},{\"./DocumentObservers\":3,\"./Execution\":4,\"./Expression\":5,\"./ExpressionChainable\":6,\"./Timer\":7}],2:[function(e,t,n){\"use strict\";const{getDOMDocumentWindow:i,isDOMWindow:r,isDOMDocument:s,addEventListener:o,removeEventListener:u}=e(\"./dom\"),c=e(\"./Timer\");class a{constructor(e){if(!s(e))throw Error(\"new DocumentObserver(document): Invalid argument `document`\");const t=i(e);if(!r(t))throw Error(\"new DocumentObserver(document): The given `document` must have a browsing context (a window)\");this.document=e,this.window=t,this._handleChange=this._handleChange.bind(this),this._handleChangeDeferred=this._handleChangeDeferred.bind(this),this._handleDeferrals=this._handleDeferrals.bind(this),this._pendingExecutions=new Set,this._registeredListeners=!1,this._mutationObserver=null,this._hasDeferredChange=!1,this._removeListenersTimer=new c(0,()=>this.removeListeners()),this._deferralsTimer=new c(0,this._handleDeferrals)}get hasPendingExecutions(){return this._pendingExecutions.size>0}get hasRegisteredListeners(){return this._registeredListeners}register(e){this._pendingExecutions.add(e),this.registerListeners()}unregister(e){this._pendingExecutions.delete(e),this.hasPendingExecutions||this._removeListenersTimer.reschedule()}registerListeners(){if(this._removeListenersTimer.cancel(),this.hasRegisteredListeners)return;this._registeredListeners=!0;const{window:e,document:t}=this;o(e,\"DOMContentLoaded\",this._handleChange,!0),o(e,\"load\",this._handleChange,!0),o(t,\"load\",this._handleChangeDeferred,!0),o(t,\"error\",this._handleChangeDeferred,!0),this._mutationObserver=new this.window.MutationObserver(this._handleChangeDeferred),this._mutationObserver.observe(t,{attributeOldValue:!1,attributes:!0,characterData:!0,characterDataOldValue:!1,childList:!0,subtree:!0})}removeListeners(){if(!this.hasRegisteredListeners)return;const{window:e,document:t}=this;this._removeListenersTimer.cancel(),u(e,\"DOMContentLoaded\",this._handleChange,!0),u(e,\"load\",this._handleChange,!0),u(t,\"load\",this._handleChangeDeferred,!0),u(t,\"error\",this._handleChangeDeferred,!0),this._mutationObserver.disconnect(),this._mutationObserver=null,this._deferralsTimer.cancel(),this._registeredListeners=!1}runChecks(){this._hasDeferredChange=!1,this._deferralsTimer.cancel();for(const e of this._pendingExecutions)e.check()}runChecksDeferred(){this._hasDeferredChange=!0,this._deferralsTimer.schedule()}drainDeferrals(){this._handleDeferrals()}_handleChange(){this.runChecks()}_handleChangeDeferred(){this._hasDeferredChange=!0,this._deferralsTimer.schedule()}_handleDeferrals(){this._hasDeferredChange&&(this._hasDeferredChange=!1,this.runChecks())}}t.exports=a},{\"./Timer\":7,\"./dom\":9}],3:[function(e,t,n){\"use strict\";const i=e(\"./DocumentObserver\");class r{constructor(){this._documentToObserver=new WeakMap}_getOrCreate(e){let t=this._documentToObserver.get(e);return t||(t=new i(e),this._documentToObserver.set(e,t)),t}registerExecution(e,t){this._getOrCreate(e).register(t)}unregisterExecution(e,t){const n=this._documentToObserver.get(e);n&&n.unregister(t)}runAllChecks(e){const t=this._documentToObserver.get(e);t&&t.runChecks()}runAllChecksDeferred(e){const t=this._documentToObserver.get(e);t&&t.runChecksDeferred()}drainDeferrals(e){const t=this._documentToObserver.get(e);t&&t.drainDeferrals()}}t.exports=r},{\"./DocumentObserver\":2}],4:[function(e,t,n){\"use strict\";const{ResultWrapper:i,RESULT_STATUS_SUCCESS:r,RESULT_STATUS_PENDING:s}=e(\"./result\"),o=e(\"./Timer\");class u{constructor(e,t,n){this.expression=e,this.expressionChain=e.getExpressionChain(),this.documentObservers=t,this.id=n,this.onCheckBegin=null,this.onCheckEnd=null,this.executionPromise=new Promise((e,t)=>{this.executionResolve=e;this.executionReject=t}),this.executionStart=null,this.didFirstCheck=!1,this.fulfilled=!1,this.registeredDocuments=new Set,this.additionalCheckTimers=new Map,this._handleAdditionalCheckTimer=this._handleAdditionalCheckTimer.bind(this),this.createTimer=((e,t)=>new o(e,t)),this.now=(()=>Date.now())}async execute(){return this.didFirstCheck||this.firstCheck(),this.executionPromise}firstCheck(){if(this.didFirstCheck)throw Error(\"Invalid state\");this.didFirstCheck=!0,this.executionStart=this.now();for(const e of this.expressionChain){const{additionalCheckTimeout:t}=e.configuration;for(const e of t)if(!this.additionalCheckTimers.has(e)){const t=this.createTimer(e,this._handleAdditionalCheckTimer);t.schedule(),this.additionalCheckTimers.set(e,t)}}this.check()}check(){if(!this.didFirstCheck)throw Error(\"Execution#check(): This execution has not been started\");if(this.fulfilled)throw Error(\"Execution#check(): This execution has already been fulfilled\");const{onCheckBegin:e,onCheckEnd:t}=this;e&&e({expression:this.expression,executionId:this.id,resultPromise:this.executionPromise});const{executionStart:n}=this,o=this.now(),u=o-n,c=new i,a=new Set;let h=!1;for(const e of this.expressionChain){const t=Object.freeze({executionStart:n,checkStart:o}),i=c.runAction(e.configuration.action,t);if(i===s&&(h=e),i!==r)break;c.addDOMDocumentsToSet(a)}if(h){const{timeout:e}=h.configuration;u>=e?(this.fulfilled=!0,this.cleanup(),this.executionReject(this.timeoutError(e,c,h))):this.updateDocumentRegistrations(a)}else this.fulfill(c);t&&t({expression:this.expression,executionId:this.id,resultPromise:this.executionPromise})}timeoutError(e,t,n){const i=t.failureString(),r=`Wait expression timed out after ${e/1e3} seconds because ${i}. `+n.describe(),s=new Error(r);return s.timeout=e,s.actionFailure=i,s.expression=n,s.fullExpression=this.expression,s}updateDocumentRegistrations(e){for(const t of this.registeredDocuments)e.has(t)||this.documentObservers.unregisterExecution(t,this);for(const t of e)this.documentObservers.registerExecution(t,this);this.registeredDocuments=e}cleanup(){for(const e of this.registeredDocuments)this.documentObservers.unregisterExecution(e,this);this.registeredDocuments.clear();for(const e of this.additionalCheckTimers.values())e.cancel();this.additionalCheckTimers.clear()}fulfill(e){if(this.fulfilled=!0,this.cleanup(),e.lastResultStatus===r)this.executionResolve(e.value);else{const t=e.errorObject?e.errorObject:Error(e.failureString());this.executionReject(t)}}_handleAdditionalCheckTimer(){this.check()}}t.exports=u},{\"./Timer\":7,\"./result\":10}],5:[function(e,t,n){\"use strict\";const i=e(\"./ExpressionChainable\"),{DEFAULT_AMOUNT_ACTION:r}=e(\"./actions\");if(!r.appliesAmountCheck)throw Error(\"Assertion Error\");class s extends i{constructor(e,t,n,i){if(super(),null!==e&&!(e instanceof s))throw Error(\"Invalid argument `previous`\");if(Boolean(e)===Boolean(i))throw Error(\"`executor` must (only) be set for the root Expression\");if(!t||\"object\"!=typeof t||\"function\"!=typeof t.execute||\"function\"!=typeof t.describe)throw Error(\"Invalid argument `action`\");if(\"number\"!=typeof n)throw Error(\"Invalid argument `timeout`\");const o=e&&e.configuration,u=(o&&o.wantsDefaultAmountCheck||t.wantsDefaultAmountCheck)&&!t.appliesAmountCheck;Object.defineProperty(this,\"configuration\",{value:{previous:e,depth:o?o.depth+1:0,action:t,timeout:n,additionalCheckTimeout:Object.freeze([n,...t.additionalCheckTimeout]),_executor:o?o._executor:i,wantsDefaultAmountCheck:u,_defaultAmountExpression:null}}),this.configuration._defaultAmountExpression=u?new s(this,r,n):null,Object.freeze(this.configuration),Object.freeze(this)}getExpressionChain(){const{_defaultAmountExpression:e}=this.configuration;if(e)return e.getExpressionChain();const t=this.configuration.depth+1,n=new Array(t);let i=this;for(let e=t-1;e>=0;--e){n[e]=i;const{previous:t}=i.configuration;i=t}if(i)throw Error(\"Assertion Error\");return n}createNextExpression(e,t=this.configuration.timeout){return new s(this,e,t)}describe(){const e=[];for(const t of this.getExpressionChain()){const{configuration:n}=t,i=n.action.describe(n.timeout);i&&e.push(i)}return`The expression ${e.join(\", \")}.`}async execute(){return await this.configuration._executor(this)}then(...e){return this.execute().then(...e)}catch(...e){return this.execute().catch(...e)}finally(e){return this.then(t=>Promise.resolve(e()).then(()=>t),t=>Promise.resolve(e()).then(()=>Promise.reject(t)))}}t.exports=s},{\"./ExpressionChainable\":6,\"./actions\":8}],6:[function(e,t,n){\"use strict\";const i=e(\"./actions\");class r{action(e){return this.createNextExpression(e)}target(e){return this.createNextExpression(new i.Target(e))}timeout(e){const t=i.parseTimeoutArgument(e);return this.createNextExpression(new i.Noop,t)}amount(e,t){return this.createNextExpression(new i.Amount(e,t))}selector(e){return this.createNextExpression(new i.Selector(e))}selectorAll(e){return this.createNextExpression(new i.SelectorAll(e))}xpath(e){return this.createNextExpression(new i.XPath(e))}xpathAll(e){return this.createNextExpression(new i.XPathAll(e))}documentInteractive(){return this.createNextExpression(new i.DocumentInteractive)}documentComplete(){return this.createNextExpression(new i.DocumentComplete)}delay(e){return this.createNextExpression(new i.Delay(e))}isDisplayed(){return this.createNextExpression(new i.IsDisplayed)}check(e){return this.createNextExpression(new i.Check(e))}}t.exports=r},{\"./actions\":8}],7:[function(e,t,n){\"use strict\";class i{constructor(e,t){this._id=0,this.delay=e,this.callback=t,this.setTimeout=i.setTimeout,this.clearTimeout=i.clearTimeout,this._timerCallback=(()=>{this._id=0;this.callback.call(null)})}get isScheduled(){return Boolean(this._id)}schedule(){this._id||(this._id=this.setTimeout(this._timerCallback,this.delay))}cancel(){this.isScheduled&&(this.clearTimeout(this._id),this._id=0)}reschedule(){this.cancel(),this.schedule()}}i.setTimeout=((e,t)=>setTimeout(e,t)),i.clearTimeout=(e=>clearTimeout(e)),t.exports=i},{}],8:[function(e,t,n){\"use strict\";const{isResultItem:i,isDOMNode:r,describeDOMObject:s,cssSelectorFirst:o,cssSelectorArray:u,xpathFirst:c,xpathArray:a,resultItemToDocument:h,documentReadyState:l,hasFormattingBox:f}=e(\"./dom\"),{resultToArray:m,resultCount:d,executeSuccess:p,executePendingTag:x,executeFatalFailureTag:g}=e(\"./result\"),b=e=>{if(Array.isArray(e))return Object.freeze(e.slice());return e},O=e=>\"function\"==typeof e?e():e,D=\"“\",E=\"”\",T=\"…\",C=Object.freeze([]),w=64;n.parseTimeoutArgument=(e=>{if(\"string\"==typeof e&&/^([\\d.]+)s$/.test(e))return 1e3*parseFloat(e);if(\"number\"==typeof e)return e;throw Error(\"Invalid timeout argument, expected a number or a duration string\")}),n.describeCallback=(e=>{const t=e.toString();if(t.length<=64)return t;return t.slice(0,63)+\"…\"});class v{execute(e,t){return p(e)}describe(e){return\"\"}get wantsDefaultAmountCheck(){return!1}get appliesAmountCheck(){return!1}get additionalCheckTimeout(){return C}}class _ extends v{constructor(){super(),Object.freeze(this)}execute(e){return p(e)}describe(){return\"\"}}class y extends v{constructor(e){super(),this.results=b(e),Object.freeze(this)}execute(e){const t=b(O(this.results));for(const e of m(t))if(!i(e))return g`a value that is not a WindowProxy nor a HTMLDocument, nor an Element was set as the target`;return p(t)}describe(){const e=this.results;if(\"function\"==typeof e&&!r(e))return`sets the target using a callback: \\`${n.describeCallback(e)}\\``;if(Array.isArray(e)){const t=[];for(const n of e){if(t.length>=5){t.push(\"…\");break}t.push(s(n))}return`sets the target to [${t.join(\", \")}]`}return`sets the target to ${s(e)}`}}class S extends v{constructor(e,t=e){if(super(),this.minimum=e,this.maximum=t,\"number\"!=typeof this.minimum)throw Error(\".amount(minimum, maximum): minimum must be a number\");if(\"number\"!=typeof this.maximum)throw Error(\".amount(minimum, maximum): maximum must be a number\");if(this.minimum>this.maximum)throw Error(\".amount(minimum, maximum): maximum must be greater than or equal to minimum\");Object.freeze(this)}execute(e){const t=d(e);return t<this.minimum?0===t?x`no results were found, instead of a minimum of ${this.minimum} results`:x`only ${t} results were found, instead of a minimum of ${this.minimum} results`:t>this.maximum?x`${t} results were found, instead of a maximum of ${this.maximum} results`:p(e)}describe(e){const t=`waits up to ${e/1e3} seconds until`;return this.minimum===this.maximum?`${t} exactly ${this.minimum} results are found`:1===this.minimum&&this.maximum===1/0?`${t} a result is found`:this.maximum===1/0?`${t} ${this.minimum} or more results are found`:`${t} between ${this.minimum} and ${this.maximum} (inclusive) results are found`}get appliesAmountCheck(){return!0}}class k extends v{constructor(e){super(),this.expression=e,Object.freeze(this)}execute(e){const t=O(this.expression);for(const n of m(e)){const e=o(n,t);if(e)return p(e)}return p(null)}describe(){return\"function\"==typeof this.expression?`finds the first descendant element matching a CSS selector from `+`a callback: \\`${n.describeCallback(this.expression)}\\``:`finds the first descendant element matching the CSS selector ${D}${this.expression}${E}`}get wantsDefaultAmountCheck(){return!0}}class A extends v{constructor(e){super(),this.expression=e,Object.freeze(this)}execute(e){const t=O(this.expression),n=[];for(const i of m(e)){const e=u(i,t);n.push(e)}const i=[].concat(...n);return Object.freeze(i),p(i)}describe(){return\"function\"==typeof this.expression?`finds all descendant elements matching a CSS selector from a callback: `+`\\`${n.describeCallback(this.expression)}\\``:`finds all descendant elements matching the CSS selector ${D}${this.expression}${E}`}get wantsDefaultAmountCheck(){return!0}}class I extends v{constructor(e){super(),this.expression=e,Object.freeze(this)}execute(e){const t=O(this.expression);for(const n of m(e)){const e=c(n,t);if(e&&!i(e))return g`a value that is not an Element was returned by the XPath expression`;if(e)return p(e)}return p(null)}describe(){return\"function\"==typeof this.expression?`finds the first element matching a XPath expression from a callback: `+`\\`${n.describeCallback(this.expression)}\\``:`finds the first element matching the XPath expression ${D}${this.expression}${E}`}get wantsDefaultAmountCheck(){return!0}}class j extends v{constructor(e){super(),this.expression=e,Object.freeze(this)}execute(e){const t=O(this.expression),n=[];for(const i of m(e)){const e=a(i,t);n.push(e)}const r=[].concat(...n);Object.freeze(r);for(const e of r)if(!i(e))return g`a value that is not an Element was returned by the XPath expression`;return p(r)}describe(){return\"function\"==typeof this.expression?`finds all elements matching a XPath expression from a callback: `+`\\`${n.describeCallback(this.expression)}\\``:`finds all elements matching the XPath expression ${D}${this.expression}${E}`}get wantsDefaultAmountCheck(){return!0}}class M extends v{constructor(){super(),Object.freeze(this)}execute(e){for(const t of m(e)){const e=h(t);if(\"loading\"===l(e))return x`the HTML document has not yet been parsed`}return p(e)}describe(e){return`waits up to ${e/1e3} seconds until the HTML document has finished parsing`}}class P extends v{constructor(){super(),Object.freeze(this)}execute(e){for(const t of m(e)){const e=h(t),n=l(e);if(\"loading\"===n)return x`the HTML document has not yet been parsed`;if(\"interactive\"===n)return x`the HTML document has not yet been loaded`}return p(e)}describe(e){return`waits up to ${e/1e3} seconds until all synchronous resources of the HTML document have been loaded`}}class N extends v{constructor(e){super(),this.delayMs=n.parseTimeoutArgument(e),Object.freeze(this)}execute(e,{executionStart:t,checkStart:n}){const{delayMs:i}=this,r=n-t;return r<i?x`the delay of ${i/1e3} seconds has not yet elapsed, only ${r/1e3} seconds have elapsed so far`:p(e)}describe(){return`waits until ${this.delayMs/1e3} seconds have elapsed since the start of the execution`}get additionalCheckTimeout(){return Object.freeze([this.delayMs])}}class L extends v{constructor(){super(),Object.freeze(this)}execute(e){if(!e)return p(e);if(Array.isArray(e)){const t=e.filter(e=>f(e));return p(Object.freeze(t))}const t=f(e)?e:null;return p(t)}describe(){return`but only including elements which are displayed on the page`}}class z extends v{constructor(e){if(\"function\"!=typeof e)throw Error(\".check(callback): callback must be a function\");super(),this.callback=e,Object.freeze(this)}execute(e){if(!e)return p(e);if(Array.isArray(e)){const t=e.filter(e=>this.callback(e));return p(Object.freeze(t))}const t=this.callback(e)?e:null;return p(t)}describe(){return`but only including results that match a callback: \\`${n.describeCallback(this.callback)}\\``}}const R=new S(1,1/0);n.Action=v,n.Noop=_,n.Target=y,n.Amount=S,n.DEFAULT_AMOUNT_ACTION=R,n.Selector=k,n.SelectorAll=A,n.XPath=I,n.XPathAll=j,n.DocumentInteractive=M,n.DocumentComplete=P,n.Delay=N,n.IsDisplayed=L,n.Check=z},{\"./dom\":9,\"./result\":10}],9:[function(e,t,n){\"use strict\";const i=1,r=7,s=9,o=n,u=e=>Object.prototype.toString.call(e);o.findPropertyInChain=((e,t)=>{let n=Object.getPrototypeOf(e);for(;n;){const e=Object.getOwnPropertyDescriptor(n,t);if(e)return e;n=Object.getPrototypeOf(n)}return null}),o.isDOMWindow=(e=>Boolean(e&&e.window===e&&e.self===e&&o.isDOMDocument(e.document))),o.isDOMNode=(e=>Boolean(e&&(\"object\"==typeof e||\"function\"==typeof e)&&\"nodeType\"in e&&\"nodeName\"in e&&\"ownerDocument\"in e&&\"parentNode\"in e)),o.isDOMDocument=(e=>Boolean(o.isDOMNode(e)&&\"defaultView\"in e&&(\"[object HTMLDocument]\"===u(e)||\"[object Document]\"===u(e)))),o.isDOMElement=(e=>Boolean(o.isDOMNode(e)&&(1===e.nodeType||\"[object HTMLFormElement]\"===u(e))&&\"tagName\"in e)),o.getDOMDocumentWindow=(e=>{const t=o.findPropertyInChain(e,\"defaultView\");return t.get.call(e)}),o.isResultItem=(e=>Boolean(o.isDOMWindow(e)||o.isDOMDocument(e)||o.isDOMElement(e))),o.resultItemToWindow=(e=>{if(o.isDOMWindow(e))return e;if(o.isDOMDocument(e))return o.getDOMDocumentWindow(e);if(o.isDOMNode(e)){const t=o.findPropertyInChain(e,\"ownerDocument\");return o.getDOMDocumentWindow(t.get.call(e))}throw Error(\"dom.resultItemToWindow(): Invalid argument\")}),o.resultItemToDocument=(e=>{if(o.isDOMWindow(e))return e.document;if(o.isDOMDocument(e))return e;if(o.isDOMNode(e)){const t=o.findPropertyInChain(e,\"ownerDocument\");return t.get.call(e)}throw Error(\"dom.resultItemToDocument(): Invalid argument\")}),o.resultItemToDocumentElement=(e=>{const t=o.resultItemToDocument(e);return o.findPropertyInChain(t,\"documentElement\").get.call(t)}),o.resultItemToParentNode=(e=>{if(o.isDOMWindow(e))return e.document;if(o.isDOMDocument(e))return e;if(o.isDOMElement(e))return e;throw Error(\"dom.resultItemToParentNode(): Invalid argument\")}),o.resultItemToElement=(e=>{if(o.isDOMWindow(e)||o.isDOMDocument(e))return o.resultItemToDocumentElement(e);if(o.isDOMElement(e))return e;throw Error(\"dom.resultItemToElement(): Invalid argument\")}),o.describeDOMObject=(e=>{if(void 0===e)return\"<#undefined>\";if(null===e)return\"<#null>\";if(o.isDOMWindow(e))return\"<#window>\";if(o.isDOMDocument(e))return\"<#document>\";if(\"[object HTMLFormElement]\"===u(e))return\"<form>\";if(o.isDOMNode(e))return`<${e.nodeName.toLowerCase()}>`;return\"<???>\"}),o.cssSelectorFirst=((e,t)=>{const n=o.resultItemToParentNode(e);const i=o.findPropertyInChain(n,\"querySelector\").value;return i.call(n,t)}),o.cssSelectorArray=((e,t)=>{const n=o.resultItemToParentNode(e);const i=o.findPropertyInChain(n,\"querySelectorAll\").value;return Array.from(i.call(n,t))}),o.xpathFirst=((e,t)=>{const n=o.resultItemToDocument(e);const i=o.resultItemToParentNode(e);const r=o.findPropertyInChain(n,\"evaluate\").value;const s=r.call(n,t,i,null,9,null);return s.singleNodeValue}),o.xpathArray=((e,t)=>{const n=o.resultItemToDocument(e);const i=o.resultItemToParentNode(e);const r=o.findPropertyInChain(n,\"evaluate\").value;const s=r.call(n,t,i,null,7,null);const u=new Array(s.snapshotLength);for(let e=0;e<u.length;++e)u[e]=s.snapshotItem(e);return u}),o.documentReadyState=(e=>{const t=o.findPropertyInChain(e,\"readyState\");return t.get.call(e)}),o.addEventListener=((e,...t)=>{if(o.isDOMNode(e)){const n=o.findPropertyInChain(e,\"addEventListener\");return n.value.apply(e,t)}return e.addEventListener(...t)}),o.removeEventListener=((e,...t)=>{if(o.isDOMNode(e)){const n=o.findPropertyInChain(e,\"removeEventListener\");return n.value.apply(e,t)}return e.removeEventListener(...t)}),o.getBoundingClientRect=(e=>{const t=o.findPropertyInChain(e,\"getBoundingClientRect\");return t.value.call(e)}),o.hasFormattingBox=(e=>{const t=o.resultItemToElement(e);const n=o.getBoundingClientRect(t);return n.width>0&&n.height>0})},{}],10:[function(e,t,n){\"use strict\";const{resultItemToDocument:i}=e(\"./dom\"),r=\"success\",s=\"pending\",o=\"fatal failure\";n.ResultWrapper=class e{constructor(){this.value=null,this.reasonStrings=null,this.reasonValues=null,this.errorObject=null,this.lastResultStatus=null}runAction(e,t){try{const{status:n,value:i,reasonStrings:u,reasonValues:c}=e.execute(this.value,t);if(n!==r&&n!==s&&n!==o)throw Error('runAction: Invalid \"status\" value returned from action.execute()');return this.value=i,this.lastResultStatus=n,n===r?(this.reasonStrings=null,this.reasonValues=null,this.errorObject=null,this.lastResultStatus):(this.reasonStrings=u,this.reasonValues=c,this.lastResultStatus)}catch(e){return this.value=null,this.reasonStrings=null,this.reasonValues=null,this.errorObject=e,this.lastResultStatus=o,this.lastResultStatus}}addDOMDocumentsToSet(e){if(Array.isArray(this.value))for(const t of this.value)e.add(i(t));else this.value&&e.add(i(this.value))}failureString(){return this.reasonStrings?n.buildStringFromTagValues(this.reasonStrings,this.reasonValues):this.errorObject?this.errorObject.toString():null}},n.resultToArray=(e=>{if(Array.isArray(e))return e;if(void 0===e||null===e)return[];return[e]}),n.resultCount=(e=>{if(Array.isArray(e))return e.length;if(void 0===e||null===e)return 0;return 1}),n.buildStringFromTagValues=((e,t)=>{let n=e[0];for(let i=1;i<e.length;++i)n+=String(t[i-1]),n+=e[i];return n}),n.executeSuccess=(e=>Object.freeze({status:r,value:e})),n.executePendingTag=((e,...t)=>Object.freeze({status:s,reasonStrings:Object.freeze(e),reasonValues:Object.freeze(t),value:null})),n.executeFatalFailureTag=((e,...t)=>Object.freeze({status:o,reasonStrings:Object.freeze(e),reasonValues:Object.freeze(t),value:null})),n.RESULT_STATUS_SUCCESS=r,n.RESULT_STATUS_PENDING=s,n.RESULT_STATUS_FATAL_FAILURE=o},{\"./dom\":9}]},{},[1])(1)});";

@@ -1,1 +0,1 @@

module.exports="(function(f){if(typeof exports===\"object\"&&typeof module!==\"undefined\"){module.exports=f()}else if(typeof define===\"function\"&&define.amd){define([],f)}else{var g;if(typeof window!==\"undefined\"){g=window}else if(typeof global!==\"undefined\"){g=global}else if(typeof self!==\"undefined\"){g=self}else{g=this}g.Bluefox = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require==\"function\"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error(\"Cannot find module '\"+o+\"'\");throw f.code=\"MODULE_NOT_FOUND\",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require==\"function\"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){\n'use strict';\nconst ExpressionChainable = require('./ExpressionChainable');\nconst Expression = require('./Expression');\nconst Execution = require('./Execution');\nconst DocumentObservers = require('./DocumentObservers');\nconst Timer = require('./Timer');\n\nclass Bluefox extends ExpressionChainable {\n static setTimerFunctions(setTimeout, clearTimeout) {\n Timer.setTimeout = setTimeout;\n Timer.clearTimeout = clearTimeout;\n }\n\n constructor() {\n super();\n this._expressionExecutor = this._expressionExecutor.bind(this);\n this._documentObservers = new DocumentObservers();\n this._nextExecutionId = 0;\n this.onExecuteBegin = null; // ({expression, executionId, resultPromise}) => undefined\n this.onExecuteEnd = null; // ({expression, executionId, resultPromise}) => undefined\n this.onCheckBegin = null; // ({expression, executionId, resultPromise}) => undefined\n this.onCheckEnd = null; // ({expression, executionId, resultPromise}) => undefined\n }\n\n createNextExpression(action, timeout = 30000) {\n return new Expression(null, action, timeout, this._expressionExecutor);\n }\n\n runAllChecks(document) {\n this._documentObservers.runAllChecks(document);\n }\n\n runAllChecksDeferred(document) {\n this._documentObservers.runAllChecksDeferred(document);\n }\n\n async _expressionExecutor(expression) {\n const execution = new Execution(expression, this._documentObservers, this._nextExecutionId++);\n const {onExecuteBegin, onExecuteEnd, onCheckBegin, onCheckEnd} = this;\n execution.onCheckBegin = onCheckBegin;\n execution.onCheckEnd = onCheckEnd;\n\n onExecuteBegin && onExecuteBegin({\n expression,\n executionId: execution.id,\n resultPromise: execution.executionPromise,\n });\n\n try {\n return await execution.execute();\n }\n finally {\n onExecuteEnd && onExecuteEnd({\n expression,\n executionId: execution.id,\n resultPromise: execution.executionPromise,\n });\n }\n }\n}\n\nmodule.exports = Bluefox;\n\n},{\"./DocumentObservers\":3,\"./Execution\":4,\"./Expression\":5,\"./ExpressionChainable\":6,\"./Timer\":7}],2:[function(require,module,exports){\n'use strict';\n\nconst {getDOMDocumentWindow, isDOMWindow, isDOMDocument, addEventListener, removeEventListener} = require('./dom');\nconst Timer = require('./Timer');\n\nclass DocumentObserver {\n constructor(document) {\n if (!isDOMDocument(document)) {\n throw Error('new DocumentObserver(document): Invalid argument `document`');\n }\n\n const window = getDOMDocumentWindow(document);\n if (!isDOMWindow(window)) {\n throw Error('new DocumentObserver(document): The given `document` must have a browsing context (a window)');\n }\n\n this.document = document;\n this.window = window;\n\n this._handleChange = this._handleChange.bind(this);\n this._handleChangeDeferred = this._handleChangeDeferred.bind(this);\n this._handleDeferrals = this._handleDeferrals.bind(this);\n\n // state:\n this._pendingExecutions = new Set();\n this._registeredListeners = false;\n this._mutationObserver = null;\n this._hasDeferredChange = false;\n this._removeListenersTimer = new Timer(0, () => this.removeListeners());\n\n // some checks are deferred, for two reasons:\n // 1. avoid running the checks too often\n // 2. wait for the other JS to complete whatever it is working on, in most cases this is the \"moment\" that we would like to measure\n this._deferralsTimer = new Timer(0, this._handleDeferrals);\n }\n\n get hasPendingExecutions() {\n return this._pendingExecutions.size > 0;\n }\n\n get hasRegisteredListeners() {\n return this._registeredListeners;\n }\n\n register(execution) {\n this._pendingExecutions.add(execution);\n this.registerListeners();\n }\n\n unregister(execution) {\n this._pendingExecutions.delete(execution);\n\n if (!this.hasPendingExecutions) {\n // defer the actual removal of the events, this avoids continuous the adding and removing of the event handlers in case\n // multiple wait expressions are run after one another, e.g.:\n // await bluefox.target(window).selector('foo'); await bluefox.target(window).selector('bar');\n this._removeListenersTimer.reschedule();\n }\n }\n\n registerListeners() {\n this._removeListenersTimer.cancel();\n\n if (this.hasRegisteredListeners) {\n return;\n }\n\n this._registeredListeners = true;\n const {window, document} = this;\n addEventListener(window, 'DOMContentLoaded', this._handleChange, true);\n addEventListener(window, 'load', this._handleChange, true);\n addEventListener(document, 'load', this._handleChangeDeferred, true); // e.g. <img>, <script src='\"> load\n\n // 'error' fired at the `window` represents a JavaScript runtime error\n // 'error' events that bubble up to the `document` are resource error, such an <img> that fails to load\n addEventListener(document, 'error', this._handleChangeDeferred, true); // e.g. <img/> fails to load\n\n this._mutationObserver = new this.window.MutationObserver(this._handleChangeDeferred);\n this._mutationObserver.observe(document, {\n attributeOldValue: false,\n attributes: true,\n characterData: true,\n characterDataOldValue: false,\n childList: true,\n subtree: true,\n });\n }\n\n removeListeners() {\n if (!this.hasRegisteredListeners) {\n return;\n }\n\n const {window, document} = this;\n this._removeListenersTimer.cancel();\n removeEventListener(window, 'DOMContentLoaded', this._handleChange, true);\n removeEventListener(window, 'load', this._handleChange, true);\n removeEventListener(document, 'load', this._handleChangeDeferred, true);\n removeEventListener(document, 'error', this._handleChangeDeferred, true);\n this._mutationObserver.disconnect();\n this._mutationObserver = null;\n this._deferralsTimer.cancel();\n this._registeredListeners = false;\n }\n\n runChecks() {\n this._hasDeferredChange = false;\n this._deferralsTimer.cancel();\n\n for (const execution of this._pendingExecutions) {\n execution.check();\n }\n }\n\n runChecksDeferred() {\n this._hasDeferredChange = true;\n this._deferralsTimer.schedule();\n }\n\n drainDeferrals() {\n this._handleDeferrals();\n }\n\n _handleChange() {\n this.runChecks();\n }\n\n _handleChangeDeferred() {\n this._hasDeferredChange = true;\n this._deferralsTimer.schedule();\n }\n\n _handleDeferrals() {\n if (this._hasDeferredChange) {\n this._hasDeferredChange = false;\n this.runChecks();\n }\n }\n}\n\nmodule.exports = DocumentObserver;\n\n},{\"./Timer\":7,\"./dom\":9}],3:[function(require,module,exports){\n'use strict';\nconst DocumentObserver = require('./DocumentObserver');\n\nclass DocumentObservers {\n constructor() {\n // HTMLDocument -> DocumentObserver (a Window object is not used as the key\n // because the reference is reused between navigation, see WindowProxy in spec)\n this._documentToObserver = new WeakMap();\n }\n\n _getOrCreate(document) {\n let documentObserver = this._documentToObserver.get(document);\n if (!documentObserver) {\n documentObserver = new DocumentObserver(document);\n this._documentToObserver.set(document, documentObserver);\n }\n return documentObserver;\n }\n\n registerExecution(document, execution) {\n const documentObserver = this._getOrCreate(document);\n documentObserver.register(execution);\n }\n\n unregisterExecution(document, execution) {\n const documentObserver = this._documentToObserver.get(document);\n if (documentObserver) {\n documentObserver.unregister(execution);\n }\n }\n\n runAllChecks(document) {\n const documentObserver = this._documentToObserver.get(document);\n if (documentObserver) {\n documentObserver.runChecks();\n }\n }\n\n runAllChecksDeferred(document) {\n const documentObserver = this._documentToObserver.get(document);\n if (documentObserver) {\n documentObserver.runChecksDeferred();\n }\n }\n\n drainDeferrals(document) {\n const documentObserver = this._documentToObserver.get(document);\n if (documentObserver) {\n documentObserver.drainDeferrals();\n }\n }\n}\n\nmodule.exports = DocumentObservers;\n\n},{\"./DocumentObserver\":2}],4:[function(require,module,exports){\n'use strict';\nconst {ResultWrapper, RESULT_STATUS_SUCCESS, RESULT_STATUS_PENDING} = require('./result');\nconst Timer = require('./Timer');\n\nclass Execution {\n constructor(expression, documentObservers, id) {\n this.expression = expression;\n this.expressionChain = expression.getExpressionChain();\n this.documentObservers = documentObservers;\n this.id = id;\n this.onCheckBegin = null;\n this.onCheckEnd = null;\n this.executionPromise = new Promise((resolve, reject) => {\n this.executionResolve = resolve;\n this.executionReject = reject;\n });\n this.executionStart = null;\n this.didFirstCheck = false;\n this.fulfilled = false;\n this.registeredDocuments = new Set();\n this.timeoutTimers = new Map();\n this._handleTimeoutTimer = this._handleTimeoutTimer.bind(this);\n this.createTimer = (timeout, handler) => new Timer(timeout, handler);\n this.now = () => Date.now();\n }\n\n async execute() {\n if (!this.didFirstCheck) {\n // immediately trigger the very first check, this also ensures that all\n // event handlers are added to the appropriate DOMWindow(s), which then\n // triggers any further check\n this.firstCheck();\n }\n return this.executionPromise;\n }\n\n firstCheck() {\n if (this.didFirstCheck) {\n throw Error('Invalid state');\n }\n\n this.didFirstCheck = true;\n this.executionStart = this.now();\n\n for (const expression of this.expressionChain) {\n const {timeout} = expression.configuration;\n\n if (!this.timeoutTimers.has(timeout)) {\n const timer = this.createTimer(timeout, this._handleTimeoutTimer);\n timer.schedule();\n this.timeoutTimers.set(timeout, timer);\n }\n }\n\n this.check();\n }\n\n check() {\n if (!this.didFirstCheck) {\n throw Error('Execution#check(): This execution has not been started');\n }\n\n if (this.fulfilled) {\n throw Error('Execution#check(): This execution has already been fulfilled');\n }\n\n const {onCheckBegin, onCheckEnd} = this;\n\n onCheckBegin && onCheckBegin({\n expression: this.expression,\n executionId: this.id,\n resultPromise: this.executionPromise,\n });\n\n const now = this.now();\n const currentDuration = now - this.executionStart;\n const result = new ResultWrapper();\n const documents = new Set();\n let pendingExpression = false;\n\n for (const expression of this.expressionChain) {\n const resultStatus = result.runAction(expression.configuration.action);\n\n if (resultStatus === RESULT_STATUS_PENDING) {\n pendingExpression = expression;\n }\n\n if (resultStatus !== RESULT_STATUS_SUCCESS) {\n break;\n }\n\n result.addDOMDocumentsToSet(documents);\n }\n\n if (pendingExpression) {\n const {timeout} = pendingExpression.configuration;\n\n if (currentDuration >= timeout) {\n this.fulfilled = true;\n this.cleanup();\n this.executionReject(this.timeoutError(timeout, result, pendingExpression));\n }\n else {\n // expression was not fulfilled, listen for some events to trigger a recheck\n this.updateDocumentRegistrations(documents);\n }\n }\n else {\n this.fulfill(result);\n }\n\n onCheckEnd && onCheckEnd({\n expression: this.expression,\n executionId: this.id,\n resultPromise: this.executionPromise,\n });\n }\n\n timeoutError(timeout, result, pendingExpression) {\n const actionFailure = result.failureString();\n const message = `Wait expression timed out after ${timeout / 1000} seconds because ${actionFailure}. ` +\n pendingExpression.describe();\n const error = new Error(message);\n error.timeout = timeout;\n error.actionFailure = actionFailure;\n error.expression = pendingExpression;\n error.fullExpression = this.expression;\n return error;\n }\n\n updateDocumentRegistrations(documents) {\n for (const document of this.registeredDocuments) {\n if (!documents.has(document)) {\n this.documentObservers.unregisterExecution(document, this);\n }\n }\n for (const document of documents) {\n // (it is okay to call this method too many times)\n this.documentObservers.registerExecution(document, this);\n }\n this.registeredDocuments = documents;\n }\n\n cleanup() {\n for (const window of this.registeredDocuments) {\n this.documentObservers.unregisterExecution(window, this);\n }\n this.registeredDocuments.clear();\n\n for (const timer of this.timeoutTimers.values()) {\n timer.cancel();\n }\n this.timeoutTimers.clear();\n }\n\n fulfill(result) {\n this.fulfilled = true;\n this.cleanup();\n\n if (result.lastResultStatus === RESULT_STATUS_SUCCESS) {\n this.executionResolve(result.value);\n }\n else {\n const error = result.errorObject\n ? result.errorObject\n : Error(result.failureString());\n this.executionReject(error);\n }\n }\n\n _handleTimeoutTimer() {\n this.check();\n }\n}\n\nmodule.exports = Execution;\n\n},{\"./Timer\":7,\"./result\":10}],5:[function(require,module,exports){\n'use strict';\nconst ExpressionChainable = require('./ExpressionChainable');\nconst {DEFAULT_AMOUNT_ACTION} = require('./actions');\n\n/* istanbul ignore if */\nif (!DEFAULT_AMOUNT_ACTION.appliesAmountCheck) {\n // infinite recursion would occur in this case\n throw Error('Assertion Error');\n}\n\nclass Expression extends ExpressionChainable {\n constructor(previous, action, timeout, executor) {\n super();\n\n if (previous !== null && !(previous instanceof Expression)) {\n throw Error('Invalid argument `previous`');\n }\n\n if (Boolean(previous) === Boolean(executor)) {\n throw Error('`executor` must (only) be set for the root Expression');\n }\n\n if (!action ||\n typeof action !== 'object' ||\n typeof action.execute !== 'function' ||\n typeof action.describe !== 'function') {\n throw Error('Invalid argument `action`');\n }\n\n if (typeof timeout !== 'number') {\n throw Error('Invalid argument `timeout`');\n }\n\n const prevConfig = previous && previous.configuration;\n const prevWantsDefaultAmountCheck = prevConfig && prevConfig.wantsDefaultAmountCheck;\n const wantsDefaultAmountCheck =\n (prevWantsDefaultAmountCheck || action.wantsDefaultAmountCheck) &&\n !action.appliesAmountCheck;\n\n // store our own data under a single property to avoid a messy user facing API\n Object.defineProperty(this, 'configuration', {\n value: {\n previous,\n depth: prevConfig ? prevConfig.depth + 1 : 0,\n action,\n timeout,\n _executor: prevConfig ? prevConfig._executor : executor,\n wantsDefaultAmountCheck,\n _defaultAmountExpression: null,\n },\n });\n\n this.configuration._defaultAmountExpression = wantsDefaultAmountCheck\n ? new Expression(this, DEFAULT_AMOUNT_ACTION, timeout)\n : null;\n\n Object.freeze(this.configuration);\n Object.freeze(this);\n }\n\n getExpressionChain() {\n const {_defaultAmountExpression} = this.configuration;\n if (_defaultAmountExpression) {\n return _defaultAmountExpression.getExpressionChain();\n }\n\n const expressionCount = this.configuration.depth + 1;\n const result = new Array(expressionCount);\n let currentExpression = this;\n for (let i = expressionCount - 1; i >= 0; --i) {\n result[i] = currentExpression;\n const {previous} = currentExpression.configuration;\n currentExpression = previous;\n }\n\n /* istanbul ignore if */\n if (currentExpression) {\n throw Error('Assertion Error');\n }\n\n return result;\n }\n\n createNextExpression(action, timeout = this.configuration.timeout) {\n return new Expression(this, action, timeout);\n }\n\n describe() {\n const descriptions = [];\n\n for (const expression of this.getExpressionChain()) {\n const {configuration} = expression;\n const description = configuration.action.describe(configuration.timeout);\n if (description) {\n descriptions.push(description);\n }\n }\n\n return `The expression ${descriptions.join(', ')}.`;\n }\n\n async execute() {\n return await this.configuration._executor(this);\n }\n\n then(...args) {\n // Note the intentional difference between:\n // expression = wait.selector('foo')\n // await expression;\n // await expression; // execute again!\n // and:\n // promise = wait.selector('foo').execute()\n // await expression;\n // await expression;\n return this.execute().then(...args);\n }\n\n catch(...args) {\n return this.execute().catch(...args);\n }\n\n finally(handler) {\n return this.then(\n value => Promise.resolve(handler()).then(() => value),\n error => Promise.resolve(handler()).then(() => Promise.reject(error))\n );\n }\n}\n\nmodule.exports = Expression;\n\n},{\"./ExpressionChainable\":6,\"./actions\":8}],6:[function(require,module,exports){\n'use strict';\nconst actions = require('./actions');\n\n/** @constructor */\nclass ExpressionChainable {\n /**\n * @param {actions.Action} action\n * @param {number} [timeout=previous.timeout]\n * @return {ExpressionChainable}\n * @method createNextExpression\n * @memberof ExpressionChainable.prototype\n */\n\n /**\n * @param {actions.Action} action\n * @return {ExpressionChainable}\n */\n action(action) {\n return this.createNextExpression(action);\n }\n\n /**\n * @param {Window|Node|Array|Function} targets\n * @return {ExpressionChainable}\n */\n target(targets) {\n return this.createNextExpression(new actions.Target(targets));\n }\n\n /**\n * @param {number|string} timeout string in the format of \"10s\" to specify seconds or a number to specify milliseconds\n * @return {ExpressionChainable}\n */\n timeout(timeout) {\n const timeoutMs = actions.parseTimeoutArgument(timeout);\n return this.createNextExpression(new actions.Noop(), timeoutMs);\n }\n\n /**\n * @param {number} minimum\n * @param {number} maximum\n * @return {ExpressionChainable}\n */\n amount(minimum, maximum) {\n return this.createNextExpression(new actions.Amount(minimum, maximum));\n }\n\n /**\n * @param {string|Function} expression\n * @return {ExpressionChainable}\n */\n selector(expression) {\n return this.createNextExpression(new actions.Selector(expression));\n }\n\n /**\n * @param {string|Function} expression\n * @return {ExpressionChainable}\n */\n selectorAll(expression) {\n return this.createNextExpression(new actions.SelectorAll(expression));\n }\n\n /**\n * @param {string|Function} expression\n * @return {ExpressionChainable}\n */\n xpath(expression) {\n return this.createNextExpression(new actions.XPath(expression));\n }\n\n /**\n * @param {string|Function} expression\n * @return {ExpressionChainable}\n */\n xpathAll(expression) {\n return this.createNextExpression(new actions.XPathAll(expression));\n }\n\n /**\n * @return {ExpressionChainable}\n */\n documentInteractive() {\n return this.createNextExpression(new actions.DocumentInteractive());\n }\n\n /**\n * @return {ExpressionChainable}\n */\n documentComplete() {\n return this.createNextExpression(new actions.DocumentComplete());\n }\n}\n\nmodule.exports = ExpressionChainable;\n\n},{\"./actions\":8}],7:[function(require,module,exports){\n'use strict';\n\nclass Timer {\n constructor(delay, callback) {\n this._id = 0;\n this.delay = delay;\n this.callback = callback;\n this.setTimeout = Timer.setTimeout;\n this.clearTimeout = Timer.clearTimeout;\n this._timerCallback = () => {\n this._id = 0;\n this.callback.call(null);\n };\n }\n\n get isScheduled() {\n return Boolean(this._id);\n }\n\n schedule() {\n if (!this._id) {\n this._id = this.setTimeout(this._timerCallback, this.delay);\n }\n }\n\n cancel() {\n if (this.isScheduled) {\n this.clearTimeout(this._id);\n this._id = 0;\n }\n }\n\n reschedule() {\n this.cancel();\n this.schedule();\n }\n}\n\n/* istanbul ignore next */\nTimer.setTimeout = (func, delay) => setTimeout(func, delay);\n/* istanbul ignore next */\nTimer.clearTimeout = (id) => clearTimeout(id);\n\nmodule.exports = Timer;\n\n},{}],8:[function(require,module,exports){\n'use strict';\nconst {\n isResultItem,\n isDOMNode,\n describeDOMObject,\n cssSelectorFirst,\n cssSelectorArray,\n xpathFirst,\n xpathArray,\n resultItemToDocument,\n documentReadyState,\n} = require('./dom');\nconst {resultToArray, resultCount, executeSuccess, executePendingTag} = require('./result');\n\nconst freezeCopyIfArray = value => {\n if (Array.isArray(value)) {\n return Object.freeze(value.slice());\n }\n return value;\n};\nconst funcOrValue = value => (typeof value === 'function' ? value() : value);\nconst LEFT_QUOTE = '\\u201c';\nconst RIGHT_QUOTE = '\\u201d';\n\nexports.parseTimeoutArgument = timeout => {\n if (typeof timeout === 'string' && /^([\\d.]+)s$/.test(timeout)) {\n return parseFloat(timeout) * 1000;\n }\n\n if (typeof timeout === 'number') {\n return timeout;\n }\n\n throw Error('Invalid timeout argument, expected a number or a duration string');\n};\n\nclass Action {\n /**\n * @param {?Window|Node|Array.<(Window|Node)>} currentResult\n * @return {{status: string, reasonStrings: string[], reasonValues: string[], value: (?Window|Node|Array.<(Window|Node)>)}}\n */\n execute(currentResult) {\n return executeSuccess(currentResult);\n }\n\n /**\n * @param {number} timeout milliseconds\n * @return {string}\n */\n describe(timeout) {\n return '';\n }\n\n /**\n * If true, this action should trigger a default amount check. Unless the user provides an amount check\n * For example if this value is true for \"myAction\": `.myAction()` would have the same effect as `.myAction().amount(1, Infinity)`\n * @return {boolean}\n */\n get wantsDefaultAmountCheck() {\n return false;\n }\n\n /**\n * If true, this action perform an an amount check and the default amount check should not be applied.\n * @return {boolean}\n */\n get appliesAmountCheck() {\n return false;\n }\n}\n\nclass Noop extends Action {\n constructor() {\n super();\n Object.freeze(this);\n }\n\n execute(currentResult) {\n return executeSuccess(currentResult);\n }\n\n describe() {\n return '';\n }\n}\n\nclass Target extends Action {\n /**\n * @param {?Window|Node|Array.<(Window|Node)>|Function} targets\n */\n constructor(targets) {\n super();\n this.results = freezeCopyIfArray(targets);\n Object.freeze(this);\n }\n\n execute(currentResult) {\n const results = freezeCopyIfArray(funcOrValue(this.results));\n\n for (const result of resultToArray(results)) {\n if (!isResultItem(result)) {\n return executePendingTag`a value that is not a Window nor a Node was set as the target`;\n }\n }\n\n return executeSuccess(results);\n }\n\n describe() {\n const results = this.results;\n // (some DOM nodes are typeof function)\n if (typeof results === 'function' && !isDOMNode(results)) {\n return 'sets the target using a callback';\n }\n\n if (Array.isArray(results)) {\n const descriptions = [];\n\n for (const result of results) {\n if (descriptions.length >= 5) {\n descriptions.push('\\u2026');\n break;\n }\n\n descriptions.push(describeDOMObject(result));\n }\n\n return `sets the target to [${descriptions.join(', ')}]`;\n }\n\n return `sets the target to ${describeDOMObject(results)}`;\n }\n}\n\nclass Amount extends Action {\n constructor(minimum, maximum = minimum) {\n super();\n this.minimum = minimum;\n this.maximum = maximum;\n\n if (typeof this.minimum !== 'number') {\n throw Error('.amount(minimum, maximum): minimum must be a number');\n }\n\n if (typeof this.maximum !== 'number') {\n throw Error('.amount(minimum, maximum): maximum must be a number');\n }\n\n if (this.minimum > this.maximum) {\n throw Error('.amount(minimum, maximum): maximum must be greater than or equal to minimum');\n }\n\n Object.freeze(this);\n }\n\n execute(currentResult) {\n const count = resultCount(currentResult);\n\n if (count < this.minimum) {\n if (count === 0) {\n return executePendingTag`no results were found, instead of a minimum of ${this.minimum} results`;\n }\n\n return executePendingTag`only ${count} results were found, instead of a minimum of ${this.minimum} results`;\n }\n\n if (count > this.maximum) {\n return executePendingTag`${count} results were found, instead of a maximum of ${this.maximum} results`;\n }\n\n return executeSuccess(currentResult);\n }\n\n describe(timeout) {\n const prefix = `waits up to ${timeout / 1000} seconds until`;\n\n if (this.minimum === this.maximum) {\n return `${prefix} exactly ${this.minimum} results are found`;\n }\n\n if (this.minimum === 1 && this.maximum === Infinity) {\n return `${prefix} a result is found`;\n }\n\n if (this.maximum === Infinity) {\n return `${prefix} ${this.minimum} or more results are found`;\n }\n\n return `${prefix} between ${this.minimum} and ${this.maximum} (inclusive) results are found`;\n }\n\n get appliesAmountCheck() {\n return true;\n }\n}\n\nclass Selector extends Action {\n constructor(expression) {\n super();\n this.expression = expression;\n Object.freeze(this);\n }\n\n execute(currentResult) {\n const expression = funcOrValue(this.expression);\n\n for (const resultItem of resultToArray(currentResult)) {\n const result = cssSelectorFirst(resultItem, expression);\n\n if (result) {\n return executeSuccess(result);\n }\n }\n\n return executeSuccess(null);\n }\n\n describe() {\n if (typeof this.expression === 'function') {\n return `finds the first descendant element matching a CSS selector from a callback`;\n }\n\n return `finds the first descendant element matching the CSS selector ${LEFT_QUOTE}${this.expression}${RIGHT_QUOTE}`;\n }\n\n get wantsDefaultAmountCheck() {\n return true;\n }\n}\n\nclass SelectorAll extends Action {\n constructor(expression) {\n super();\n this.expression = expression;\n Object.freeze(this);\n }\n\n execute(currentResult) {\n const expression = funcOrValue(this.expression);\n const elementListList = [];\n\n for (const resultItem of resultToArray(currentResult)) {\n const elementList = cssSelectorArray(resultItem, expression);\n elementListList.push(elementList);\n }\n\n const value = [].concat(...elementListList);\n Object.freeze(value);\n return executeSuccess(value);\n }\n\n describe() {\n if (typeof this.expression === 'function') {\n return `finds all descendant elements matching a CSS selector from a callback`;\n }\n\n return `finds all descendant elements matching the CSS selector ${LEFT_QUOTE}${this.expression}${RIGHT_QUOTE}`;\n }\n\n get wantsDefaultAmountCheck() {\n return true;\n }\n}\n\nclass XPath extends Action {\n constructor(expression) {\n super();\n this.expression = expression;\n Object.freeze(this);\n }\n\n execute(currentResult) {\n const expression = funcOrValue(this.expression);\n\n for (const resultItem of resultToArray(currentResult)) {\n const result = xpathFirst(resultItem, expression);\n\n if (result) {\n return executeSuccess(result);\n }\n }\n\n return executeSuccess(null);\n }\n\n describe() {\n if (typeof this.expression === 'function') {\n return `finds the first element matching a XPath expression from a callback`;\n }\n\n return `finds the first element matching the XPath expression ${LEFT_QUOTE}${this.expression}${RIGHT_QUOTE}`;\n }\n\n get wantsDefaultAmountCheck() {\n return true;\n }\n}\n\nclass XPathAll extends Action {\n constructor(expression) {\n super();\n this.expression = expression;\n Object.freeze(this);\n }\n\n execute(currentResult) {\n const expression = funcOrValue(this.expression);\n const elementListList = [];\n\n for (const resultItem of resultToArray(currentResult)) {\n const elementList = xpathArray(resultItem, expression);\n elementListList.push(elementList);\n }\n\n const value = [].concat(...elementListList);\n Object.freeze(value);\n return executeSuccess(value);\n }\n\n describe() {\n if (typeof this.expression === 'function') {\n return `finds all elements matching a XPath expression from a callback`;\n }\n\n return `finds all elements matching the XPath expression ${LEFT_QUOTE}${this.expression}${RIGHT_QUOTE}`;\n }\n\n get wantsDefaultAmountCheck() {\n return true;\n }\n}\n\nclass DocumentInteractive extends Action {\n constructor() {\n super();\n Object.freeze(this);\n }\n\n execute(currentResult) {\n for (const resultItem of resultToArray(currentResult)) {\n const document = resultItemToDocument(resultItem);\n\n if (documentReadyState(document) === 'loading') {\n return executePendingTag`the HTML document has not yet been parsed`;\n }\n }\n\n return executeSuccess(currentResult);\n }\n\n describe(timeout) {\n return `waits up to ${timeout / 1000} seconds until the HTML document has finished parsing`;\n }\n}\n\nclass DocumentComplete extends Action {\n constructor() {\n super();\n Object.freeze(this);\n }\n\n execute(currentResult) {\n for (const resultItem of resultToArray(currentResult)) {\n const document = resultItemToDocument(resultItem);\n\n const readyState = documentReadyState(document);\n if (readyState === 'loading') {\n return executePendingTag`the HTML document has not yet been parsed`;\n }\n\n if (readyState === 'interactive') {\n return executePendingTag`the HTML document has not yet been loaded`;\n }\n }\n\n return executeSuccess(currentResult);\n }\n\n describe(timeout) {\n return `waits up to ${timeout / 1000} seconds until all synchronous resources of the HTML document have been loaded`;\n }\n}\n\nconst DEFAULT_AMOUNT_ACTION = new Amount(1, Infinity);\n\nexports.Action = Action;\nexports.Noop = Noop;\nexports.Target = Target;\nexports.Amount = Amount;\nexports.DEFAULT_AMOUNT_ACTION = DEFAULT_AMOUNT_ACTION;\nexports.Selector = Selector;\nexports.SelectorAll = SelectorAll;\nexports.XPath = XPath;\nexports.XPathAll = XPathAll;\nexports.DocumentInteractive = DocumentInteractive;\nexports.DocumentComplete = DocumentComplete;\n\n},{\"./dom\":9,\"./result\":10}],9:[function(require,module,exports){\n'use strict';\n\nconst ELEMENT_NODE = 1;\nconst XPATHRESULT_ORDERED_NODE_SNAPSHOT_TYPE = 7;\nconst XPATHRESULT_FIRST_ORDERED_NODE_TYPE = 9;\n\nconst dom = exports;\nconst getStringTag = object => Object.prototype.toString.call(object);\n\ndom.findPropertyInChain = (object, name) => {\n let proto = Object.getPrototypeOf(object);\n while (proto) {\n const descriptor = Object.getOwnPropertyDescriptor(proto, name);\n if (descriptor) {\n return descriptor;\n }\n proto = Object.getPrototypeOf(proto);\n }\n return null;\n};\n\n/**\n * @param {*} object\n * @return {Boolean}\n */\ndom.isDOMWindow = object => Boolean(\n object &&\n object.window === object &&\n object.self === object &&\n dom.isDOMDocument(object.document)\n);\n\n/**\n * @param {*} object\n * @return {Boolean} (window is not a Node)\n */\ndom.isDOMNode = object => Boolean(\n object &&\n (typeof object === 'object' || typeof object === 'function') && // some nodes are typeof function\n 'nodeType' in object &&\n 'nodeName' in object &&\n 'ownerDocument' in object &&\n 'parentNode' in object\n);\n\n/**\n * @param {*} object\n * @return {Boolean}\n */\ndom.isDOMDocument = object => Boolean(\n dom.isDOMNode(object) &&\n 'defaultView' in object &&\n (getStringTag(object) === '[object HTMLDocument]' || getStringTag(object) === '[object Document]')\n);\n\n/**\n * @param {*} object\n * @return {Boolean}\n */\ndom.isDOMElement = object => Boolean(\n dom.isDOMNode(object) &&\n (object.nodeType === ELEMENT_NODE || getStringTag(object) === '[object HTMLFormElement]') &&\n 'tagName' in object\n);\n\n/**\n * @param {HTMLDocument} document\n * @return {?Window}\n */\ndom.getDOMDocumentWindow = document => {\n const defaultView = dom.findPropertyInChain(document, 'defaultView');\n return defaultView.get.call(document);\n};\n\n/**\n * Is the given argument a valid result item as input/output to a wait `Expression`\n * @param {*} object\n * @return {boolean}\n */\ndom.isResultItem = object => Boolean(\n dom.isDOMWindow(object) ||\n dom.isDOMDocument(object) ||\n dom.isDOMElement(object)\n);\n\n/**\n * @param {Window|Node} object\n * @return {Window}\n */\ndom.resultItemToWindow = object => {\n if (dom.isDOMWindow(object)) {\n return object;\n }\n\n if (dom.isDOMDocument(object)) {\n return dom.getDOMDocumentWindow(object); // (might be null)\n }\n\n if (dom.isDOMNode(object)) {\n const ownerDocument = dom.findPropertyInChain(object, 'ownerDocument');\n return dom.getDOMDocumentWindow(ownerDocument.get.call(object));\n }\n\n throw Error('dom.resultItemToWindow(): Invalid argument');\n};\n\n/**\n * @param {Window|Node} object\n * @return {Document}\n */\ndom.resultItemToDocument = object => {\n if (dom.isDOMWindow(object)) {\n return object.document;\n }\n\n if (dom.isDOMDocument(object)) {\n return object;\n }\n\n if (dom.isDOMNode(object)) {\n const ownerDocument = dom.findPropertyInChain(object, 'ownerDocument');\n return ownerDocument.get.call(object);\n }\n\n throw Error('dom.resultItemToDocument(): Invalid argument');\n};\n\n/**\n * Find the closest object that implements the `ParentElement` interface, for the given result item\n * @param {Window|Node} object\n * @return {ParentElement} (A Document or an Element)\n */\ndom.resultItemToParentNode = object => {\n if (dom.isDOMWindow(object)) {\n return object.document;\n }\n\n if (dom.isDOMDocument(object)) {\n return object;\n }\n\n if (dom.isDOMElement(object)) {\n return object;\n }\n\n throw Error('dom.resultItemToParentNode(): Invalid argument');\n};\n\n/**\n * @param {Window|Node} object\n * @return {string}\n */\ndom.describeDOMObject = object => {\n if (object === undefined) {\n return '<#undefined>';\n }\n\n if (object === null) {\n return '<#null>';\n }\n\n if (dom.isDOMWindow(object)) {\n return '<#window>';\n }\n\n if (dom.isDOMDocument(object)) {\n return '<#document>';\n }\n\n if (getStringTag(object) === '[object HTMLFormElement]') {\n return '<form>';\n }\n\n if (dom.isDOMNode(object)) {\n return `<${object.nodeName.toLowerCase()}>`;\n }\n\n return '<???>';\n};\n\n/**\n * @param {Window|Node} resultItem\n * @param {string} expression\n * @return {?Element}\n */\ndom.cssSelectorFirst = (resultItem, expression) => {\n const context = dom.resultItemToParentNode(resultItem);\n const querySelector = dom.findPropertyInChain(context, 'querySelector').value;\n return querySelector.call(context, expression);\n};\n\n/**\n * @param {Window|Node} resultItem\n * @param {string} expression\n * @return {Element[]}\n */\ndom.cssSelectorArray = (resultItem, expression) => {\n const context = dom.resultItemToParentNode(resultItem);\n const querySelectorAll = dom.findPropertyInChain(context, 'querySelectorAll').value;\n return Array.from(querySelectorAll.call(context, expression));\n};\n\n/**\n * @param {Window|Node} resultItem\n * @param {string} expression\n * @return {?Element}\n */\ndom.xpathFirst = (resultItem, expression) => {\n const document = dom.resultItemToDocument(resultItem);\n const context = dom.resultItemToParentNode(resultItem);\n const evaluate = dom.findPropertyInChain(document, 'evaluate').value;\n const xpathResult = evaluate.call(document, expression, context, null, XPATHRESULT_FIRST_ORDERED_NODE_TYPE, null);\n return xpathResult.singleNodeValue;\n};\n\n/**\n * @param {Window|Node} resultItem\n * @param {string} expression\n * @return {Element[]}\n */\ndom.xpathArray = (resultItem, expression) => {\n const document = dom.resultItemToDocument(resultItem);\n const context = dom.resultItemToParentNode(resultItem);\n const evaluate = dom.findPropertyInChain(document, 'evaluate').value;\n const xpathResult = evaluate.call(document, expression, context, null, XPATHRESULT_ORDERED_NODE_SNAPSHOT_TYPE, null);\n\n const array = new Array(xpathResult.snapshotLength);\n for (let i = 0; i < array.length; ++i) {\n array[i] = xpathResult.snapshotItem(i);\n }\n\n return array;\n};\n\n/**\n * @param {HTMLDocument} document\n * @return {string} \"loading\" or \"interactive\" or \"complete\"\n */\ndom.documentReadyState = document => {\n const readyState = dom.findPropertyInChain(document, 'readyState');\n return readyState.get.call(document);\n};\n\ndom.addEventListener = (object, ...args) => {\n if (dom.isDOMNode(object)) {\n const addEventListener = dom.findPropertyInChain(object, 'addEventListener');\n return addEventListener.value.apply(object, args);\n }\n\n // WindowProxy or something different\n return object.addEventListener(...args);\n};\n\ndom.removeEventListener = (object, ...args) => {\n if (dom.isDOMNode(object)) {\n const removeEventListener = dom.findPropertyInChain(object, 'removeEventListener');\n return removeEventListener.value.apply(object, args);\n }\n\n // WindowProxy or something different\n return object.removeEventListener(...args);\n};\n\n},{}],10:[function(require,module,exports){\n'use strict';\nconst {resultItemToDocument} = require('./dom');\n\nconst RESULT_STATUS_SUCCESS = 'success';\nconst RESULT_STATUS_PENDING = 'pending';\nconst RESULT_STATUS_FATAL_FAILURE = 'fatal failure';\n\nexports.ResultWrapper = class ResultWrapper {\n constructor() {\n /** @type {?Node|Node[]} */\n this.value = null;\n /** @type {?string[]} */\n this.reasonStrings = null;\n /** @type {?Array} */\n this.reasonValues = null;\n /** @type {?Error} */\n this.errorObject = null;\n /** one of RESULT_STATUS_*\n * @type {?string}\n */\n this.lastResultStatus = null;\n }\n\n runAction(action) {\n try {\n const {status, value, reasonStrings, reasonValues} = action.execute(this.value);\n\n if (status !== RESULT_STATUS_SUCCESS && status !== RESULT_STATUS_PENDING && status !== RESULT_STATUS_FATAL_FAILURE) {\n throw Error('runAction: Invalid \"status\" value returned from action.execute()');\n }\n\n this.value = value;\n this.lastResultStatus = status;\n\n if (status === RESULT_STATUS_SUCCESS) {\n this.reasonStrings = null;\n this.reasonValues = null;\n this.errorObject = null;\n return this.lastResultStatus;\n }\n // status = pending / fatal failure\n\n this.reasonStrings = reasonStrings;\n this.reasonValues = reasonValues;\n return this.lastResultStatus;\n }\n catch (error) {\n this.value = null;\n this.reasonStrings = null;\n this.reasonValues = null;\n this.errorObject = error;\n this.lastResultStatus = RESULT_STATUS_FATAL_FAILURE;\n return this.lastResultStatus;\n }\n }\n\n addDOMDocumentsToSet(documents) {\n if (Array.isArray(this.value)) {\n for (const resultItem of this.value) {\n documents.add(resultItemToDocument(resultItem));\n }\n }\n else if (this.value) {\n documents.add(resultItemToDocument(this.value));\n }\n }\n\n failureString() {\n if (this.reasonStrings) {\n return exports.buildStringFromTagValues(this.reasonStrings, this.reasonValues);\n }\n\n if (this.errorObject) {\n return this.errorObject.toString();\n }\n\n return null;\n }\n};\n\nexports.resultToArray = object => {\n if (Array.isArray(object)) {\n return object;\n }\n if (object === undefined || object === null) {\n return [];\n }\n return [object];\n};\n\nexports.resultCount = result => {\n if (Array.isArray(result)) {\n return result.length;\n }\n\n if (result === undefined || result === null) {\n return 0;\n }\n\n return 1;\n};\n\nexports.buildStringFromTagValues = (strings, values) => {\n let result = strings[0];\n for (let i = 1; i < strings.length; ++i) {\n result += String(values[i - 1]);\n result += strings[i];\n }\n return result;\n};\n\n/**\n * @param {?Window|Node|Array.<(Window|Node)>} value\n * @return {{status: string, value: (?Window|Node|Array.<(Window|Node)>)}}\n */\nexports.executeSuccess = value => Object.freeze({\n status: RESULT_STATUS_SUCCESS,\n value,\n});\n\n/**\n * @param {string[]} strings\n * @param {...string} values\n * @return {{status: string, reasonStrings: string[], reasonValues: string[], value: null}}\n */\nexports.executePendingTag = (strings, ...values) => Object.freeze({\n status: RESULT_STATUS_PENDING,\n // the descriptive string is only computed if the error is actually displayed\n reasonStrings: Object.freeze(strings),\n reasonValues: Object.freeze(values),\n value: null,\n});\n\n/**\n * @param {string[]} strings\n * @param {...string} values\n * @return {{status: string, reasonStrings: string[], reasonValues: string[], value: null}}\n */\nexports.executeFatalFailureTag = (strings, ...values) => Object.freeze({\n status: RESULT_STATUS_FATAL_FAILURE,\n // the descriptive string is only computed if the error is actually displayed\n reasonStrings: Object.freeze(strings),\n reasonValues: Object.freeze(values),\n value: null,\n});\n\nexports.RESULT_STATUS_SUCCESS = RESULT_STATUS_SUCCESS;\nexports.RESULT_STATUS_PENDING = RESULT_STATUS_PENDING;\nexports.RESULT_STATUS_FATAL_FAILURE = RESULT_STATUS_FATAL_FAILURE;\n\n},{\"./dom\":9}]},{},[1])(1)\n});";
module.exports="(function(f){if(typeof exports===\"object\"&&typeof module!==\"undefined\"){module.exports=f()}else if(typeof define===\"function\"&&define.amd){define([],f)}else{var g;if(typeof window!==\"undefined\"){g=window}else if(typeof global!==\"undefined\"){g=global}else if(typeof self!==\"undefined\"){g=self}else{g=this}g.Bluefox = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require==\"function\"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error(\"Cannot find module '\"+o+\"'\");throw f.code=\"MODULE_NOT_FOUND\",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require==\"function\"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){\n'use strict';\nconst ExpressionChainable = require('./ExpressionChainable');\nconst Expression = require('./Expression');\nconst Execution = require('./Execution');\nconst DocumentObservers = require('./DocumentObservers');\nconst Timer = require('./Timer');\n\nclass Bluefox extends ExpressionChainable {\n static setTimerFunctions(setTimeout, clearTimeout) {\n Timer.setTimeout = setTimeout;\n Timer.clearTimeout = clearTimeout;\n }\n\n constructor() {\n super();\n this._expressionExecutor = this._expressionExecutor.bind(this);\n this._documentObservers = new DocumentObservers();\n this._nextExecutionId = 0;\n this.onExecuteBegin = null; // ({expression, executionId, resultPromise}) => undefined\n this.onExecuteEnd = null; // ({expression, executionId, resultPromise}) => undefined\n this.onCheckBegin = null; // ({expression, executionId, resultPromise}) => undefined\n this.onCheckEnd = null; // ({expression, executionId, resultPromise}) => undefined\n }\n\n createNextExpression(action, timeout = 30000) {\n return new Expression(null, action, timeout, this._expressionExecutor);\n }\n\n runAllChecks(document) {\n this._documentObservers.runAllChecks(document);\n }\n\n runAllChecksDeferred(document) {\n this._documentObservers.runAllChecksDeferred(document);\n }\n\n async _expressionExecutor(expression) {\n const execution = new Execution(expression, this._documentObservers, this._nextExecutionId++);\n const {onExecuteBegin, onExecuteEnd, onCheckBegin, onCheckEnd} = this;\n execution.onCheckBegin = onCheckBegin;\n execution.onCheckEnd = onCheckEnd;\n\n onExecuteBegin && onExecuteBegin({\n expression,\n executionId: execution.id,\n resultPromise: execution.executionPromise,\n });\n\n try {\n return await execution.execute();\n }\n finally {\n onExecuteEnd && onExecuteEnd({\n expression,\n executionId: execution.id,\n resultPromise: execution.executionPromise,\n });\n }\n }\n}\n\nmodule.exports = Bluefox;\n\n},{\"./DocumentObservers\":3,\"./Execution\":4,\"./Expression\":5,\"./ExpressionChainable\":6,\"./Timer\":7}],2:[function(require,module,exports){\n'use strict';\n\nconst {getDOMDocumentWindow, isDOMWindow, isDOMDocument, addEventListener, removeEventListener} = require('./dom');\nconst Timer = require('./Timer');\n\nclass DocumentObserver {\n constructor(document) {\n if (!isDOMDocument(document)) {\n throw Error('new DocumentObserver(document): Invalid argument `document`');\n }\n\n const window = getDOMDocumentWindow(document);\n if (!isDOMWindow(window)) {\n throw Error('new DocumentObserver(document): The given `document` must have a browsing context (a window)');\n }\n\n this.document = document;\n this.window = window;\n\n this._handleChange = this._handleChange.bind(this);\n this._handleChangeDeferred = this._handleChangeDeferred.bind(this);\n this._handleDeferrals = this._handleDeferrals.bind(this);\n\n // state:\n this._pendingExecutions = new Set();\n this._registeredListeners = false;\n this._mutationObserver = null;\n this._hasDeferredChange = false;\n this._removeListenersTimer = new Timer(0, () => this.removeListeners());\n\n // some checks are deferred, for two reasons:\n // 1. avoid running the checks too often\n // 2. wait for the other JS to complete whatever it is working on, in most cases this is the \"moment\" that we would like to measure\n this._deferralsTimer = new Timer(0, this._handleDeferrals);\n }\n\n get hasPendingExecutions() {\n return this._pendingExecutions.size > 0;\n }\n\n get hasRegisteredListeners() {\n return this._registeredListeners;\n }\n\n register(execution) {\n this._pendingExecutions.add(execution);\n this.registerListeners();\n }\n\n unregister(execution) {\n this._pendingExecutions.delete(execution);\n\n if (!this.hasPendingExecutions) {\n // defer the actual removal of the events, this avoids continuous the adding and removing of the event handlers in case\n // multiple wait expressions are run after one another, e.g.:\n // await bluefox.target(window).selector('foo'); await bluefox.target(window).selector('bar');\n this._removeListenersTimer.reschedule();\n }\n }\n\n registerListeners() {\n this._removeListenersTimer.cancel();\n\n if (this.hasRegisteredListeners) {\n return;\n }\n\n this._registeredListeners = true;\n const {window, document} = this;\n addEventListener(window, 'DOMContentLoaded', this._handleChange, true);\n addEventListener(window, 'load', this._handleChange, true);\n addEventListener(document, 'load', this._handleChangeDeferred, true); // e.g. <img>, <script src='\"> load\n\n // 'error' fired at the `window` represents a JavaScript runtime error\n // 'error' events that bubble up to the `document` are resource error, such an <img> that fails to load\n addEventListener(document, 'error', this._handleChangeDeferred, true); // e.g. <img/> fails to load\n\n this._mutationObserver = new this.window.MutationObserver(this._handleChangeDeferred);\n this._mutationObserver.observe(document, {\n attributeOldValue: false,\n attributes: true,\n characterData: true,\n characterDataOldValue: false,\n childList: true,\n subtree: true,\n });\n }\n\n removeListeners() {\n if (!this.hasRegisteredListeners) {\n return;\n }\n\n const {window, document} = this;\n this._removeListenersTimer.cancel();\n removeEventListener(window, 'DOMContentLoaded', this._handleChange, true);\n removeEventListener(window, 'load', this._handleChange, true);\n removeEventListener(document, 'load', this._handleChangeDeferred, true);\n removeEventListener(document, 'error', this._handleChangeDeferred, true);\n this._mutationObserver.disconnect();\n this._mutationObserver = null;\n this._deferralsTimer.cancel();\n this._registeredListeners = false;\n }\n\n runChecks() {\n this._hasDeferredChange = false;\n this._deferralsTimer.cancel();\n\n for (const execution of this._pendingExecutions) {\n execution.check();\n }\n }\n\n runChecksDeferred() {\n this._hasDeferredChange = true;\n this._deferralsTimer.schedule();\n }\n\n drainDeferrals() {\n this._handleDeferrals();\n }\n\n _handleChange() {\n this.runChecks();\n }\n\n _handleChangeDeferred() {\n this._hasDeferredChange = true;\n this._deferralsTimer.schedule();\n }\n\n _handleDeferrals() {\n if (this._hasDeferredChange) {\n this._hasDeferredChange = false;\n this.runChecks();\n }\n }\n}\n\nmodule.exports = DocumentObserver;\n\n},{\"./Timer\":7,\"./dom\":9}],3:[function(require,module,exports){\n'use strict';\nconst DocumentObserver = require('./DocumentObserver');\n\nclass DocumentObservers {\n constructor() {\n // HTMLDocument -> DocumentObserver (a Window object is not used as the key\n // because the reference is reused between navigation, see WindowProxy in spec)\n this._documentToObserver = new WeakMap();\n }\n\n _getOrCreate(document) {\n let documentObserver = this._documentToObserver.get(document);\n if (!documentObserver) {\n documentObserver = new DocumentObserver(document);\n this._documentToObserver.set(document, documentObserver);\n }\n return documentObserver;\n }\n\n registerExecution(document, execution) {\n const documentObserver = this._getOrCreate(document);\n documentObserver.register(execution);\n }\n\n unregisterExecution(document, execution) {\n const documentObserver = this._documentToObserver.get(document);\n if (documentObserver) {\n documentObserver.unregister(execution);\n }\n }\n\n runAllChecks(document) {\n const documentObserver = this._documentToObserver.get(document);\n if (documentObserver) {\n documentObserver.runChecks();\n }\n }\n\n runAllChecksDeferred(document) {\n const documentObserver = this._documentToObserver.get(document);\n if (documentObserver) {\n documentObserver.runChecksDeferred();\n }\n }\n\n drainDeferrals(document) {\n const documentObserver = this._documentToObserver.get(document);\n if (documentObserver) {\n documentObserver.drainDeferrals();\n }\n }\n}\n\nmodule.exports = DocumentObservers;\n\n},{\"./DocumentObserver\":2}],4:[function(require,module,exports){\n'use strict';\nconst {ResultWrapper, RESULT_STATUS_SUCCESS, RESULT_STATUS_PENDING} = require('./result');\nconst Timer = require('./Timer');\n\nclass Execution {\n constructor(expression, documentObservers, id) {\n this.expression = expression;\n this.expressionChain = expression.getExpressionChain();\n this.documentObservers = documentObservers;\n this.id = id;\n this.onCheckBegin = null;\n this.onCheckEnd = null;\n this.executionPromise = new Promise((resolve, reject) => {\n this.executionResolve = resolve;\n this.executionReject = reject;\n });\n this.executionStart = null;\n this.didFirstCheck = false;\n this.fulfilled = false;\n this.registeredDocuments = new Set();\n this.additionalCheckTimers = new Map();\n this._handleAdditionalCheckTimer = this._handleAdditionalCheckTimer.bind(this);\n this.createTimer = (timeout, handler) => new Timer(timeout, handler);\n this.now = () => Date.now();\n }\n\n async execute() {\n if (!this.didFirstCheck) {\n // immediately trigger the very first check, this also ensures that all\n // event handlers are added to the appropriate DOMWindow(s), which then\n // triggers any further check\n this.firstCheck();\n }\n return this.executionPromise;\n }\n\n firstCheck() {\n if (this.didFirstCheck) {\n throw Error('Invalid state');\n }\n\n this.didFirstCheck = true;\n this.executionStart = this.now();\n\n for (const expression of this.expressionChain) {\n const {additionalCheckTimeout} = expression.configuration;\n for (const timeout of additionalCheckTimeout) {\n if (!this.additionalCheckTimers.has(timeout)) {\n const timer = this.createTimer(timeout, this._handleAdditionalCheckTimer);\n timer.schedule();\n this.additionalCheckTimers.set(timeout, timer);\n }\n }\n }\n\n this.check();\n }\n\n check() {\n if (!this.didFirstCheck) {\n throw Error('Execution#check(): This execution has not been started');\n }\n\n if (this.fulfilled) {\n throw Error('Execution#check(): This execution has already been fulfilled');\n }\n\n const {onCheckBegin, onCheckEnd} = this;\n\n onCheckBegin && onCheckBegin({\n expression: this.expression,\n executionId: this.id,\n resultPromise: this.executionPromise,\n });\n\n const {executionStart} = this;\n const checkStart = this.now();\n const currentDuration = checkStart - executionStart;\n const result = new ResultWrapper();\n const documents = new Set();\n let pendingExpression = false;\n\n for (const expression of this.expressionChain) {\n const metaData = Object.freeze({\n executionStart,\n checkStart,\n });\n const resultStatus = result.runAction(expression.configuration.action, metaData);\n\n if (resultStatus === RESULT_STATUS_PENDING) {\n pendingExpression = expression;\n }\n\n if (resultStatus !== RESULT_STATUS_SUCCESS) {\n break;\n }\n\n result.addDOMDocumentsToSet(documents);\n }\n\n if (pendingExpression) {\n const {timeout} = pendingExpression.configuration;\n\n if (currentDuration >= timeout) {\n this.fulfilled = true;\n this.cleanup();\n this.executionReject(this.timeoutError(timeout, result, pendingExpression));\n }\n else {\n // expression was not fulfilled, listen for some events to trigger a recheck\n this.updateDocumentRegistrations(documents);\n }\n }\n else {\n this.fulfill(result);\n }\n\n onCheckEnd && onCheckEnd({\n expression: this.expression,\n executionId: this.id,\n resultPromise: this.executionPromise,\n });\n }\n\n timeoutError(timeout, result, pendingExpression) {\n const actionFailure = result.failureString();\n const message = `Wait expression timed out after ${timeout / 1000} seconds because ${actionFailure}. ` +\n pendingExpression.describe();\n const error = new Error(message);\n error.timeout = timeout;\n error.actionFailure = actionFailure;\n error.expression = pendingExpression;\n error.fullExpression = this.expression;\n return error;\n }\n\n updateDocumentRegistrations(documents) {\n for (const document of this.registeredDocuments) {\n if (!documents.has(document)) {\n this.documentObservers.unregisterExecution(document, this);\n }\n }\n for (const document of documents) {\n // (it is okay to call this method too many times)\n this.documentObservers.registerExecution(document, this);\n }\n this.registeredDocuments = documents;\n }\n\n cleanup() {\n for (const window of this.registeredDocuments) {\n this.documentObservers.unregisterExecution(window, this);\n }\n this.registeredDocuments.clear();\n\n for (const timer of this.additionalCheckTimers.values()) {\n timer.cancel();\n }\n this.additionalCheckTimers.clear();\n }\n\n fulfill(result) {\n this.fulfilled = true;\n this.cleanup();\n\n if (result.lastResultStatus === RESULT_STATUS_SUCCESS) {\n this.executionResolve(result.value);\n }\n else {\n const error = result.errorObject\n ? result.errorObject\n : Error(result.failureString());\n this.executionReject(error);\n }\n }\n\n _handleAdditionalCheckTimer() {\n this.check();\n }\n}\n\nmodule.exports = Execution;\n\n},{\"./Timer\":7,\"./result\":10}],5:[function(require,module,exports){\n'use strict';\nconst ExpressionChainable = require('./ExpressionChainable');\nconst {DEFAULT_AMOUNT_ACTION} = require('./actions');\n\n/* istanbul ignore if */\nif (!DEFAULT_AMOUNT_ACTION.appliesAmountCheck) {\n // infinite recursion would occur in this case\n throw Error('Assertion Error');\n}\n\nclass Expression extends ExpressionChainable {\n constructor(previous, action, timeout, executor) {\n super();\n\n if (previous !== null && !(previous instanceof Expression)) {\n throw Error('Invalid argument `previous`');\n }\n\n if (Boolean(previous) === Boolean(executor)) {\n throw Error('`executor` must (only) be set for the root Expression');\n }\n\n if (!action ||\n typeof action !== 'object' ||\n typeof action.execute !== 'function' ||\n typeof action.describe !== 'function') {\n throw Error('Invalid argument `action`');\n }\n\n if (typeof timeout !== 'number') {\n throw Error('Invalid argument `timeout`');\n }\n\n const prevConfig = previous && previous.configuration;\n const prevWantsDefaultAmountCheck = prevConfig && prevConfig.wantsDefaultAmountCheck;\n const wantsDefaultAmountCheck =\n (prevWantsDefaultAmountCheck || action.wantsDefaultAmountCheck) &&\n !action.appliesAmountCheck;\n\n // store our own data under a single property to avoid a messy user facing API\n Object.defineProperty(this, 'configuration', {\n value: {\n previous,\n depth: prevConfig ? prevConfig.depth + 1 : 0,\n action,\n timeout,\n additionalCheckTimeout: Object.freeze([timeout, ...action.additionalCheckTimeout]),\n _executor: prevConfig ? prevConfig._executor : executor,\n wantsDefaultAmountCheck,\n _defaultAmountExpression: null,\n },\n });\n\n this.configuration._defaultAmountExpression = wantsDefaultAmountCheck\n ? new Expression(this, DEFAULT_AMOUNT_ACTION, timeout)\n : null;\n\n Object.freeze(this.configuration);\n Object.freeze(this);\n }\n\n getExpressionChain() {\n const {_defaultAmountExpression} = this.configuration;\n if (_defaultAmountExpression) {\n return _defaultAmountExpression.getExpressionChain();\n }\n\n const expressionCount = this.configuration.depth + 1;\n const result = new Array(expressionCount);\n let currentExpression = this;\n for (let i = expressionCount - 1; i >= 0; --i) {\n result[i] = currentExpression;\n const {previous} = currentExpression.configuration;\n currentExpression = previous;\n }\n\n /* istanbul ignore if */\n if (currentExpression) {\n throw Error('Assertion Error');\n }\n\n return result;\n }\n\n createNextExpression(action, timeout = this.configuration.timeout) {\n return new Expression(this, action, timeout);\n }\n\n describe() {\n const descriptions = [];\n\n for (const expression of this.getExpressionChain()) {\n const {configuration} = expression;\n const description = configuration.action.describe(configuration.timeout);\n if (description) {\n descriptions.push(description);\n }\n }\n\n return `The expression ${descriptions.join(', ')}.`;\n }\n\n async execute() {\n return await this.configuration._executor(this);\n }\n\n then(...args) {\n // Note the intentional difference between:\n // expression = wait.selector('foo')\n // await expression;\n // await expression; // execute again!\n // and:\n // promise = wait.selector('foo').execute()\n // await expression;\n // await expression;\n return this.execute().then(...args);\n }\n\n catch(...args) {\n return this.execute().catch(...args);\n }\n\n finally(handler) {\n return this.then(\n value => Promise.resolve(handler()).then(() => value),\n error => Promise.resolve(handler()).then(() => Promise.reject(error))\n );\n }\n}\n\nmodule.exports = Expression;\n\n},{\"./ExpressionChainable\":6,\"./actions\":8}],6:[function(require,module,exports){\n'use strict';\nconst actions = require('./actions');\n\n/** @constructor */\nclass ExpressionChainable {\n /**\n * @param {actions.Action} action\n * @param {number} [timeout=previous.timeout]\n * @return {ExpressionChainable}\n * @method createNextExpression\n * @memberof ExpressionChainable.prototype\n */\n\n /**\n * @param {actions.Action} action\n * @return {ExpressionChainable}\n */\n action(action) {\n return this.createNextExpression(action);\n }\n\n /**\n * @param {Window|Node|Array|Function} targets\n * @return {ExpressionChainable}\n */\n target(targets) {\n return this.createNextExpression(new actions.Target(targets));\n }\n\n /**\n * @param {number|string} timeout string in the format of \"10s\" to specify seconds or a number to specify milliseconds\n * @return {ExpressionChainable}\n */\n timeout(timeout) {\n const timeoutMs = actions.parseTimeoutArgument(timeout);\n return this.createNextExpression(new actions.Noop(), timeoutMs);\n }\n\n /**\n * @param {number} minimum\n * @param {number} maximum\n * @return {ExpressionChainable}\n */\n amount(minimum, maximum) {\n return this.createNextExpression(new actions.Amount(minimum, maximum));\n }\n\n /**\n * @param {string|Function} expression\n * @return {ExpressionChainable}\n */\n selector(expression) {\n return this.createNextExpression(new actions.Selector(expression));\n }\n\n /**\n * @param {string|Function} expression\n * @return {ExpressionChainable}\n */\n selectorAll(expression) {\n return this.createNextExpression(new actions.SelectorAll(expression));\n }\n\n /**\n * @param {string|Function} expression\n * @return {ExpressionChainable}\n */\n xpath(expression) {\n return this.createNextExpression(new actions.XPath(expression));\n }\n\n /**\n * @param {string|Function} expression\n * @return {ExpressionChainable}\n */\n xpathAll(expression) {\n return this.createNextExpression(new actions.XPathAll(expression));\n }\n\n /**\n * @return {ExpressionChainable}\n */\n documentInteractive() {\n return this.createNextExpression(new actions.DocumentInteractive());\n }\n\n /**\n * @return {ExpressionChainable}\n */\n documentComplete() {\n return this.createNextExpression(new actions.DocumentComplete());\n }\n\n /**\n * @param {number|string} timeout string in the format of \"10s\" to specify seconds or a number to specify milliseconds\n * @return {ExpressionChainable}\n */\n delay(timeout) {\n return this.createNextExpression(new actions.Delay(timeout));\n }\n\n /**\n * @return {ExpressionChainable}\n */\n isDisplayed() {\n return this.createNextExpression(new actions.IsDisplayed());\n }\n\n /**\n * @param {function} callback\n * @return {ExpressionChainable}\n */\n check(callback) {\n return this.createNextExpression(new actions.Check(callback));\n }\n}\n\nmodule.exports = ExpressionChainable;\n\n},{\"./actions\":8}],7:[function(require,module,exports){\n'use strict';\n\nclass Timer {\n constructor(delay, callback) {\n this._id = 0;\n this.delay = delay;\n this.callback = callback;\n this.setTimeout = Timer.setTimeout;\n this.clearTimeout = Timer.clearTimeout;\n this._timerCallback = () => {\n this._id = 0;\n this.callback.call(null);\n };\n }\n\n get isScheduled() {\n return Boolean(this._id);\n }\n\n schedule() {\n if (!this._id) {\n this._id = this.setTimeout(this._timerCallback, this.delay);\n }\n }\n\n cancel() {\n if (this.isScheduled) {\n this.clearTimeout(this._id);\n this._id = 0;\n }\n }\n\n reschedule() {\n this.cancel();\n this.schedule();\n }\n}\n\n/* istanbul ignore next */\nTimer.setTimeout = (func, delay) => setTimeout(func, delay);\n/* istanbul ignore next */\nTimer.clearTimeout = (id) => clearTimeout(id);\n\nmodule.exports = Timer;\n\n},{}],8:[function(require,module,exports){\n'use strict';\nconst {\n isResultItem,\n isDOMNode,\n describeDOMObject,\n cssSelectorFirst,\n cssSelectorArray,\n xpathFirst,\n xpathArray,\n resultItemToDocument,\n documentReadyState,\n hasFormattingBox,\n} = require('./dom');\nconst {resultToArray, resultCount, executeSuccess, executePendingTag, executeFatalFailureTag} = require('./result');\n\nconst freezeCopyIfArray = value => {\n if (Array.isArray(value)) {\n return Object.freeze(value.slice());\n }\n return value;\n};\nconst funcOrValue = value => (typeof value === 'function' ? value() : value);\nconst LEFT_QUOTE = '\\u201c';\nconst RIGHT_QUOTE = '\\u201d';\nconst HORIZONTAL_ELLIPSIS = '\\u2026';\nconst EMPTY_FROZEN_ARRAY = Object.freeze([]);\nconst CALLBACK_DESCRIPTION_MAX_LENGTH = 64;\n\nexports.parseTimeoutArgument = timeout => {\n if (typeof timeout === 'string' && /^([\\d.]+)s$/.test(timeout)) {\n return parseFloat(timeout) * 1000;\n }\n\n if (typeof timeout === 'number') {\n return timeout;\n }\n\n throw Error('Invalid timeout argument, expected a number or a duration string');\n};\n\nexports.describeCallback = func => {\n const funcString = func.toString();\n if (funcString.length <= CALLBACK_DESCRIPTION_MAX_LENGTH) {\n return funcString;\n }\n\n return funcString.slice(0, CALLBACK_DESCRIPTION_MAX_LENGTH - 1) + HORIZONTAL_ELLIPSIS;\n};\n\nclass Action {\n /**\n * @param {?Window|Node|Array.<(Window|Node)>} currentResult\n * @param {Object} metaData\n * @return {{status: string, reasonStrings: string[], reasonValues: string[], value: (?Window|Node|Array.<(Window|Node)>)}}\n */\n execute(currentResult, metaData) {\n return executeSuccess(currentResult);\n }\n\n /**\n * @param {number} timeout milliseconds\n * @return {string}\n */\n describe(timeout) {\n return '';\n }\n\n /**\n * If true, this action should trigger a default amount check. Unless the user provides an amount check\n * For example if this value is true for \"myAction\": `.myAction()` would have the same effect as `.myAction().amount(1, Infinity)`\n * @return {boolean}\n */\n get wantsDefaultAmountCheck() {\n return false;\n }\n\n /**\n * If true, this action perform an an amount check and the default amount check should not be applied.\n * @return {boolean}\n */\n get appliesAmountCheck() {\n return false;\n }\n\n /**\n * Schedule an additional check after this many milliseconds have passed since the start of the expression\n * @return {number[]}\n */\n get additionalCheckTimeout() {\n return EMPTY_FROZEN_ARRAY;\n }\n}\n\nclass Noop extends Action {\n constructor() {\n super();\n Object.freeze(this);\n }\n\n execute(currentResult) {\n return executeSuccess(currentResult);\n }\n\n describe() {\n return '';\n }\n}\n\nclass Target extends Action {\n /**\n * @param {?Window|Node|Array.<(Window|Node)>|Function} targets\n */\n constructor(targets) {\n super();\n this.results = freezeCopyIfArray(targets);\n Object.freeze(this);\n }\n\n execute(currentResult) {\n const results = freezeCopyIfArray(funcOrValue(this.results));\n\n for (const result of resultToArray(results)) {\n if (!isResultItem(result)) {\n return executeFatalFailureTag`a value that is not a WindowProxy nor a HTMLDocument, nor an Element was set as the target`;\n }\n }\n\n return executeSuccess(results);\n }\n\n describe() {\n const results = this.results;\n // (some DOM nodes are typeof function)\n if (typeof results === 'function' && !isDOMNode(results)) {\n return `sets the target using a callback: \\`${exports.describeCallback(results)}\\``;\n }\n\n if (Array.isArray(results)) {\n const descriptions = [];\n\n for (const result of results) {\n if (descriptions.length >= 5) {\n descriptions.push('\\u2026');\n break;\n }\n\n descriptions.push(describeDOMObject(result));\n }\n\n return `sets the target to [${descriptions.join(', ')}]`;\n }\n\n return `sets the target to ${describeDOMObject(results)}`;\n }\n}\n\nclass Amount extends Action {\n constructor(minimum, maximum = minimum) {\n super();\n this.minimum = minimum;\n this.maximum = maximum;\n\n if (typeof this.minimum !== 'number') {\n throw Error('.amount(minimum, maximum): minimum must be a number');\n }\n\n if (typeof this.maximum !== 'number') {\n throw Error('.amount(minimum, maximum): maximum must be a number');\n }\n\n if (this.minimum > this.maximum) {\n throw Error('.amount(minimum, maximum): maximum must be greater than or equal to minimum');\n }\n\n Object.freeze(this);\n }\n\n execute(currentResult) {\n const count = resultCount(currentResult);\n\n if (count < this.minimum) {\n if (count === 0) {\n return executePendingTag`no results were found, instead of a minimum of ${this.minimum} results`;\n }\n\n return executePendingTag`only ${count} results were found, instead of a minimum of ${this.minimum} results`;\n }\n\n if (count > this.maximum) {\n return executePendingTag`${count} results were found, instead of a maximum of ${this.maximum} results`;\n }\n\n return executeSuccess(currentResult);\n }\n\n describe(timeout) {\n const prefix = `waits up to ${timeout / 1000} seconds until`;\n\n if (this.minimum === this.maximum) {\n return `${prefix} exactly ${this.minimum} results are found`;\n }\n\n if (this.minimum === 1 && this.maximum === Infinity) {\n return `${prefix} a result is found`;\n }\n\n if (this.maximum === Infinity) {\n return `${prefix} ${this.minimum} or more results are found`;\n }\n\n return `${prefix} between ${this.minimum} and ${this.maximum} (inclusive) results are found`;\n }\n\n get appliesAmountCheck() {\n return true;\n }\n}\n\nclass Selector extends Action {\n constructor(expression) {\n super();\n this.expression = expression;\n Object.freeze(this);\n }\n\n execute(currentResult) {\n const expression = funcOrValue(this.expression);\n\n for (const resultItem of resultToArray(currentResult)) {\n const result = cssSelectorFirst(resultItem, expression);\n\n if (result) {\n return executeSuccess(result);\n }\n }\n\n return executeSuccess(null);\n }\n\n describe() {\n if (typeof this.expression === 'function') {\n return `finds the first descendant element matching a CSS selector from ` +\n `a callback: \\`${exports.describeCallback(this.expression)}\\``;\n }\n\n return `finds the first descendant element matching the CSS selector ${LEFT_QUOTE}${this.expression}${RIGHT_QUOTE}`;\n }\n\n get wantsDefaultAmountCheck() {\n return true;\n }\n}\n\nclass SelectorAll extends Action {\n constructor(expression) {\n super();\n this.expression = expression;\n Object.freeze(this);\n }\n\n execute(currentResult) {\n const expression = funcOrValue(this.expression);\n const elementListList = [];\n\n for (const resultItem of resultToArray(currentResult)) {\n const elementList = cssSelectorArray(resultItem, expression);\n elementListList.push(elementList);\n }\n\n const value = [].concat(...elementListList);\n Object.freeze(value);\n return executeSuccess(value);\n }\n\n describe() {\n if (typeof this.expression === 'function') {\n return `finds all descendant elements matching a CSS selector from a callback: ` +\n `\\`${exports.describeCallback(this.expression)}\\``;\n }\n\n return `finds all descendant elements matching the CSS selector ${LEFT_QUOTE}${this.expression}${RIGHT_QUOTE}`;\n }\n\n get wantsDefaultAmountCheck() {\n return true;\n }\n}\n\nclass XPath extends Action {\n constructor(expression) {\n super();\n this.expression = expression;\n Object.freeze(this);\n }\n\n execute(currentResult) {\n const expression = funcOrValue(this.expression);\n\n for (const resultItem of resultToArray(currentResult)) {\n const result = xpathFirst(resultItem, expression);\n\n if (result && !isResultItem(result)) {\n return executeFatalFailureTag`a value that is not an Element was returned by the XPath expression`;\n }\n\n if (result) {\n return executeSuccess(result);\n }\n }\n\n return executeSuccess(null);\n }\n\n describe() {\n if (typeof this.expression === 'function') {\n return `finds the first element matching a XPath expression from a callback: ` +\n `\\`${exports.describeCallback(this.expression)}\\``;\n }\n\n return `finds the first element matching the XPath expression ${LEFT_QUOTE}${this.expression}${RIGHT_QUOTE}`;\n }\n\n get wantsDefaultAmountCheck() {\n return true;\n }\n}\n\nclass XPathAll extends Action {\n constructor(expression) {\n super();\n this.expression = expression;\n Object.freeze(this);\n }\n\n execute(currentResult) {\n const expression = funcOrValue(this.expression);\n const elementListList = [];\n\n for (const resultItem of resultToArray(currentResult)) {\n const elementList = xpathArray(resultItem, expression);\n elementListList.push(elementList);\n }\n\n const value = [].concat(...elementListList);\n Object.freeze(value);\n\n for (const resultItem of value) {\n if (!isResultItem(resultItem)) {\n return executeFatalFailureTag`a value that is not an Element was returned by the XPath expression`;\n }\n }\n\n return executeSuccess(value);\n }\n\n describe() {\n if (typeof this.expression === 'function') {\n return `finds all elements matching a XPath expression from a callback: ` +\n `\\`${exports.describeCallback(this.expression)}\\``;\n }\n\n return `finds all elements matching the XPath expression ${LEFT_QUOTE}${this.expression}${RIGHT_QUOTE}`;\n }\n\n get wantsDefaultAmountCheck() {\n return true;\n }\n}\n\nclass DocumentInteractive extends Action {\n constructor() {\n super();\n Object.freeze(this);\n }\n\n execute(currentResult) {\n for (const resultItem of resultToArray(currentResult)) {\n const document = resultItemToDocument(resultItem);\n\n if (documentReadyState(document) === 'loading') {\n return executePendingTag`the HTML document has not yet been parsed`;\n }\n }\n\n return executeSuccess(currentResult);\n }\n\n describe(timeout) {\n return `waits up to ${timeout / 1000} seconds until the HTML document has finished parsing`;\n }\n}\n\nclass DocumentComplete extends Action {\n constructor() {\n super();\n Object.freeze(this);\n }\n\n execute(currentResult) {\n for (const resultItem of resultToArray(currentResult)) {\n const document = resultItemToDocument(resultItem);\n\n const readyState = documentReadyState(document);\n if (readyState === 'loading') {\n return executePendingTag`the HTML document has not yet been parsed`;\n }\n\n if (readyState === 'interactive') {\n return executePendingTag`the HTML document has not yet been loaded`;\n }\n }\n\n return executeSuccess(currentResult);\n }\n\n describe(timeout) {\n return `waits up to ${timeout / 1000} seconds until all synchronous resources of the HTML document have been loaded`;\n }\n}\n\nclass Delay extends Action {\n constructor(timeout) {\n super();\n this.delayMs = exports.parseTimeoutArgument(timeout);\n Object.freeze(this);\n }\n\n execute(currentResult, {executionStart, checkStart}) {\n const {delayMs} = this;\n const timeSinceStart = checkStart - executionStart;\n if (timeSinceStart < delayMs) {\n // eslint-disable-next-line max-len\n return executePendingTag`the delay of ${delayMs / 1000} seconds has not yet elapsed, only ${timeSinceStart / 1000} seconds have elapsed so far`;\n }\n\n return executeSuccess(currentResult);\n }\n\n describe() {\n return `waits until ${this.delayMs / 1000} seconds have elapsed since the start of the execution`;\n }\n\n get additionalCheckTimeout() {\n return Object.freeze([this.delayMs]);\n }\n}\n\n\nclass IsDisplayed extends Action {\n constructor() {\n super();\n Object.freeze(this);\n }\n\n execute(currentResult) {\n if (!currentResult) {\n return executeSuccess(currentResult);\n }\n\n if (Array.isArray(currentResult)) {\n const result = currentResult.filter(object => hasFormattingBox(object));\n return executeSuccess(Object.freeze(result));\n }\n\n const result = hasFormattingBox(currentResult) ? currentResult : null;\n return executeSuccess(result);\n }\n\n describe() {\n return `but only including elements which are displayed on the page`;\n }\n}\n\nclass Check extends Action {\n constructor(callback) {\n if (typeof callback !== 'function') {\n throw Error('.check(callback): callback must be a function');\n }\n\n super();\n this.callback = callback;\n Object.freeze(this);\n }\n\n execute(currentResult) {\n if (!currentResult) {\n return executeSuccess(currentResult);\n }\n\n if (Array.isArray(currentResult)) {\n const result = currentResult.filter(object => this.callback(object));\n return executeSuccess(Object.freeze(result));\n }\n\n const result = this.callback(currentResult) ? currentResult : null;\n return executeSuccess(result);\n }\n\n describe() {\n return `but only including results that match a callback: \\`${exports.describeCallback(this.callback)}\\``;\n }\n}\n\nconst DEFAULT_AMOUNT_ACTION = new Amount(1, Infinity);\n\nexports.Action = Action;\nexports.Noop = Noop;\nexports.Target = Target;\nexports.Amount = Amount;\nexports.DEFAULT_AMOUNT_ACTION = DEFAULT_AMOUNT_ACTION;\nexports.Selector = Selector;\nexports.SelectorAll = SelectorAll;\nexports.XPath = XPath;\nexports.XPathAll = XPathAll;\nexports.DocumentInteractive = DocumentInteractive;\nexports.DocumentComplete = DocumentComplete;\nexports.Delay = Delay;\nexports.IsDisplayed = IsDisplayed;\nexports.Check = Check;\n\n},{\"./dom\":9,\"./result\":10}],9:[function(require,module,exports){\n'use strict';\n\nconst ELEMENT_NODE = 1;\nconst XPATHRESULT_ORDERED_NODE_SNAPSHOT_TYPE = 7;\nconst XPATHRESULT_FIRST_ORDERED_NODE_TYPE = 9;\n\nconst dom = exports;\nconst getStringTag = object => Object.prototype.toString.call(object);\n\ndom.findPropertyInChain = (object, name) => {\n let proto = Object.getPrototypeOf(object);\n while (proto) {\n const descriptor = Object.getOwnPropertyDescriptor(proto, name);\n if (descriptor) {\n return descriptor;\n }\n proto = Object.getPrototypeOf(proto);\n }\n return null;\n};\n\n/**\n * @param {*} object\n * @return {Boolean}\n */\ndom.isDOMWindow = object => Boolean(\n object &&\n object.window === object &&\n object.self === object &&\n dom.isDOMDocument(object.document)\n);\n\n/**\n * @param {*} object\n * @return {Boolean} (window is not a Node)\n */\ndom.isDOMNode = object => Boolean(\n object &&\n (typeof object === 'object' || typeof object === 'function') && // some nodes are typeof function\n 'nodeType' in object &&\n 'nodeName' in object &&\n 'ownerDocument' in object &&\n 'parentNode' in object\n);\n\n/**\n * @param {*} object\n * @return {Boolean}\n */\ndom.isDOMDocument = object => Boolean(\n dom.isDOMNode(object) &&\n 'defaultView' in object &&\n (getStringTag(object) === '[object HTMLDocument]' || getStringTag(object) === '[object Document]')\n);\n\n/**\n * @param {*} object\n * @return {Boolean}\n */\ndom.isDOMElement = object => Boolean(\n dom.isDOMNode(object) &&\n (object.nodeType === ELEMENT_NODE || getStringTag(object) === '[object HTMLFormElement]') &&\n 'tagName' in object\n);\n\n/**\n * @param {HTMLDocument} document\n * @return {?Window}\n */\ndom.getDOMDocumentWindow = document => {\n const defaultView = dom.findPropertyInChain(document, 'defaultView');\n return defaultView.get.call(document);\n};\n\n/**\n * Is the given argument a valid result item as input/output to a wait `Expression`\n * @param {*} object\n * @return {boolean}\n */\ndom.isResultItem = object => Boolean(\n dom.isDOMWindow(object) ||\n dom.isDOMDocument(object) ||\n dom.isDOMElement(object)\n);\n\n/**\n * @param {Window|Node} object\n * @return {Window}\n */\ndom.resultItemToWindow = object => {\n if (dom.isDOMWindow(object)) {\n return object;\n }\n\n if (dom.isDOMDocument(object)) {\n return dom.getDOMDocumentWindow(object); // (might be null)\n }\n\n if (dom.isDOMNode(object)) {\n const ownerDocument = dom.findPropertyInChain(object, 'ownerDocument');\n return dom.getDOMDocumentWindow(ownerDocument.get.call(object));\n }\n\n throw Error('dom.resultItemToWindow(): Invalid argument');\n};\n\n/**\n * @param {Window|Node} object\n * @return {Document}\n */\ndom.resultItemToDocument = object => {\n if (dom.isDOMWindow(object)) {\n return object.document;\n }\n\n if (dom.isDOMDocument(object)) {\n return object;\n }\n\n if (dom.isDOMNode(object)) {\n const ownerDocument = dom.findPropertyInChain(object, 'ownerDocument');\n return ownerDocument.get.call(object);\n }\n\n throw Error('dom.resultItemToDocument(): Invalid argument');\n};\n\n/**\n * @param {Window|Node} object\n * @return {?HTMLHtmlElement}\n */\ndom.resultItemToDocumentElement = object => {\n const document = dom.resultItemToDocument(object);\n return dom.findPropertyInChain(document, 'documentElement').get.call(document);\n};\n\n/**\n * Find the closest object that implements the `ParentElement` interface, for the given result item\n * @param {Window|Node} object\n * @return {ParentElement} (A Document or an Element)\n */\ndom.resultItemToParentNode = object => {\n if (dom.isDOMWindow(object)) {\n return object.document;\n }\n\n if (dom.isDOMDocument(object)) {\n return object;\n }\n\n if (dom.isDOMElement(object)) {\n return object;\n }\n\n throw Error('dom.resultItemToParentNode(): Invalid argument');\n};\n\n/**\n * Find the closest object that implements the `Element` interface, for the given result item\n * @param {Window|Node} object\n * @return {Element}\n */\ndom.resultItemToElement = object => {\n if (dom.isDOMWindow(object) || dom.isDOMDocument(object)) {\n return dom.resultItemToDocumentElement(object);\n }\n\n if (dom.isDOMElement(object)) {\n return object;\n }\n\n throw Error('dom.resultItemToElement(): Invalid argument');\n};\n\n/**\n * @param {Window|Node} object\n * @return {string}\n */\ndom.describeDOMObject = object => {\n if (object === undefined) {\n return '<#undefined>';\n }\n\n if (object === null) {\n return '<#null>';\n }\n\n if (dom.isDOMWindow(object)) {\n return '<#window>';\n }\n\n if (dom.isDOMDocument(object)) {\n return '<#document>';\n }\n\n if (getStringTag(object) === '[object HTMLFormElement]') {\n return '<form>';\n }\n\n if (dom.isDOMNode(object)) {\n return `<${object.nodeName.toLowerCase()}>`;\n }\n\n return '<???>';\n};\n\n/**\n * @param {Window|Node} resultItem\n * @param {string} expression\n * @return {?Element}\n */\ndom.cssSelectorFirst = (resultItem, expression) => {\n const context = dom.resultItemToParentNode(resultItem);\n const querySelector = dom.findPropertyInChain(context, 'querySelector').value;\n return querySelector.call(context, expression);\n};\n\n/**\n * @param {Window|Node} resultItem\n * @param {string} expression\n * @return {Element[]}\n */\ndom.cssSelectorArray = (resultItem, expression) => {\n const context = dom.resultItemToParentNode(resultItem);\n const querySelectorAll = dom.findPropertyInChain(context, 'querySelectorAll').value;\n return Array.from(querySelectorAll.call(context, expression));\n};\n\n/**\n * @param {Window|Node} resultItem\n * @param {string} expression\n * @return {?Element}\n */\ndom.xpathFirst = (resultItem, expression) => {\n const document = dom.resultItemToDocument(resultItem);\n const context = dom.resultItemToParentNode(resultItem);\n const evaluate = dom.findPropertyInChain(document, 'evaluate').value;\n const xpathResult = evaluate.call(document, expression, context, null, XPATHRESULT_FIRST_ORDERED_NODE_TYPE, null);\n return xpathResult.singleNodeValue;\n};\n\n/**\n * @param {Window|Node} resultItem\n * @param {string} expression\n * @return {Element[]}\n */\ndom.xpathArray = (resultItem, expression) => {\n const document = dom.resultItemToDocument(resultItem);\n const context = dom.resultItemToParentNode(resultItem);\n const evaluate = dom.findPropertyInChain(document, 'evaluate').value;\n const xpathResult = evaluate.call(document, expression, context, null, XPATHRESULT_ORDERED_NODE_SNAPSHOT_TYPE, null);\n\n const array = new Array(xpathResult.snapshotLength);\n for (let i = 0; i < array.length; ++i) {\n array[i] = xpathResult.snapshotItem(i);\n }\n\n return array;\n};\n\n/**\n * @param {HTMLDocument} document\n * @return {string} \"loading\" or \"interactive\" or \"complete\"\n */\ndom.documentReadyState = document => {\n const readyState = dom.findPropertyInChain(document, 'readyState');\n return readyState.get.call(document);\n};\n\ndom.addEventListener = (object, ...args) => {\n if (dom.isDOMNode(object)) {\n const addEventListener = dom.findPropertyInChain(object, 'addEventListener');\n return addEventListener.value.apply(object, args);\n }\n\n // WindowProxy or something different\n return object.addEventListener(...args);\n};\n\ndom.removeEventListener = (object, ...args) => {\n if (dom.isDOMNode(object)) {\n const removeEventListener = dom.findPropertyInChain(object, 'removeEventListener');\n return removeEventListener.value.apply(object, args);\n }\n\n // WindowProxy or something different\n return object.removeEventListener(...args);\n};\n\n/**\n * @param {Element} element\n * @return {DOMRect}\n */\ndom.getBoundingClientRect = element => {\n const getBoundingClientRect = dom.findPropertyInChain(element, 'getBoundingClientRect');\n return getBoundingClientRect.value.call(element);\n};\n\n/**\n * @param {Window|Node} object\n * @return {boolean}\n */\ndom.hasFormattingBox = object => {\n const element = dom.resultItemToElement(object);\n const rect = dom.getBoundingClientRect(element);\n return rect.width > 0 && rect.height > 0;\n};\n\n},{}],10:[function(require,module,exports){\n'use strict';\nconst {resultItemToDocument} = require('./dom');\n\nconst RESULT_STATUS_SUCCESS = 'success';\nconst RESULT_STATUS_PENDING = 'pending';\nconst RESULT_STATUS_FATAL_FAILURE = 'fatal failure';\n\nexports.ResultWrapper = class ResultWrapper {\n constructor() {\n /** @type {?Node|Node[]} */\n this.value = null;\n /** @type {?string[]} */\n this.reasonStrings = null;\n /** @type {?Array} */\n this.reasonValues = null;\n /** @type {?Error} */\n this.errorObject = null;\n /** one of RESULT_STATUS_*\n * @type {?string}\n */\n this.lastResultStatus = null;\n }\n\n runAction(action, metaData) {\n try {\n const {status, value, reasonStrings, reasonValues} = action.execute(this.value, metaData);\n\n if (status !== RESULT_STATUS_SUCCESS && status !== RESULT_STATUS_PENDING && status !== RESULT_STATUS_FATAL_FAILURE) {\n throw Error('runAction: Invalid \"status\" value returned from action.execute()');\n }\n\n this.value = value;\n this.lastResultStatus = status;\n\n if (status === RESULT_STATUS_SUCCESS) {\n this.reasonStrings = null;\n this.reasonValues = null;\n this.errorObject = null;\n return this.lastResultStatus;\n }\n // status = pending / fatal failure\n\n this.reasonStrings = reasonStrings;\n this.reasonValues = reasonValues;\n return this.lastResultStatus;\n }\n catch (error) {\n this.value = null;\n this.reasonStrings = null;\n this.reasonValues = null;\n this.errorObject = error;\n this.lastResultStatus = RESULT_STATUS_FATAL_FAILURE;\n return this.lastResultStatus;\n }\n }\n\n addDOMDocumentsToSet(documents) {\n if (Array.isArray(this.value)) {\n for (const resultItem of this.value) {\n documents.add(resultItemToDocument(resultItem));\n }\n }\n else if (this.value) {\n documents.add(resultItemToDocument(this.value));\n }\n }\n\n failureString() {\n if (this.reasonStrings) {\n return exports.buildStringFromTagValues(this.reasonStrings, this.reasonValues);\n }\n\n if (this.errorObject) {\n return this.errorObject.toString();\n }\n\n return null;\n }\n};\n\nexports.resultToArray = object => {\n if (Array.isArray(object)) {\n return object;\n }\n if (object === undefined || object === null) {\n return [];\n }\n return [object];\n};\n\nexports.resultCount = result => {\n if (Array.isArray(result)) {\n return result.length;\n }\n\n if (result === undefined || result === null) {\n return 0;\n }\n\n return 1;\n};\n\nexports.buildStringFromTagValues = (strings, values) => {\n let result = strings[0];\n for (let i = 1; i < strings.length; ++i) {\n result += String(values[i - 1]);\n result += strings[i];\n }\n return result;\n};\n\n/**\n * @param {?Window|Node|Array.<(Window|Node)>} value\n * @return {{status: string, value: (?Window|Node|Array.<(Window|Node)>)}}\n */\nexports.executeSuccess = value => Object.freeze({\n status: RESULT_STATUS_SUCCESS,\n value,\n});\n\n/**\n * @param {string[]} strings\n * @param {...string} values\n * @return {{status: string, reasonStrings: string[], reasonValues: string[], value: null}}\n */\nexports.executePendingTag = (strings, ...values) => Object.freeze({\n status: RESULT_STATUS_PENDING,\n // the descriptive string is only computed if the error is actually displayed\n reasonStrings: Object.freeze(strings),\n reasonValues: Object.freeze(values),\n value: null,\n});\n\n/**\n * @param {string[]} strings\n * @param {...string} values\n * @return {{status: string, reasonStrings: string[], reasonValues: string[], value: null}}\n */\nexports.executeFatalFailureTag = (strings, ...values) => Object.freeze({\n status: RESULT_STATUS_FATAL_FAILURE,\n // the descriptive string is only computed if the error is actually displayed\n reasonStrings: Object.freeze(strings),\n reasonValues: Object.freeze(values),\n value: null,\n});\n\nexports.RESULT_STATUS_SUCCESS = RESULT_STATUS_SUCCESS;\nexports.RESULT_STATUS_PENDING = RESULT_STATUS_PENDING;\nexports.RESULT_STATUS_FATAL_FAILURE = RESULT_STATUS_FATAL_FAILURE;\n\n},{\"./dom\":9}]},{},[1])(1)\n});";
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc