dce-selenium
v1.0.59
Published
Selenium library to simplify testing and automatically snapshot the DOM.
Downloads
21
Readme
dce-selenium
Selenium library to simplify integration testing on multiple browsers.
Table of Contents
- Writing Tests
- Running Tests
- Snapshots
- Environment Config
- Setting up a New Project
- Driver Functions:
- Examples
Writing Tests
Create a
test/selenium
folder for your selenium testsImport
dce-selenium
at the top of each test:require('dce-selenium'); ...
Use standard Mocha testing practices, but use
describeS
anditS
instead ofdescribe
andit
:describeS('My App', function () { itS('Opens', async function (driver) { await driver.visit('https://www.website.com/'); ... }); });
To add a timeout to a test, call
itS
like this:itS(title, timeout, testFunction)
. Default timeout is 45s.describeS('My App', function () { // Test with 5s timeout: itS('Logs in', 5000, async function (driver) { await driver.visit('https://www.website.com/login'); ... }); });
To add code that runs before or after each test, add arguments to the
describe
handler:describeS('My App', function (beforeEachS, afterEachS) { beforeEachS(async function (driver) { // Code to run before each test }); afterEachS(async function (driver) { // Code to run after each test }); });
See "Driver Functions" below for a list of actions the driver can perform
Running Tests
To run your tests on all non-headless browsers (Chrome, Firefox, and Safari if on Mac), use:
npm run selenium
To run your tests on specific browser(s), use:
# run on chrome
npm run selenium --chrome
# run on firefox
npm run selenium --firefox
# run on safari
npm run selenium --safari
# run on safari technology preview
npm run selenium --safari-stp
# run on headless chrome
npm run selenium --headless-chrome
# run on chrome then safari
npm run selenium --chrome --safari
To run your tests with less printing to the terminal, use the --silent
parameter. Example:
npm run selenium --chrome --silent
Snapshots
When you run your tests, a test/snapshots
folder will be created. Check it out!
Environment Config
Add config parameters to your test/selenium/config.json
file to customize how dce-selenium
works.
Name | Description | Default
:--- | :--- | :---
defaultHost | a default hostname to use when driver.visit
is passed a path, not a full url | none
dontUseHTTPS | if true, when driver.visit
is passed a path. not a full url, we will visit the host using HTTP instead of HTTPS | false
noSnapshots | if true, no snapshots are taken | false
Setting up a New Project
To add dce-selenium to your NPM project, use our initializer:
npm init dce-selenium
Notes:
- Your npm project must already be initialized with
npm init
ornpm init caccl
- This initializer automatically installs dependencies, creates a
/test
folder, and adds thenpm run selenium
script topackage.json
Driver Functions
This is the list of built-in functions the driver can perform. Every function is asynchronous, so you must use the await
command to wait for it to complete.
To call any driver function, just call driver.functionName
(driver
is a global variable):
await driver.visit('https://www.my-website.com');
await driver.click('#login-button');
await driver.typeInto('#username-field', 'divardo');
await driver.typeInto('#password-field', '142509');
Custom functions: to create your own functions, see the info at the end of this section.
Logging
log(object) - print to the log
Arguments:
object
- a string or any object to print to the terminal
Note: use this function instead of console.log
for better log formatting.
Example:
// Print the status driver.log(`The current status is ${status}`);
Navigation
visit(location, [locationToWaitFor]) – visit a webpage and wait for it to load
Arguments:
location
– either full url or just path. If location is a path,defaultHost
anddontUseHTTPS
are used to determine the host and protocol for the url.locationToWaitFor
– optional: the location or list of locations to wait for before resolving. If the location we're visiting redirects the user elsewhere, we need to wait for that location instead. Put that final location as this locationToWaitFor. If there are more than one possible final locations, include an array. Defaults to same value aslocation
.
Example:
// Visit the /about page await driver.visit('/about');
Example with redirect:
// Visit the /contact page which redirects to /email await driver.visit('/contact', '/email');
Example with nondeterministic redirect:
// Visit the /contact page which redirects to /email or /phone await driver.visit('/contact', ['/email', '/phone']);
post(location, body, [finalLocation]) – visit a webpage and wait for it to load
Arguments:
location
– either full url or just path. If location is a path,defaultHost
anddontUseHTTPS
are used to determine the host and protocol for the url.body
– the POST request body to send.locationToWaitFor
– optional: the location or list of locations to wait for before resolving. If the location we're visiting redirects the user elsewhere, we need to wait for that location instead. Put that final location as this locationToWaitFor. If there are more than one possible final locations, include an array. Defaults to same value aslocation
.
Example:
// Send a POST request to the login page await driver.post('/login', { user: 'admin', password: 'Pa$$w0rD', });
Interactions
click(cssSelectorOrElem) – click an item on the page
Arguments:
cssSelectorOrElem
– the css selector or the WebElement that identifies the item to click
Example:
// Click the support button await driver.click('#support-button');
openAnchorInSameTab(cssSelectorOrElem, [locationToWaitFor]) - open an anchor tab in the current tab even if it was made to open in another tab
Arguments:
cssSelectorOrElem
– the css selector or the WebElement that identifies the anchor taglocationToWaitFor
– optional: the location or list of locations to wait for before resolving. If the location we're visiting redirects the user elsewhere, we need to wait for that location instead. Put that final location as this locationToWaitFor. If there are more than one possible final locations, include an array. Defaults to same value aslocation
.
Example:
// Click the contact button but force it to open in the same tab await driver.openAnchorInSameTab('#contact-button');
Example where button leads to /contact which redirects to /email:
// Click the contact button but force it to open in the same tab await driver.openAnchorInSameTab('#contact-button', '/email');
Example where button leads to /contact which either redirects to /email or /phone:
// Click the contact button but force it to open in the same tab await driver.openAnchorInSameTab('#contact-button', ['/email', '/phone']);
clickByContents(contents, [cssSelector]) – click an item (find using its contents)
Find an item containing contents
in its body and click it.
Arguments:
contents
– the text contents of the item to click (may be a substring)cssSelector
– the css selector that further limits the items in question
Example:
// The log in button doesn't have any identifying characteristics // other than its text, so click it by contents await driver.clickByContents('Log In');
typeInto(cssSelectorOrElem, text) – type in an html element
Arguments:
cssSelectorOrElem
– the css selector or the WebElement that identifies the item to type intotext
– the text to type
Example:
// Log in await driver.typeInto('#username', 'admin'); await driver.typeInto('#password', 'Pa$$w0rD'); await driver.clickByContents('Log In');
Note: to type a backspace, use the driver.BACKSPACE
character.
Example:
// Type query await driver.typeInto('#search', 'dogs'); // Remove the "s" await driver.typeInto('#search', driver.BACKSPACE);
simulateKeystrokesIntoDocument(text, [finishWithEnter]) – simulate keystroke into the page document
Arguments:
text
– the text to typefinishWithEnter
– if true, the enter key is pressed after the text is typed
Example:
// Simulate typing onto page itself then press enter await driver.simulateKeystrokesIntoDocument('test', true);
scrollTo(cssSelectorOrElem) – scroll to an element
Arguments:
cssSelectorOrElem
– the css selector or the WebElement that identifies the item to scroll to
Example:
// Scroll down to the footer await driver.scrollTo('#footer');
chooseSelectItem(cssSelectorOrElem, item) – select an item from a select-based dropdown based on its human-visible text
Arguments:
cssSelectorOrElem
– the css selector or the WebElement that identifies the select item to interact withitem
– the human-readable text of the option to choose
Example:
// Choose 'MasterCard Debit' await driver.chooseSelectValue('#card-types', 'MasterCard Debit');
chooseSelectValue(cssSelectorOrElem, value) – select an item from a select-based dropdown based on the item's value attribute
Arguments:
cssSelectorOrElem
– the css selector or the WebElement that identifies the select item to interact withvalue
– the value attribute of the option to select
Example:
// Choose 'MasterCard Debit' by its select value ('mc-debit') await driver.chooseSelectValue('#card-types', 'mc-debit');
chooseFile(cssSelectorOrElem, filePath) – choose a file for a file input field
Arguments:
cssSelectorOrElem
– the css selector or the WebElement that identifies the file chooser elementfilePath
– the path of the file with respect to the project directory (the directory from which you started the selenium tests)
Example:
const path = require('path'); ... // Upload new profile image await driver.chooseFile('#file-upload', '/test/resources/images/profile.png'); await driver.click('#upload');
Data
getTitle() – gets the title of the page
Returns the title of the current page.
Example:
// Make sure the title of the page is "Divardo's Profile" assert.equal(await driver.getTitle(), 'Divard\'s Profile', 'Page title is wrong');
getSource() – gets the source of the page
Returns the source of the current page.
Example:
// Make sure the source of the page includes a jQuery import const body = await driver.getSource(); assert(body.includes('src="https://code.jquery.com'), 'No jQuery embed');
getJSON() – gets the JSON of the page
Returns the JSON object of the current page (only valid if the current url points to a JSON object).
Example:
// Visit the server's user profile endpoint that sends a json response await driver.visit('/api/user/profile'); const profile = await driver.getJSON(); // Log the user's name driver.log(`The current user's name is: ${profile.name}`);
getBody() - gets the html body of the page
Return the html body of the page.
Example:
// Make sure the body of the page includes at least 3 "@" characters const body = await driver.getBody(); const numAtSymbols = (body.split('@').length - 1); assert(numAtSymbols >= 3, `Not enough "@" symbols: only found ${numAtSymbols}.`);
getURL() - gets the url of the page
Return the url of the page.
Example:
// Check that the url ends with '/about' const url = await driver.getURL(); assert(url.endsWith('/about'), 'URL does not end with /about');
getQuery() - gets the query parameters of the page
Return the query parameters of the page in the form { name: value }
.
Example:
// Get the 'email' and 'name' query parameter const queryParams = await driver.getQuery(); const { name, email } = queryParams;
Elements
elementExists(cssSelector) - checks if an element exists
Returns true if the element exists.
Arguments:
cssSelector
– the css selector identifying the item
Example:
// Make sure there is a search box assert(await driver.elementExists('#search-box'), 'No search box');
elementAbsent(cssSelector) - checks if an element does not exist
Returns true if the element does not exist.
Arguments:
cssSelector
– the css selector identifying the item
Example:
// Make sure there is no warning messgae assert(await driver.elementAbsent('#warning-message'), 'Warning message found');
elementWithContentsExists(contents, [cssSelector]) – check if an element with specific contents exists
Return true if the element exists.
Arguments:
contents
– the text contents of the element we're looking forcssSelector
– the css selector that further limits the search
Example:
// Click the submit button if it's there // The submit button has no identifying characteristics other than // its contents, so we need to identify using contents const submitVisible = await driver.elementWithContentsExists('Submit'); if (submitVisible) { await driver.clickByContents('Submit'); }
elementWithContentsAbsent(contents, [cssSelector]) – check if an element with specific contents does not exist
Returns true if the element does not exist.
Arguments:
contents
– the text contents of the element we're looking forcssSelector
– the css selector that further limits the search
Example:
// Expand the description if it isn't already visible const needToExpand = elementWithContentsAbsent('This is part of the body of the description'); if (needToExpand) { await driver.click('#expand-description'); }
getElement(cssSelector) - find an element by css selector
Arguments:
cssSelector
- the css selector
Example:
// Get a table with the id "cities" const searchButtonElement = await driver.getElement('table#cities');
getElements(cssSelector) - find all elements that match a css selector
Arguments:
cssSelector
- the css selector
Example:
// Make sure there are 3 images on the page const images = await driver.getElements('img'); assert.equal( images.length, 3, 'The wrong number of images were found in the page' );
getElementByContents(contents, [cssSelector]) – find an element by its contents
Arguments:
contents
– the text contents of the element we're looking forcssSelector
– the css selector that further limits the search
Example:
// The search button doesn't have any identifying characteristics, // so let's find it by its contents const searchButtonElement = await driver.getElementByContents('Search');
parentOf(cssSelectorOrElem) – given a selector or an element, finds the parent of the element
Arguments:
cssSelectorOrElem
– the css selector or the WebElement that identifies the child element
Example:
// Each user's profile has a picture and name inside it: // |"""""""| |"""""""| |"""""""| |"""""""| |"""""""| // | \O/ | | \O/ | | \O/ | | \O/ | | \O/ | // | Sarah | | Jenny | | David | | Caleb | | Alexi | // """"""" """"""" """"""" """"""" """"""" // To click Sarah's profile, find her name, // get the parent (the profile) and click it const nameElement = await driver.getElementByContents('Sarah'); const profileElement = await driver.parentOf(nameElement); await driver.click(profileElement);
descendantOf(element, cssSelector) - given an element and a cssSelector, finds the first descendant of the element that matches the css selector
Arguments:
element
- the parent elementcssSelector
- the css selector that identifies the desired descendant
Example:
// Find a button within a specific div const elem = await driver.getElement('div#main'); const button = await driver.descendantOf(elem, 'button');
listSelectItems(cssSelectorOrElem) - lists the human-readable text for the items in a select-based dropdown
Arguments:
cssSelectorOrElem
– the css selector or the WebElement that identifies the select element
Example:
// List the human-readable options for supported credit card types const cards = await listSelectItems('#card-types'); > ['MasterCard Credit', 'MasterCard Debit', 'Visa', 'Discover']
listSelectValues(cssSelectorOrElem) - lists the values for the items in a select-based dropdown
Arguments:
cssSelectorOrElem
– the css selector or the WebElement that identifies the select element
Example:
// Find the types of supported credit cards const cards = await listSelectValues('#card-types'); > ['mc-credit', 'mc-debit', 'visa', 'discover']
getElementInnerHTML(cssSelectorOrElement) - gets the innerHTML of an element
Arguments:
cssSelectorOrElem
– the css selector or the WebElement that identifies the item to get contents of
Example:
// Get the body of the message on the page const html = await getElementInnerHTML('#message');
getEmbeddedMetadata() - Searches the page for a #embedded-metadata element and parses the stringified json content inside it
Example:
// Get the current embedded metadata const metadata = await driver.getEmbeddedMetadata();
Session
reset() – reset the browser session
Example:
// Reset the user's session await driver.reset();
Waiting
pause() – wait for the user to press enter in the terminal
Example:
// Wait until user hits enter await driver.pause();
wait(ms) – wait for a specific number of milliseconds
Arguments:
ms
– number of milliseconds to wait
Example:
// Wait 2 seconds await driver.wait(2000);
waitForElementVisible(cssSelector, timeout) – wait for an element to be visible
Arguments:
cssSelector
– the css selector of the element to wait for[timeout=10000]
– number of ms to wait before timing out
Example:
// Wait for the title bar to be visible await driver.waitForElementVisible('#title-bar');
waitForElementWithContentsVisible([see below]) – wait for an element with contents to be visible
Either use separated arguments:
contents
– the text contents to search for[cssSelector]
– an optional css selector to further limit the search[timeout=10000]
– the timeout of the wait in ms
Example:
await waitForElementWithContentsVisible('About Me', 'h3');
...or use a single-argument options object:
options.contents
– the text contents to search for[options.cssSelector]
– an optional css selector to further limit the search[options.timeout=10000]
– the timeout of the wait in ms
Example:
await waitForElementWithContentsVisible({ contents: 'About Me', timeout: 7000, });
waitForLocation(location) – wait for a location to load
Note: location waiting happens automatically after visit(...)
. There is no need to call this function right after calling visit(...)
.
Arguments:
location
– either full url or just path. If location is a path,defaultHost
anddontUseHTTPS
are used to determine the host and protocol for the url. The query part of the path is not included in the match. If you want to check the query, usegetQuery()
(see above)
waitForLocations(locations) – wait for any location in a list to load
Note: location waiting happens automatically after visit(...)
. There is no need to call this function right after calling visit(...)
.
Arguments:
locations
– either an array of or a single url/path to wait for. If a location is a path,defaultHost
anddontUseHTTPS
are used to determine the host and protocol for the url. The query part of the path is not included in the match. If you want to check the query, usegetQuery()
(see above)
Custom Functions
To create your own functions, add a file test/selenium/commands.js
and export your custom commands:
module.exports = {
async visitGoogle() {
await this.visit('https://www.google.com');
},
async searchYoutube(query) {
await this.visit(`https://www.youtube.com/results?search_query=${query}`);
},
};
The context of the function is the driver. Thus, this.visit
calls driver.visit
. To directly access the Selenium webdriver, use this.webdriver
.
Examples
Visit google and type into the search box
require('dce-selenium');
const assert = require('assert');
describeS('Google', function () {
itS('Displays Search Results', async function (driver) {
// Load Google
await driver.visit('https://www.google.com');
// Type a query
await driver.typeInto('.gLFyf', 'Puppy');
// Click the "Search" button
await driver.clickByContents('Google Search', 'input');
// Wait for results to be visible
await driver.waitForElementVisible('#resultStats');
// Check for the usual top result
const wikiExists = await driver.elementWithContentsExists('Puppy - Wikipedia');
assert(wikiExists, 'Could not find expected result: Wikipedia');
});
});