Security News
The Push to Ban Ransom Payments Is Gaining Momentum
Ransomware costs victims an estimated $30 billion per year and has gotten so out of control that global support for banning payments is gaining momentum.
bluefox
Advanced tools
Readme
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.
npm i bluefox
// browserify / webpack / jsdom
const Bluefox = require('bluefox');
const wait = new Bluefox().target(window);
wait.timeout('5s').selector('section#main > div.contactInformation > a.viewProfile').then(link => {
link.click();
}).catch(err => {
console.error('uh o', err);
});
<!DOCTYPE html>
<html>
<head>
<title>Hi!</title>
<script src="node_modules/bluefox/standalone.js"></script>
<!-- <script src="node_modules/bluefox/standalone.min.js"></script> -->
<script>
(async () => {
console.log(new Date(), 'Waiting...');
const wait = new Bluefox().target(window);
const element = await wait.timeout('5s').selector('#foo > strong');
element.textContent = 'wereld!!';
console.log(new Date(), 'Done!');
})();
</script>
</head>
<body>
<div id="foo">
Hello
</div>
<script>
setTimeout(() => {
foo.insertAdjacentHTML(
'beforeend',
'<strong>world</strong>'
)
}, 1000);
</script>
</body>
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);
})();
First, this library must by instantiated by calling its constructor:
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
WindowProxy
instanceHTMLDocument
instanceElement
instanceWindowProxy
, HTMLDocument
, Element
instancesFor 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.
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 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
The target action is used to simply set the current value
. It is almost always used as the first action in the chain.
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')
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 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
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 wait.target(window).selector('a.someLink');
link.click();
const anotherLink = await wait.target([someElement, anotherElement]).selector('a.someLink');
anotherLink.click();
const needsSomeEscaping = '#"b[l]a'
await wait.target(window).selector`div[data-foo=${needsSomeEscaping}]`;
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 wait.target(window).selectorAll('.todoList a');
links.forEach(link => link.click());
const needsSomeEscaping = '#"b[l]a'
await wait.target(window).selectorAll`div[data-foo=${needsSomeEscaping}]`;
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 wait.target(window).xpath(`.//h1[./@id = 'introduction']`);
await wait.target(document.body).xpath(`./p`);
Note: XPath expressions often cause more overhead than CSS Selectors.
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 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.
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.
window.addEventListener('DOMContentLoaded',
() => console.log('documentInteractive!')
);
await wait.target(document).documentInteractive();
await wait.target(document.body).documentInteractive();
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.addEventListener('load',
() => console.log('documentComplete!')
);
await wait.target(document).documentComplete();
await wait.target(document.body).documentComplete();
This action causes the execution to remain pending until the given duration
has passed (since the start of the execution).
await wait.delay('2s'); // 2000ms
await wait.delay(2000); // 2000ms
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 wait.selector('.submitButton').isDisplayed()
await wait.selectorAll('.gallery img').isDisplayed().amount(10, 50);
This action calls the given callback
function for each item in current value
and removes all items for which the callback returns false
.
await wait.selector('p.introduction').check(n => /hello/.test(n.textContent))
await wait.selector('img').check(n => img.complete).amount(10, Infinity)
This action removes all elements from current value
for which the textContent
does not contain the given text
.
await wait.selector('p.introduction').containsText('hello')
await wait.selector('p.introduction').containsText(/hello/)
await wait.selectorAll('p').containsText('ipsum').amount(10, 50);
FAQs
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.
We found that bluefox demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Ransomware costs victims an estimated $30 billion per year and has gotten so out of control that global support for banning payments is gaining momentum.
Application Security
New SEC disclosure rules aim to enforce timely cyber incident reporting, but fear of job loss and inadequate resources lead to significant underreporting.
Security News
The Python Software Foundation has secured a 5-year sponsorship from Fastly that supports PSF's activities and events, most notably the security and reliability of the Python Package Index (PyPI).