Bluefox
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.
The functionality is similar to the wait functions found in many WebDriver/Selenium client libraries. Unlike most of those libraries, bluefox does not employ periodic polling. Also, instead of sending many commands over the network during the wait, the resolving of wait conditions in bluefox takes place entirely in the browser. This means that the moment the wait condition resolves is a lot closer to the actual change.
The overhead that this library introduces to the page being tested is kept as low as possible.
Examples
npm i bluefox
Webpack / Browserify / node.js (jsdom)
const Bluefox = ;const wait = targetwindow;wait;
HTML Document
Hi! <!-- <script src="node_modules/bluefox/standalone.min.js"></script> --> Hello
WebDriver
const bluefoxString = ;// const bluefoxString = require('bluefox/standalone.min.string.js');const wd = ;const browser = wd;async { await browser; await browser; await browser; await browser; await browser; const result = await browser; console;};
API
First, this library must by instantiated by calling its constructor:
const Bluefox = ;const wait = ;
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.
await waittargetdocument; // 30 second timeoutawait waittargetdocument; // 1 second timeoutawait waittargetdocument; // 1.5 second timeout
The error object contains the following properties:
const expression = await waittargetdocument;const fullExpression = expression;try await fullExpression;catch err console; // String("BluefoxTimeoutError") console; // String("Wait expression timed out after 1.2 seconds because the HTML document has not yet been parsed") console; // String("the HTML document has not yet been parsed") console; // Number(1200) - milliseconds console; // Boolean(true) console; // Boolean(true)
.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.
await waittargetwindowawait waittargetdocumentawait waittargetdocumentbodyawait waittargetsomeElement anotherElement
.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.
await waittargetwindow // 1 or moreawait waittargetwindow // 1 or moreawait waittargetwindow // exactly 1await waittargetwindow // exactly 0await waittargetwindow // 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
.
const link = await waittargetwindow;link; const anotherLink = await waittargetsomeElement anotherElement;anotherLink; const needsSomeEscaping = '#"b[l]a'await waittargetwindowselector`div[data-foo=]`;
.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
.
const links = await waittargetwindow;links; const needsSomeEscaping = '#"b[l]a'await waittargetwindowselectorAll`div[data-foo=]`;
.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.
await waittargetwindow;await waittargetdocumentbody;
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.
await waittargetwindow;await waittargetdocumentbody;
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 "interactive"
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.
window;await waittargetdocument;await waittargetdocumentbody;
.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.
window;await waittargetdocument;await waittargetdocumentbody;
.delay(duration)
This action causes the execution to remain pending until the given duration
has passed (since the start of the execution).
await wait; // 2000msawait wait; // 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
).
await waitawait wait;
.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
.
await waitawait wait
.containsText(text)
This action removes all elements from current value
for which the textContent
does not contain the given text
.
await waitawait waitawait wait;
.first()
This action returns the first element (index 0) from current value
const oneImage = await wait;const button = await wait