Security News
Bun 1.2 Released with 90% Node.js Compatibility and Built-in S3 Object Support
Bun 1.2 enhances its JavaScript runtime with 90% Node.js compatibility, built-in S3 and Postgres support, HTML Imports, and faster, cloud-first performance.
browser-monkey
Advanced tools
Reliable DOM testing
npm install browser-monkey
Browser Monkey is a DOM assertion library. It helps you write framework agnostic browser tests that are reliable in the face of asynchronous behaviours like animations, AJAX and delayed rendering. It also helps you to write tests that exhibit the semantic meaning of the page, as opposed to a jumble of CSS selectors.
describe('admin', function () {
// describes the admin panel, with a search box, results and a user editor
var adminPanel = browser.extend({
searchUsers: function () {
return this.find('.search');
},
userResult: function (name) {
// find a user in the results by their name
return this.find('.results .user', {text: name});
}
userEditor: function () {
// return the user editor, scoped to the .user-editor div.
return userEditor.scope(this.find('.user-editor'));
}
});
// describes the user editor, with inputs for name and email, and a save button.
var userEditor = browser.extend({
name: function () { this.find('.name'); },
email: function () { this.find('.email'); },
save: function () { this.find('.save'); },
});
it('can search for, edit and save a user', function () {
return adminPanel.searchUsers().typeIn('bar').then(function () {
return adminPanel.userResult('Barry').click();
}).then(function () {
var userEditor = adminPanel.userEditor();
return Promise.all([
userEditor.name().typeIn('Barry Jones'),
userEditor.email().typeIn('barryjones@example.com')
]).then(function () {
return userEditor.save().click();
});
}).then(function () {
// verify that the user was saved
// use mockjax-router!
});
});
});
The API is made up of three concepts: scopes, actions and assertions.
find(css)
and containing(css)
, that progressively narrow the scope of elements to be searched for. These queries return new scopes.click()
and typeIn(text)
wait for the scope to be found before simulating a UI event. These return promises that resolve when the event has been dispatched.shouldExist()
and shouldHave(properties)
can be made on scopes to ensure that they exist or contain text, classes or other properties.All scope chains are immutable, so you can reuse portions of a scope chain to build new chains:
var details = browser.find('.details'); // finds .details
var name = details.find('.name'); // finds .details .name
var email = details.find('.email'); // finds .details .email
...
The API starts with the browser scope, which contains everything on the page.
You can also create DSLs for components on the page using scope.extend(methods)
. By extending a scope, you can add methods that represent elements of the component at a higher level than mere CSS selectors. It's probably worth noting that these methods should normally just return scopes and not perform actions or assertions.
var innerScope = scope.find(css, [options]);
Returns a new scope that matches css
.
css
- css to find in the scopeoptions.text
- text to find in the scope.var scope = scope.is(css);
Returns a new scope that ensures that the element found matches the CSS. For example, scope.find('li').is('.enabled')
ensures that the <li>
has the class enabled
.
css
- css to match against the scopevar scope = scope.containing(css, [options]);
Ensures that the scope contains the css
and options.text
, the scope returned still refers to the outer scope. This is useful, for example, in finding list items that contain certain elements, but still referring to the list items.
css
- css to find in the scopeoptions.text
- text to find in the scope.For example, find the li
that contains the h2
with the text Second
, and click the link in the li
.
<ul>
<li>
<h2>First</h2>
<a href="first">link</a>
</li>
<li>
<h2>Second</h2>
<a href="second">link</a>
</li>
<li>
<h2>Third</h2>
<a href="third">link</a>
</li>
</ul>
browser.find('ul li').containing('h2', {text: 'Second'}).find('a').click();
Represents a component on the page, with methods to access certain elements of the component.
var componentScope = scope.component(methods);
methods
- an object containing functions for scopes of elements inside the component.componentScope
- a scope, but containing additional access methodsYou can create a component from another component too, simply extending the functionality in that component.
For example, you may have an area on the page that deals with instant messages. You have a list of messages, a text box to enter a new message, and a button to send the message.
var messages = browser.component({
messages: function () {
return this.find('.messages');
},
messageText: function () {
return this.find('input.message');
},
sendButton: function () {
return this.find('button', {text: 'Send'});
}
});
You can then use the messages component:
messages.messages().shouldHave({text: ['hi!', 'wassup?']}).then(function () {
return messages.messageBox().typeIn("just hangin'");
}).then(function () {
return messages.sendButton().click();
});
You can reset the starting point for the scope, the element from which all elements are searched for. By default this is the <body>
element, but you can set it to a more specific element, or indeed another scope.
var scopeUnderElement = scope.scope(element | selector | anotherScope);
element
- an element. This can be an <iframe>
element, in which case the scope will be the contents of the iframe.
selector
- a CSS selector string
anotherScope
a scope to define where to start this scope. This is useful if you want to set the starting scope of a comonent. E.g.
var component = browser.component({
... methods ...
});
var componentScope = component.scope(browser.find('.component'));
Wait for an element to exist.
var promise = scope.shouldExist([options]);
options.timeout
- length of time to wait for the element (1000ms)options.interval
- time between testing the dom (10ms)options.allowMultiple
- allow multiple elements to be found, default just oneReturns a promise that resolves when the element exists, or is rejected if the timeout expires.
Waits for the element not to exist.
var promise = scope.shouldNotExist([options]);
options.timeout
- length of time to wait for the element (1000ms)options.interval
- time between testing the dom (10ms)Returns a promise that resolves when the element no longer exists, or is rejected if the timeout expires.
Assert that a scope has certain properties.
var promise = scope.shouldHave([options]);
options.text
- a string, expects the resolved scope to have the text. If an array of strings, expects the elements to have the same number of elements as there are strings in the array, and expects each string to be found in each respective element's text.options.css
- a CSS string. Expects the resolved element to be matched by the CSS selector. Note that it won't match if the element contains other elements that match the CSS selector. So if we have {css: '.class'}
then we expect the resolved element to have a class class
.options.value
- a string, expects the resolved element to be an input and have the value. An array expects the same number of inputs, each with the respective value.options.html
- a string, expects the resolved element to have the html. An array expects the same number of elements, each with the respective html.options.length
- a number, expects there to be this number of elementsoptions.elements
- a function, which is passed the resolved elements, return truthy for a match, falsey for a failure.options.message
- the error messageoptions.timeout
- length of time to wait for the element (1000ms)options.interval
- time between testing the dom (10ms)Returns a promise that resolves once the element has been found and the click has been triggered
scope.click().then(function () {
});
Returns a promise that resolves once the element has been found and the matching item selected from the select box
scope.select({text: 'Text of option'}).then(function () {
});
Example:
<select class="my-select">
<option>First</option>
<option>Second</option>
</select>
var scope = browser.extend({
mySelect: function(){
return this.find('.my-select');
}
})
scope.mySelect().select({text: 'Second'}).then(function(){
});
Returns a promise resolving to the list of elements matched by the scope.
scope.elements([options]).then(function (elements) {
});
elements
- the HTML DOM elements matched by the scope.options.timeout
- length of time to wait for the element (1000ms)options.interval
- time between testing the dom (10ms)Returns a promise resolving to the single element matched by the scope, it will be rejected if there are multiple.
scope.element([options]).then(function (element) {
});
element
- the HTML DOM element matched by the scope.options.timeout
- length of time to wait for the element (1000ms)options.interval
- time between testing the dom (10ms)FAQs
reliable dom testing
The npm package browser-monkey receives a total of 278 weekly downloads. As such, browser-monkey popularity was classified as not popular.
We found that browser-monkey demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 2 open source maintainers 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
Bun 1.2 enhances its JavaScript runtime with 90% Node.js compatibility, built-in S3 and Postgres support, HTML Imports, and faster, cloud-first performance.
Security News
Biden's executive order pushes for AI-driven cybersecurity, software supply chain transparency, and stronger protections for federal and open source systems.
Security News
Fluent Assertions is facing backlash after dropping the Apache license for a commercial model, leaving users blindsided and questioning contributor rights.