wendigo
v3.0.2
Published
A proper monster for front-end automated testing
Downloads
304
Maintainers
Readme
Wendigo
A proper monster for front-end automated testing.
Wendigo (/wɛndɪɡo/) simplify your front-end and end-to-end automated testing using Puppeteer. Install it with npm install --save-dev wendigo
.
WARNING: This documentation refers to Wendigo 2, if you are using previous versions of Wendigo, go here.
Consider the following example using just Puppeteer:
await page.click(".my-btn");
await page.waitForSelector("#my-modal")
const modalText = await page.evaluate(() => {
const modalElement = document.querySelector("#my-modal");
return modalElement.textContent;
})
assert.strictEqual(modalText, "Button Clicked");
The same test can be written like this with Wendigo:
await browser.click(".my-btn");
await browser.waitFor("#my-modal");
await browser.assert.text("#my-modal", "Button Clicked");
Features
- Assertion library built-in.
- Cookies, LocalStorage and WebWorkers handling.
- Requests mocker.
- Plugins!
- Full access to Puppeteer methods.
- Easy and flexible query system with support for CSS selectors and XPath.
- Docker and CI friendly.
- Easy to setup, just node required.
- Authorization helpers.
Contents
Getting Started
Requirements
To start using Wendigo for testing or browser automation. Make sure you've got NodeJS 8.16.0 or higher and npm installed in your system. You can check if they are installed and their versions with the following commands:
node -v
npm -v
Installing Wendigo
You should install Wendigo in your npm project (usually as a dev dependency):
npm install --save-dev wendigo
Usage
You can use it with your favorite test suite or standalone in a JavaScript file
const Wendigo = require('wendigo');
async function getMyPageHeader() {
const browser = await Wendigo.createBrowser();
await browser.open("http://my-page");
const text = await browser.text("h1");
await browser.close();
return text;
}
getMyPageHeader().then((text)=>{
console.log(text);
});
Queries With Wendigo
Most methods in Wendigo will receive a selector parameter to query for DOM elements on which execute actions or get data. Unless specified these queries can be performed by passing a CSS selector (e.g. div
, .container
), an xPath selector (//*[text()='my text']
) or passing a DOM Element.
For example:
const myElement = await browser.query(".div");
await browser.text(".div"); // My Element Text
await browser.text(myElement); // My Element Text
Using Wendigo With TypesScript
Wendigo 2.0 and higher contains typings, so importing it in a TyeScript project is enough for types support:
import * as Wendigo from 'wendigo';
If you find any problem, please check our Troubleshooting for solutions, or fill an issue if it appears to be a bug or lacking feature with Wendigo. More information and guides on how to use Wendigo available at the wiki
Using Puppeteer directly
Wendigo is intended to be used as a full wrapper of Puppeteer, so usually accessing Puppeteer directly is not needed, however, the browser class provide direct access to Puppeteer classes:
- browser.page
- browser.context
- browser.coreBrowser
Check the API for those properties for more info.
Api
Wendigo Class
Wendigo is the only class exported by the package. It provides the methods necessary to create browsers and disconnect from chrome, can be imported with require('wendigo')
:
createBrowser(settings)
Will create and return a promise to a Browser instance. It will automatically launch and connect Puppeteer and Chrome.
- settings: an optional object with the configuration for the browser
log: false
: If true, it will log all the console events of the browser.logRequests: false
: If true, all requests made by the browser will be logged in the console.incognito: false
: If true, the browser will open as an incognito browser.userAgent
: If defined, the default user agent will be overridden.noSandbox
: Sets the option--no-sandbox
when opening Puppeteer. This option will also be set if the env variableNO_SANDBOX
is set (check troubleshooting).timezone
: Sets the browser's timezone (e.g.UTC
,Asia/Tokyo
).bypassCSP: true
: If set to false, puppeteer may fail if Content Security Policy is set in the page.proxyServer: null
: If defined, Chromium will run with the option--proxy-server
set to the given address.defaultTimeout: 500
: Sets the default timeout for "wait" methods, exceptbrowser.wait()
.cache: true
: If true, requests cache will be enabled.- Any settings that can be passed to Puppeteer can be passed to createBrowser, for example:
headless: true
: If true, the browser will run on headless mode.slowMo: 0
: Slows the execution of commands by given number of milliseconds
Examples:
const browser = await Wendigo.createBrowser(); // Using default options
const browser = await Wendigo.createBrowser({
headless: false,
slowMo: 500
}); // Using options to see what's happening
stop()
Will stop and disconnect all the browsers. It should be called after finishing all the tests.
registerPlugin(name, plugin?, assertions?)
Registers a new plugin, for more information, check Plugins. This must be called before createBrowser
for the plugins to work.
Optionally an object can be passed with the following options:
name
plugin
assertions
clearPlugins()
Removes all plugins from Wendigo. This will affect all newly created browsers.
Browser
The Browser instance is and interface with the page
class of Puppeteer.
Attributes
page
Puppeteer page class, allows access to Puppeteer API if needed.
await browser.page.evaluate(() => {
document.querySelector("h1");
});
loaded
True if the page has already opened and loaded.
incognito
True if the browser is configured as incognito page.
cache
If the requests cache is active.
context
Returns Puppeteer's BrowserContext.
coreBrowser Returns Puppeteers's Browser class for direct requests.
Methods
All the methods in Browser return a Promise than can easily be handled by using async/await
.
open(url, options?)
Opens the given url in the browser.
await browser.open("http://localhost:8000");
The following options can be passed:
viewport
: Viewport config to set when opening the browser, uses the same syntax assetViewport
.queryString
: Querystring to be appended to the url, can be a string or object. Avoid using this parameter if a query string is already present in the url.geolocation
: Options to override geoLocation. Same as usingsetGeolocation
.headers
: Sets extra HTTP headers before opening the page.Same as usingrequests.setHeaders
.dismissAllDialogs
: This will automatically dismiss any native dialog (alert
,prompt
) when appearing.
If no protocol is defined (e.g. https://
), http://
will be used.
openFile(path, options?)
Opens the given file. Same options as open
can be passed. The file will be passed by appending file://
to the absolute path.
await browser.open("static/index.html");
close()
Close the browser, it should be called after finishing using the browser instance. Avoid creating a new browser before closing the previous one if possible. Having multiple open browsers will cause performance degradation in your tests.
await browser.close();
evaluate(cb, ...args)
Evaluates given callback in the browser, passing n arguments. Returns the Puppeteer's result of the evaluation.
const selector = "h1";
const elementText = await browser.evaluate((s) => {
return document.querySelector(s).textContent;
}, selector); // My Title
This method, unlike browser.page.evaluate
will automatically parse any argument if possible:
query(selector, childSelector?)
Queries the given selector (CSS, XPath or DomElement) and returns a DOMElement. If multiple elements match, only the first will be returned. Returns null if no element found.
const element = await browser.query("h1");
Optionally, 2 parameters can be passed. A query will be performed only on the nested elements of the first selector:
const element = await browser.query(".div");
const children = await browser.query(element, "p"); // First paragraph under element .div
Note that any result that is not an element node will be filtered for XPath requests.
queryAll(selector, childSelector?)
Returns an array with all the DOMElement matching the given selector.
const elements = await browser.queryAll("h1");
elements.length; // 2
Optionally, queryAll supports 2 parameters. The query will then be performed only on the elements under the first selector.
Note that any result that is not an element node will be filtered for XPath requests.
elementFromPoint(x, y)
Given the coordinates (in pixels) as two numbers, returns the topmost DomElement in that position or null
if no element is present.
const element = await browser.elementFromPoint(500, 150);
await browser.text(element); // ["My Title"]
selectPage(index)
Selects the given page (a.k.a. tab) to be used by Wendigo. Keep in mind that tabs are never changed automatically unless explicitly selected or closed with closePage
.
await browser.click(".btn.new-tab")
await browser.wait(100); // waits for new tab to be loaded
await browser.pages(); // length is 2
await browser.selectPage(1); // goes to newly opened tab
CSP bypass will not be enabled in the newly opened tabs. If you rely on it, it may be necessary to reload the tab after it has been opened with
browser.refresh
closePage(index)
Closes the page with given index, if the closed page is the current active page, it will change to the new page with index 0 (reloading it in the process). If no more pages exists, the browser will close with browser.close()
automatically.
pages()
Returns all Puppeteer's pages, one per tab or popup.
Warning: All pages related methods are still under revision, and its behavior may heavily change in future releases.
setContent(html)
Sets the page content from a string. Can be used instead of browser.open
.
await browser.setContent("<h1>Title</h1>");
addScript(scriptPath)
Executes the given script in the browser context. Useful to set helper methods and functions. This method must be called after the page is already loaded, if another page is loaded, the scripts won't be re-executed. If these scripts are required for a plugin to work, remember to execute this method on the _afterOpen
hook.
It is heavily recommended to only use this to load helper functions, and not execute anything that might cause side effects. Anything loaded as a script may interfere with the behavior of the page or Wendigo. It is recommended to always check if the object of function you are loading already exists before loading, remember that WendigoUtils
, WendigoQuery
and WendigoPathFinder
objects are required for Wendigo to work and overriding them will cause problems.
class(selector)
Returns and array with the classes of the first element found, throws if no element found.
const classes = await browser.class("div.container.main"); // Returns ["container", "main", "another-class"]
Using a DOMElement:
const node = await browser.query("div.container.main");
const classes = await browser.class(node); // Returns ["container", "main", "another-class"]
value(selector)
Returns the value of the first element with given selector. Throws if no element or value found.
const value = await browser.value("input.my-input");
attribute(selector, attributeName)
Return the attribute value of the first element found with given selector. Throws if no element is found. Returns ""
if the attribute is set but no value is given and null
if the attribute doesn't exists.
const classAttribute = await browser.attribute(".my-element", "class"); // Returns "my-element another-class"
const hiddentAttr = await browser.attribute(".my-hidden-element", "hidden"); // Returns ""
const hiddentAttr2 = await browser.attribute(".not-hidden-element", "hidden"); // Returns null
styles(selector)
Returns an object with all the computed css styles of the first element matching the given selector, throws if no element is found.
const styles = await browser.styles("h1.my-title");
styles.color; // 'rgb(255, 0, 0)'
style(selector, style)
Returns the value of the given style of the first element matching the given selector. Returns undefined if the style doesn't exists. Throws if no element found.
const style = await browser.style("h1.my-title", color); // 'rgb(255, 0, 0)'
checked(selector)
Returns true if the first element matching the given selector (checkbox) is checked. If the value is not a checkbox and doesn't have checked property set, it will return undefined. Throws if no element is found.
text(selector)
Returns an array with the texts of the elements matching the given selector. Returns the same value as element textContent
property.
const texts = await browser.text("p"); // ["My First Paragraph", "My Second Paragraph"]
innerHtml(selector)
Returns an array with the innerHtml strings of all the elements matching the given selector
await browser.innerHtml("p"); // ["my <b>first</b> paragraph"]
elementHtml(selector)
Returns an array with the html strings of all the elements matching the given selector
await browser.elementHtml("p"); // ["<p>my <b>first</b> paragraph</p>"]
title()
Returns the page title.
html()
Returns the page HTML as string. It will return the HTML as it was before performing any actions.
pdf(options)
Generates a pdf, if options is a string or contains the value path
a pdf file will be generated on given path. Buffer will be returned otherwise.
await browser.pdf("my_page.pdf");
const myBuffer = await browser.pdf();
await browser.pdf({ // Using Puppeteer pdf options
path: 'page.pdf',
width: "10cm"
})
This methods is just a wrapper on Puppeteer's pdf method, the full list of possible options can be found here
frames()
Returns all the frames attached to the page
url()
Returns the current url of the page.
click(selector, index?)
Clicks all the elements with the matching selector, if the index parameter is set, only the nth element will be clicked. Returns the number of elements clicked.
await browser.click("button.btn");
An array of DOMElements is also supported as selector.
Optionally, if two numbers are passed, position x, y (in pixels) will be clicked. In this case, null with be returned instead of the clicked elements.
Warning: Elements are clicked sequentially, if one of them is a link to an external page, subsequent clicks will fail.
clickText(selector?, text, index?)
Clicks all the elements matching given text. Returns the number of elements clicked.
await browser.clickText("Click Me!");
Optionally a selector can be passed as first argument to only click elements under the given selector. If an index is passed, only the nth element found will be clicked, be aware of the type passed down to index if selector is not passed:
await browser.clickText("Click Me!", 2); // Clicks the second element
await browser.clickText("Click Me!", "2"); // Will search for an element with selector "Click Me!" and text "2"
await browser.clickText(".container", "Click Me!", 2); // Clicks the second element with given text under the element ".container"
clickTextContaining(selector?, text, index?)
Same as clickText, but matches with any text containing the given string.
clickAndWaitForNavigation(selector, timeout=500)
Clicks an element and waits until a navigation event is triggered. Recommended for links to different pages. Keep in mind that not all the clicks will trigger a navigation event.
await browser.url(); // my-page/account
await browser.clickAndWaitForNavigation(".home-button");
await browser.url(); // my-page/home
clickAndWaitForNavigation may delay up to 100ms after the given timeout while waiting for the page to load.
waitAndClick(selector, timeout=500)
Waits for an element to exists and be visible before clicking it. Useful for clicking elements that may have a delay before appearing.
DomElements selectors not supported.
waitAndTap(selector, timeout=500)
Waits for an element to exists and be visible before tapping it.
DomElements selectors not supported.
waitAndType(selector, text, timeout=500)
Waits for an element to exists and be visible before typing text in it.
DomElements selectors not supported.
waitAndCheck(selector, timeout=500)
Waits for an element (checkbox) to exists and be visible before checking it.
DomElements selectors not supported.
tap(selector, index?)
Performs a touchscreen tap action on all the elements matching the given selector, if the index parameter is set, only the nth element will be tapped. Returns the number of elements tapped. The interface is compatible with browser.click.
If two numbers are passed, the given coordinates are clicked.
check(selector)
Checks the first element matching given selector. Setting its checked property to true. Throws if no element is found.
uncheck(selector)
Unchecks the first element matching given selector. Setting its checked property to false. Throws if no element is found
focus(selector)
Focus the first element matching the given selector.
blur(selector)
Unfocus the first element matching the given selector.
hover(selector)
Hovers over the first element matching the given selector.
dragAndDrop(source, target)
Drags the source
selector and drops it on target
.
await browser.dragAndDrop("#my-draggable", "#target");
Note that this method emulates expected events of this behavior instead of emulating mouse interaction
scroll(value, xValue?)
Vertically scrolls the page to the given value on pixels, an optional xValue can be passed for horizontal scrolling. If value is a selector or DomElement, the page will scroll until that element is at view.
screenshot(options?)
Takes a screenshot of the page. This is just a direct interface to Puppeteer's screenshot method and will use the same options, please check Puppeteer docs for the updated usage. It will return the image as a string (base64) or Buffer depending on the encoding. If an option path is defined, the image will be created on given path.
The possible options (from Puppeteer's docs) are:
path
: The file path to save the image to. The screenshot type will be inferred from file extension. If path is a relative path, then it is resolved relative to current working directory. If no path is provided, the image won't be saved to the disk.type
: Specify screenshot type, can be either jpeg or png. Defaults to 'png'.fullPage
: When true, takes a screenshot of the full scrollable page. Defaults to false.clip
: An object which specifies clipping region of the page. Should have the fields x, y, width and heightomitBackground
: Hides default white background and allows capturing screenshots with transparency. Defaults to false.encoding
: The encoding of the image, can be either base64 or binary. Defaults to binary.
screenshotOfElement(selector, options?)
Takes a screenshot of the first element matching the given selector. Will fail if the element is not found. The supported options are the same as screenshot
.
const base64Image = await browser.screenshotOfElement("#my-dashboard", {
encoding: "base64"
})
type(selector, text, options?)
Types given text in the first element matching the selector. If a value is already present, writes the new value at the beginning. Throws if no elements is found.
The following options passed as an object are supported:
- delay: If a delay is given, it will delay the given ms for each key press.
await browser.type("input.my-input", "My Input");
keyPress(key, count?)
Press a keyboard key, the key can be the name of any key supporter by Puppeteer
If an array is passed, all the keys will be pressed consecutively. If count parameter is passed, all the keys will be pressed that given count times.
await browser.keyPress("Enter"); // Press Enter once
await browser.keyPress("Escape", 2); // Press Enter twice
await browser.keyPress(["Enter", "Escape", "Enter"]);
uploadFile(selector, path)
Sets the value of an input file element matching given selector. Path can be absolute or relative to the current working directory.
await browser.uploadFile("input.my-file-input", "./my/file/path.txt");
select(selector, value)
Will select the given value in the select tag of the first element matching the given selector, removing all previous selections. Returns an array with the values that could be selected correctly.
Value can be a string or an array. If the select is multiple all elements in value will be selected, if not only the first element in the select options will.
Will throw if no elements were found.
await browser.select("select.language-select", ["spanish", "english"]); // Returns ["spanish", "english"]
If the option doesn't have a value, the text should be provided.
clearValue(selector)
Clears any value that exists in any of the elements matched by the given selector. Setting the value to ""
.
await browser.clearValue("input.my-input");
setAttribute(selector, attributeName, value)
Sets the attribute of given name to a string value. If null is passed, the attribute will be removed from the element.
addClass(selector, className)
Adds the given css class to the element.
removeClass(selector, className)
Removes the given css class from the element if exists.
wait(ms=250)
Waits the given milliseconds.
waitFor(selector, timeout=500, ...args?)
Waits for given selector to exists and be visible, with the given timeout in milliseconds.
await browser.waitFor(".popup");
If a function is passed instead of a selector, it will wait for that function to resolve in the browser context to true, the optional arguments are passed to the function.
await browser.waitFor((s) => { // Waits for 2 or more elements to be in the page
const docs = document.querySelectorAll(s);
return docs.length > 2;
}, 600, ".my-elements");
DomElements selectors not supported.
waitUntilNotVisible(selector, timeout=500)
Waits until the given selector is no longer visible or doesn't exists, with the given timeout in milliseconds.
await browser.waitUntilNotVisible(".toast");
waitForUrl(url, timeout=500)
Waits for the page to have the given url. The url can be a string or a RegExp.
await browser.click("a");
await browser.waitForUrl("my-url");
waitForText(text, timeout=500)
Waits for the given text to exists.
await browser.waitForText("Click me!");
await browser.clickText("Click me!");
waitForNavigation(timeout=500)
Waits until next page is loaded, recommended after following a link to a different page. Keep in mind that a navigation within a SPA won't necessarily trigger a navigation event.
waitForNavigation may delay up to 100ms after the given timeout while waiting for the page to load
waitUntilEnabled(selector, timeout=500)
Waits until the first element matching the given selector has the attribute disabled
set to null.
waitForPageLoad()
Waits until a dom ready event is fired, this method will also wait until Wendigo is ready to perform assertions on the given page.
findByText(selector?, text)
Returns an array with the elements with text content matching the given text.
const elements = await browser.findByText("My First Paragraph");
elements.length; // 1
Optionally, a selector can be passed as first argument to perform a text search on children of that element only.
findByTextContaining(selector?, text)
Returns an array with all the elements with a text that contains the given text.
const elements = await browser.findByTextContaining("Paragraph");
elements.length; // 2
Optionally, a selector can be passed as first argument to perform a text search on children of that element only.
findByAttribute(attributeName, attributeValue?)
Returns an array with all elements having an attribute matching the given name and value. If no value is assigned, it will match all elements with that attribute, regardless of the value. Use empty string as value to match all the elements with an attribute without value (e.g. <div hidden>
).
const hiddenElements = await browser.findByAttribute("hidden"); // Returns all the elements with the hidden attribute
const paswordElements = await browser.findByAttribute("name", "password"); // Find all elements with a name attribute and value password
findByLabelText(labelText)
Given a label text, returns all the inputs associated to the label through the for
attribute:
<label class="label1" for="input1">My Label</label>
<input id="input1">
const input = await browser.findByLabelText("My Label"); // Returns an array containing iput #input1
findCssPath(element)
Will return the CSS path string (e.g. body > div > button
) of a DomElement.
const elem = await browser.query(".my-element")
const path = await browser.findCssPath(elem); // body > div > p.my-element
findXPath(element)
Will return the xPath string (e.g. /html/body/div/button
) of a DomElement.
tag(selector)
Returns the tag name of the first element matching the given selector, keep in mind that the tag will always be returned lowercase. Returns null if no element was found.
await browser.tag(".my-header"); // "h1"
setValue(selector, value)
Sets the given value on all the elements matching the given selector. Returns the number of elements changed, throws if no element found.
await browser.setValue("input", "new val"); // Returns 1
await browser.assert.value("input", "new val");
This method won't trigger certain events, use type
and select
when possible.
options(selector)
Returns the selector options values of the first element matching the given selector. Throws if no element is found. If the element doesn't have options (i.e. is not a selector) an empty array is returned.
const options = await browser.options("selector.my-selector"); // ["value1", "value2"]
selectedOptions(selector)
Returns all the selected options of the first element matching the given selector. If no value is set, the text of the option will be returned. Throws if no element is found.
back()
Navigates to previous page in history.
forward()
Navigates to next page in history.
refresh()
Reloads current page.
setViewport(viewportConfig)
Sets the configuration of the page viewport, using the same config as Puppeteer method.
await browser.setViewport({width: 300});
Unlike Puppeteer setViewport, the current values will be used for the new viewport for any option not set.
setTimezone(timezone)
Sets browser timezone, valid timezones can be found here
setMedia(mediaOptions)
Sets css media options, options can be a string to define a type or an object with the following properties:
type
: Defines media type emulation (can beprint
orstring
), passingnull
disables media emulation.features
: Receives an array of objects containingname
andvalue
of the css media feature to override. Supported names areprefers-colors-scheme
andprefers-reduced-motion
.
This method is a wrapper over Puppeteer's emulateMediaFeatures and emulateMediaType
triggerEvent(selector, eventName, options?)
Creates and dispatch a DOM event in the elements matching the given selector. The event dispatched will have the name given, and all the options will be passed down to the native Event
constructor, with the options bubbles
, cancelable
and composed supported
await browser.triggerEvent("button", "click"); // Triggers a click event on all buttons. This won't emulate mouse movement like browser.click
await browser.triggerEvent(".listener", "my-custom-event"); // Triggers a custom event to an element that may have a listener atached
mockDate(date, options?)
Mocks the browser's Date object so it returns the expected date instead of current date when using new Date()
without parameters or Date.now()
. The first parameter must be a JavaScript Date object. The following options are supported:
freeze: true
: if set to true, the new Date objects will always return the given date as current date, if false, the expected date will increase normally as time passes.
await browser.mockDate(new Date(2010,10,6)); // Mocks to 6-sept 2010
await browser.evaluate(() => {
const d = new Date(); // 6-sept 2010
const d2 = new Date(2011,10,10); // 10-sept 2011
})
await browser.mockDate(new Date(2010,10,6), {
freeze: false
});
await browser.evaluate(() => {
const d = new Date(); // 6-sept 2010 plus some milliseconds
});
await browser.wait(1000);
await browser.evaluate(() => {
const d = new Date(); // 6-sept 2010 plus one second and some milliseconds
})
Keep in mind that there may be different timezones between the browser and Node. Using timestamps is recommended.
clearDateMock()
Clears the date mock, if any, returning to the native Date object.
setCache(enabled)
Enables or disables the requests cache. Keep in mind that this method returns a promise that resolves to when the change is effective.
setGeolocation(option)
Overrides browser's location, options can contain latitude
, longitude
and accuracy
as numbers.
geolocation()
Returns the current location position as an object. The object contains the following attributes (if available):
- accuracy
- altitude
- altitudeAccuracy
- heading
- latitude
- longitude
- speed
const location = await browser.geolocation();
location.latitude; // 60
location.longitude; //-20
To access geolocation, you may need to first override the
geolocation
permission.
overridePermissions(url, permissions)
Grants given permissions to given web. Permissions can be a string or array of strings with the options listed here.
await browser.overridePermissions("http://myweb.comm", ["geolocation", "accelerometer"]);
Assert
browser.assert
provide some out-of-the-box assertions to easily write tests that are readable without having to specifically perform evaluations. All the assertions have a last optional parameter to define a custom assertion message. All assertions will return a Promise that will fail if the assertion fails. Unless specified, any selector will support css, xPath and DOMElements.
assert.exists(selector, msg?)
Asserts that at least one element with given selector exists.
await browser.assert.exists("h1.main-title");
assert.visible(selector, msg?)
Asserts that the at least one element matching the selector is visible.
An element will considered visible if:
- Exists.
- The computed style doesn't contain display: none or visibility: hidden.
- Opacity is not 0.
- All the parents are visible.
assert.tag(selector, expected, msg?)
Asserts that at least one element matching the given selector has the given tag name.
await browser.assert.tag("my-header", "h1");
assert.text(selector, expected, msg?)
Asserts that at least one element matching the given selector has the expected string or regex.
If expected is an array, all texts in it should match. It matches against the value of element textContent
property.
await browser.assert.text("p", "My First Paragraph");
assert.textContains(selector, expected, msg?)
Asserts that at least one element matching the given selector contains the expected text. Expected text can be an array of strings, in this case all expected texts should match at least one element.
await browser.assert.textContains("p", "My First");
assert.title(expected, msg?)
Asserts that the page title matches the expected string or regex.
assert.class(selector, expected, msg?)
Asserts that the first element matching the selector contains the expected class.
await browser.assert.class("div.container.main-div", "container");
assert.url(expected, msg?)
Asserts that the current url matches the given string or RegExp.
assert.value(selector, expected, msg?)
Asserts that the first element matching the selector has the expected value.
await browser.type("input.my-input", "Dont Panic");
await browser.assert.value("input.my-input", "Dont Panic");
assert.element(selector, msg?)
Asserts that exactly one element matches given selector. Same as elements(selector, 1)
.
assert.elements(selector, count, msg?)
Asserts the number of element that matches given selector.
The count parameter can be a number of the exact number of elements expected or an object with the following properties:
- atLeast: Expects at least the given number of elements.
- atMost: Expects up to the given number of elements.
- equal: Expects the exact number of elements.
<p>Paragraph 1</p>
<p class="second">Paragraph 2</p>
await browser.assert.elements("p", 2); // Ok
await browser.assert.elements("p", {equal: 2}); // Ok
await browser.assert.elements("p", {atLeast: 1, atMost:3}); // Ok
await browser.assert.elements("p.first", 0); //Ok
await browser.assert.elements("p.second", 2); // Fails
await browser.assert.elements("p.second", {atLeast: 1}); // Ok
assert.attribute(selector, attribute, expected?, msg?)
Asserts that at least one element element matching the given selector contains an attribute matching the expected value. If no expected value is given, any not null value for the attribute will pass. The expected value can be a string or regex.
await browser.assert.attribute(".hidden-class", "class", "hidden-class");
await browser.assert.attribute(".hidden-class", "hidden");
To pass a custom message without specifying an expected value, you can pass undefined
:
await browser.assert.attribute(".hidden-class", "hidden", undefined, "hidden-class doesn't have attribute hidden");
You can check an attribute doesn't exists passing null
as expected argument or using assert.not.attribute
.
If the element doesn't exists, the assertion will fail.
assert.style(selector, style, expected, msg?)
Asserts that the first element matching the given selector has an style with the expected value. The assertion will throw an error if no element is found.
await browser.assert.style("h1", "color", "rgb(0, 0, 0)");
assert.href(selector, expected, msg?)
Asserts that the any matching the given selector contains an attribute href with expected value.
browser.assert.href("a", "foo.html");
browser.assert.href("link", "styles.css");
Same as
browser.assert.attribute(selector, "href", expected, msg?)
assert.innerHtml(selector, expected, msg?)
Asserts that at least one element matching the given selector has the expected innerHtml.
The expected html can be either a string or a Regex value.
The assertion will throw if no element is found.
await browser.assert.innerHtml("p", "my <b>first</b> paragraph");
assert.elementHtml(selector, expected, msg?)
Asserts that at least one element matching the given selector has the expected html.
The expected html can be either a string or a Regex value.
The assertion will throw if no element is found.
await browser.assert.elementHtml("p", "<p>my <b>first</b> paragraph</p>");
assert.options(selector, expected, msg?)
Assets that the first element with given selector has the expected options value. Expected can be a string, if only one option is given, or an array if multiple options are given. All expected options must match in the same order.
await browser.assert.options("select.my-select", ["value1", "value2"]);
assert.selectedOptions(selector, expected, msg?)
Assert that the first element with given selector has the expected options selected. Expected can be a string, if only one option is given or an array. All the selected options must match the expected options in the same order.
assert.global(key, value?, msg?)
Asserts that the global object (window) has the given key with the expected value. If not value (or undefined value) is provided, it will assert that the key exists with a not undefined value.
browser.assert.global("localStorage");
browser.assert.global("my-val", "dontpanic");
assert.checked(selector, msg?)
Asserts that the first element matching the given selector has a checked value set to true.
assert.disabled(selector, msg?)
Asserts that the first element matching the given selector is disabled (has attribute disabled).
assert.enabled(selector, msg?)
Asserts that the first element matching the given selector is enabled (doesn't have attribute disabled).
assert.focus(selector, msg?)
Asserts that an element matching the given selector is focused.
browser.click(".btn");
browser.assert.focus(".btn");
assert.redirect(msg?)
Asserts that the opened url is a redirection.
Negative assertions
Most of assertions have a negative counterpart that can be used with browser.assert.not
. Most of the "not" assertions are simply the inverse of the positive version.
assert.not.exists(selector, msg?)
Asserts that no element matching given selector exists.
await browser.not.exists("h1.foo.bar");
assert.not.visible(selector, msg?)
Asserts that no elements with given selector is visible. If no element matches, it will be considered as not visible as well and will pass.
assert.not.tag(selector, expected, msg?)
Asserts that no element matching the given selector has the given tag name.
await browser.assert.not.tag("my-main-header", "h4");
assert.not.text(selector, expected, msg?)
Asserts that no element matching the given selector matches the expected text.
If expected is an array, no text in it should match any element with given selector
await browser.assert.not.text("p", "This text doesn't exists");
await browser.assert.not.text("p", ["This text doesn't exists", "neither do this"]);
assert.not.textContains(selector, expected, msg?)
Asserts that no elements matching the given selector contain the expected text. If expected is an array, no text in it should be contained any element with given selector.
await browser.assert.not.textContains("p", "doesn't exist");
assert.not.title(expected, msg?)
Asserts that the title of the page is not the given string.
assert.not.class(selector, expected, msg?)
Asserts that the first element matching the selector doesn't contain the expected class. It will throw if no element is found.
assert.not.url(expected, msgs)
Asserts that the url of the page doesn't match the expected string.
assert.not.value(selector, expected, msg?)
Asserts that the first element with the given selector doesn't have the expected value.
assert.not.element(selector, msg?)
Asserts that the number of elements matching the given selector is 0.
assert.not.attribute(selector, attribute, expected?, msg?)
Asserts that no element matching the given selector doesn't contain an attribute with the expected value. If no expected value is given, any not null value on the attribute will fail.
await browser.assert.not.attribute(".not-hidden-class", "class", "hidden-class");
await browser.assert.not.attribute(".not-hidden-class", "hidden");
To pass a custom message without specifying an expected value, you can pass undefined:
await browser.assert.not.attribute(".hidden-class", "href", undefined, "hidden-class has attribute href");
The assertion will throw if no element is found.
Keep in mind that passing null as expected value will assert that the attribute exists and it is not recommended.
assert.not.style(selector, style, expected, msg?)
Asserts the first element matching the selector doesn't has a style with given value.
assert.not.href(selector, expected, msg?)
Asserts that no element matching the given selector doesn't contain an attribute href with the expected value.
Same as
browser.assert.not.attribute(selector, "href", expected, msg?)
assert.not.innerHtml(selector, expected, msg?)
Asserts that at no element matching the given selector has the expected innerHtml.
The expected HTML can be either a string or a Regex value.
The assertion will throw if no element is found.
await browser.assert.not.innerHtml("p", "not <b>a</b> paragraph");
assert.not.elementHtml(selector, expected, msg?)
Asserts that at no element matching the given selector has the expected html.
The expected HTML can be either a string or a Regex value.
The assertion will throw if no element is found.
await browser.assert.not.elementHtml("p", "<div>not <b>a</b> paragraph</div>");
assert.not.selectedOptions(selector, expected, msg?)
Assert that the first element with given selector doesn't have the expected options selected. Expected can be a string, if only one option is given or an array. The assertion will only fail if all the expected options match the selected options in the same order.
assert.not.global(key, value?, msg?)
Asserts that the global object (window) doesn't have the given key with the expected value. If not value (or undefined value) is provided, it will assert that the key doesn't exist or it is undefined.
assert.not.checked(selector, msg?)
Asserts that the first element matching the given selector has a checked value set to false.
Note that if the element doesn't have a checked value (i.e. is not a checkbox) this assertion will throw.
assert.not.disabled(selector, msg?)
Asserts that the first element matching the given selector is not disabled (same as assert.enabled).
assert.not.enabled(selector, msg?)
Asserts that the first element matching the given selector is not enabled (same as assert.disabled).
assert.not.focus(selector, msg?)
Asserts that none of the elements matching the given selector is focused.
assert.not.redirect(msg?)
Asserts that the current opened page is not a redirection.
Cookies
The module browser.cookies
provides a way to easily handle cookies through Puppeteer's API. All methods return Promises.
Most methods in the cookies module accept or return a Puppeteer's Cookie object.
cookies.all()
Returns all the cookies in the current page as an object with key being the name and value a string with the cookie value.
const cookies = await browser.cookies.all(); // {username: "arthur_dent", email: "[email protected]"}
cookies.get(name, url?)
Returns the cookie object with given name. Returns undefined if the cookie doesn't exists. Cookies from current page will be returned by default.
const cookie = await browser.cookies.get("username");
cookie.name; // "username"
cookie.value; // "arthur_dent"
If parameter url is set, cookies from the given url domain will be returned.
cookies.set(name, value)
Sets the value of the cookie with given name. If it already exists it will be replaced. The value can be a string (it will only set the cookie value) or a cookie object.
await browser.cookies.set("username", "marvin");
await browser.cookies.set("another-cookie", {
value: "foo",
secure: false
})
The possible parameters of the object are:
- name (required)
- value (required)
- url
- domain
- path
- expires Unix time in seconds.
- httpOnly
- secure
- sameSite Can be Strict or Lax.
cookies.delete(name)
Deletes the cookie with given name if exists. Optionally an array can be passed and all the cookies will be removed. Won't do anything if the cookie doesn't exists.
await browser.cookies.delete("username");
await browser.cookies.delete(["username", "email"]);
Optionally, an object with same interface as Puppeteer can be passed to delete cookies from different pages. This object can provide the following arguments:
- name (required)
- domain
- path
- url
cookies.clear()
Deletes all the cookies of the current page.
await browser.cookies.clear()
Cookies Assertions
It is possible to assert the existence or not of a cookie in the current url with the following assertions:
assert.cookies(name, expected?, msg?)
Asserts that the cookie with the given name exists. If the expected parameter is passed, it will check that the cookie has that value.
browser.assert.cookies("username");
browser.assert.cookies("username", "arthur_dent");
assert.not.cookies(name, expected?, msg?)
Asserts that the cookie with given name doesn't have the expected value. If no expected value is passed, it will check that the cookie doesn't exists (is undefined).
browser.assert.not.cookies("not-a-cookie");
browser.assert.not.cookies("username", "not-user");
Console
browser.console
provides a list of all logs generated by the current page (a.k.a console.*
methods). The logs are returned as an instance of Log. Note that none of these methods requires the use of async/await.
console.all()
Returns an array with all the logs generated by the page.
const logs = browser.console.all();
logs[0].text; // "Hello World!"
console.clear()
Clear all the current logs. Note that logs are cleared when browser.close()
is called, but not when a new page is opened.
console.filter(options)
Returns an array with all the logs matching the given parameters, options can be:
type
: The log type (log
,info
,error
), it must be a string matching Puppeteer's Console Types, some of the most common types are accessible throughbrowser.console.LogTypes
.text
a string or regex matching the log output
If no options are passed, all the logs will be returned, the options can be used together.
const errorLogs = browser.console.filter({type:browser.console.LogTypes.Error});
errorLogs[0].text; // "Oh No! An Error"
const logs = browser.console.filter({text: /Hello/});
logs[0].text; // "Hello World!"
Console Assertions
The following assertions can be used to check the existence of a console log.
assert.console(options, count?, msg?)
Assets that at least one console event with given options exists, if count is set, asserts that the exact number of events exists. The options can be:
text
: Asserts for the console event to have a text matching the given string or regextype
: Asserts that the event is of the given type (log, info, error,...)
await browser.assert.console({
text: "Hello World!",
type: browser.console.LogType.log
});
Objects logged will be converted to string using JSON.stringify, if the object fails to be stringified (circular structure)
[object Object]
will be returned
Log
The class Log provides an abstraction over Puppeteer's ConsoleMessage class. Log has the following attributes:
- text: The Log text, if multiple parameters were passed to console method, these will be concatenated with spaces.
- type: The Log type (string).
- message: The native Puppeteer Log instance.
LogTypes
All the log types are strings, but some of the most common types are accessible in browser.console.LogTypes
. For more possible types, check Puppeteer Docs:
- log
- debug
- info
- error
- warning
- trace
Keep in mind that this list does not contain all possible log types.
LocalStorage
The module browser.localStorage
provides a wrapper around the browser localStorage. All the methods return Promises.
localStorage.getItem(key)
Returns the item with the given key. Returns null if no element exists.
const value = await browser.localStorage.getItem("my-key"); // returns my-value
localStorage.setItem(key, value)
Sets a localStorage entry.
await browser.localStorage.setItem("my-key", "my-value");
localStorage.removeItem(key)
Removes the item with given key.
localStorage.clear()
Removes all the items on the store.
localStorage.length()
Returns the number of items in the store.
const itemsLength = await browser.localStorage.length(); // 3
localStorage.all()
Returns all the items in localStorage as an object.
LocalStorage Assertions
Assertions related local storage can be accessed through browser.assert.localStorage
.
assert.localStorage.exist(key, msg?)
Asserts that the item with given key exists in the localStorage (i.e. not null).
browser.assert.localStorage.exist("my-key");
Alternatively, if an array is passed as key, all the elements will be checked.
assert.localStorage.value(key, expected, msg?)
Asserts that the item with given key has the expected value.
browser.assert.localStorage.value("arthur", "dontpanic");
Alternatively, an object can be passed instead of key/expected with the elements that should be checked:
browser.assert.localStorage.value({arthur: "dontpanic", marvin:"the paranoid"});
assert.localStorage.length(expected, msg?)
Asserts that the localStorage has the expected length.
assert.localStorage.empty(msg?)
Asserts that the localStorage is empty (i.e. length>0).
All these assertions have the negative
browser.assert.localStorage.not
.
Requests
The Requests module allows to get, filter and mock the requests made by the browser since the page was opened.
Returned requests objects are Puppeteer's Requests
requests.filter
Returns a filter over the requests. Check Filtering Requests for examples.
requests.all()
Returns all requests, ordered by when it was dispatched.
await browser.requests.all();
requests.mock(url, options)
Mocks all the requests to an url, sending a fake response instead. If a method (GET
, POST
...) is specified, only requests to given method will be mocked. The url can be a full url string (http://...
) or a regex. If multiple mocks match a requests, the more specific will be used.
The following options are supported:
status
Response status code, defaults to 200.headers
Optional response headers.contentType
If set, equals to setting Content-Type response header.body
Optional response body. It can be a string or a json-serializable object.delay
Optional delay to wait for the response to be fullfilled, in ms.auto
if set to false, the request won't be fullfilled automatically and a manual trigger must be defined,default to true.continue
if set to true, the request will be continue to the server and the real response will be returned.method
defines the method (GET
,POST
, ...) to mock. Empty to mock any method.queryString
: If set, only requests with the exact query string will be mocked, accepts string or object.- By default, all requests with the given url, regardless of the query string will be mocked, unless a querystring is set in the url or in the options.
redirectTo
: If set, the mock will return the response of the given url instead of the original call, maintaining the query string, keep in mind that the redirected request won't trigger any mocks. E.g.requests.mock("http://localhost:8010", {redirectTo: "http://localhost:9010"})
will change the port where all request in the page are sent.
This object properties will be used with the interface of Puppeteer's respond method
// All requests made to /api will return 200 with the given body
browser.requests.mock("http://localhost:8000/api", {
body: `{result: "ok"}`
});
Mock will return a RequestMock object, with the following read-only properties:
called
: If the mock has been called.timesCalled
: The times the mock has been called.response
: The response the mock is returning (read only).url
: Mocked url.immediate
: If the mock will return immediately (delay=0).auto
: If the request will be completed automatically.method
: Mock expected method.querystring
: Mock expected querystring, parsed as an object.
And the following methods:
waitUntilCalled(timeout=500)
: Waits until the mock is called. It will also add a slight delay to give the browser time to process the response.
const mock = browser.requests.mock("http://localhost:8000/api", {
body: {result: "ok"}
});
mock.called; // false
mock.timesCalled; // 0
callApi(); // { result: "ok" }
mock.called; // true
mock.timesCalled; // true
The mock will also provide an assertion interface in mock.assert
with the following assertions:
called(times?, msg?)
: asserts that the mock has been called the given number of times, if times parameter is not given, the assertion will throw if no calls were made.postBody(expected, msg?)
: asserts that the mock has been called with the given body in the request, expected can be an string, object, or RegExp.
const mock = browser.requests.mock("http://localhost:8000/api", {
body: {result: "ok"}
});
await mock.assert.called(0);
callApi("my request"); // POST requests with given body
await mock.assert.called(0);
await mock.assert.postBody("my request");
All mocks are removed on browser.close
.
If the mock is not auto, it can be manually triggered with the method trigger()
, this method cannot be called with auto mocks:
const mock = browser.requests.mock("http://localhost:8000/api", {
body: {result: "ok"},
auto: false
});
callApi();
mock.trigger();
Trigger supports an optional response that will be used instead of the mock default response. It uses the same syntax (body, status, ...).
requests.removeMock(url, options?)
Removes the mock with the given url. If the original mock has a method or queryString, these must be provided in options.
requests.clearRequests()
Clears the list of requests.
requests.clearMocks()
Remove all the request mocks.
requests.getAllMocks()
Returns an array with all the current request mocks set in the browser.
requests.waitForRequest(url, timeout=500)
Waits until a request with given url is done. This will resolve immediately if the requests was already made, to wait without taking in account past requests use waitForNextRequest
. Url can be a string or regexp.
await browser.requests.waitForRequest("my-url");
requests.waitForResponse(url, timeout=500)
Waits until a response to the given url is done. This will resolve immediately if the response was already received, to wait without taking in account past requests use waitForNextResponse
. Url can be a string or regexp.
requests.waitForNextRequest(url ,timeout=500)
Waits until next request with given url is done. If the request was already made, this method will wait until next one. Url can be a string or regexp.
requests.waitForNextResponse(url ,timeout=500)
Waits until next response with given url is received. If the response was already received, this method will wait until next one. Url can be a string or regexp.
requests.setHeaders(headers)
Sends the given headers on every HTTP requests (on top of default headers).
await browser.requests.setHeaders({
custom: "dontpanic"
});
await browser.open("my-url");
Note that
authorization
header should be set withauth
module where possible.
Filtering Requests
To filter the requests made by the browser, you can use browser.requests.filter
.
For example, to filter requests with status code of 200:
const filteredRequests = await browser.requests.filter.status(200).requests;
The available filters are:
requests.filter.url(value)
Filters by the given url. The url can be a string or a regex.
await browser.requests.filter.url("http://localhost:8002/api").requests;
requests.filter.method(value)
Filters by request method (GET
, POST
,...)
requests.filter.status(value)
Filters by response status (200
, 400
)
requests.filter.fromCache(value=true)
Filters whether the response comes from the browser cache or not.
requests.filter.responseHeaders(headers)
Filters requests where the response has all the given headers with the given values. The expected value can be a string or regex.
await browser.requests.filter.responseHeaders({
'content-type': /html/,
})
requests.filter.ok(isOk=true)
Filters request which response are considered successfull (status is between 200 and 299).
Filters can be joined to perform a filter of several fields.
//Filters all the POST requests made to any url with api that are not cached and returned a success code
await browser.filter.url(/api/).method("POST").ok().fromCache(false).requests;
requests.filter.postBody(expected)
Filter requests by post body, the body can be a String, Object or regex.
// Filters all DELETE requests made to with json body
await browser.filter.url(/api/).method("DELETE").postBody({id: 5}).requests;
requests.filter.resourceType(resource)
Filter requests by given resource type (xhr
, fetch
, ...). Possible resource types are defined here.
requests.filter.resourceType(contentType)
Filter responses by content type header (text/css; charset=UTF-8
, ...). Accepts both string or RegExp.
requests.filter.pending()
Filter requests by pending (response not retrieved).
requests.filter.responseBody(expected)
Filters requests by response body, the body can be a String, Object or regex.
const byResponseFilter = await browser.requests.filter.url(/api/).responseBody({response: 'OK'}).requests;
Keep in mind that some filters like status require the requests to be finished. Use
await browser.waitForResponse()
before filtering to make sure the requests was completed.
Requests Assertions
Assertions related requests can be accessed through browser.assert.requests
.
Like filters, request assertion don't need await
and can be concatenated. All the assertions will check that at least one request with the given constraints was made.
assert.requests.url(expected, msg?)
Asserts that at least one request is made to the given url. The url can be a string or regex.
await browser.assert.requests.url(/api/);
assert.requests.method(expected, msg?)
Asserts that at least one request was made with the given method (GET
, POST
, ...).
await browser.assert.requests.method("GET");
assert.requests.status(expected, msg?)
Asserts that a response was received with the given status.
await browser.assert.requests.status(200);
Note that this method requires the request to be finished.
assert.requests.responseHeaders(expected, msg?)
Asserts that a response was received with the given headers. The expected variable is an object with one or more key values representing the expected headers. The value can be either a string or regex.
await browser.assert.requests.responseHeaders({
'content-type': /html/,
})
assert.requests.ok(expected=true, msg?)
Asserts that an successful response was received (status is between 200 and 299), or false if false is given.
assert.requests.postBody(expected, msg?)
Asserts that a request contains the given post body (regardless of method). The expected value can be a string, regex or object.
await browser.assert.requests.postBody({status: "OK"});
assert.requests.responseBody(expected, msg?)
Asserts that a request response contains the given body. The expected value can be a string, regex or object.
await browser.assert.requests.responseBody({response: "OK"});
assert.requests.pending(msg?)
Asserts that at least one request is still pending (no response received).
assert.requests.resourceType(resourceType, msg?)
Asserts that at least one request has the given resource type (fetch
, xhr
, ...).
assert.requests.contentType(expected, msg?)
Asserts that at least one response has given content type header (text/css; charset=UTF-8
, ...). Accepts both string or RegExp.
assert.requests.exactly(expected, msg?)
Asserts that the exact given number of requests match the assertions. Expected can be any positive number or 0.
await browser.assert.requests.url("localhost:800/api"); // asserts that at least one request is made to given url
await browser.assert.requests.url("localhost:800/api").exactly(2); // asserts that 2 requests are made to given url
await browser.assert.requests.url("localhost:800/api").exactly(0); // asserts that no requests are made to given url
Concatenating multiple assertions is possible:
// Asserts that a POST method was done to the api endpoint
await browser.assert.requests.method("POST").