Skip to main content

WebdriverIO Integration

Introduction

This guide requires an existing WebdriverIO project.
You can alternatively take a look to our example repository.

Sauce Visual provides an integration with WebdriverIO through a service that you can add to any existing WebdriverIO project.

Sauce Visual adds new commands to the WebdriverIO's browser object:

  • browser.sauceVisualCheck(): Takes a screenshot and send it to Sauce Visual for comparison.
  • browser.sauceVisualResults(): Waits for diff calculations to complete and returns a summary of results.

Quickstart

Step 1: Add Sauce Visual dependency

Install the Sauce Visual service in your current project.

npm install --save-dev @saucelabs/wdio-sauce-visual-service

Step 2: Add SauceVisualService to your WebdriverIO configuration

Add the SauceVisualService to your existing configuration (E.g. wdio.conf.(js|ts)):

import type { Options } from '@wdio/types';

export const config: Options.Testrunner = {
//...
services: [
//
// This service is needed for WDIO to make sure it can connect to Sauce Labs to:
// - automatically update the names
// - automatically update the status (passed/failed)
// - automatically send the stacktrace in case of a failure
//
'sauce',
//
// This service is needed for the Sauce Visual service to work
//
[
'@saucelabs/wdio-sauce-visual-service',
// The options for the Sauce Visual service
{
buildName: 'Sauce Demo Test',
branch: 'main',
project: 'WDIO examples',
},
],
],
//...
}

Step 3: Add visual tests in your project

Add a check to one of your tests:

describe('Login Flow', () => {
it('should login with valid credentials', async () => {
//...
await browser.sauceVisualCheck('My Login Page')
//...
});
})

Step 4: Configure your Sauce Labs credentials

Sauce Visual relies on environment variables for authentications.
Both SAUCE_USERNAME and SAUCE_ACCESS_KEY need to be set prior starting your WebdriverIO job.

Username and Access Key can be retrieved from https://app.saucelabs.com/user-settings.

export SAUCE_USERNAME=__YOUR_SAUCE_USER_NAME__
export SAUCE_ACCESS_KEY=__YOUR_SAUCE_ACCESS_KEY__

Step 5: Run the test

Upon executing your tests for the first time under this step, a visual baseline is automatically created in our system. This baseline serves as the standard for all subsequent WebdriverIO tests. As new tests are run, they are compared to this original baseline, with any deviations highlighted to signal visual changes. These comparisons are integral for detecting any unintended visual modifications early in your development cycle. All test builds, including the initial baseline and subsequent runs, can be monitored and managed through the Sauce Labs platform at Sauce Visual Builds.

Remember, the baseline is established during the initial run, and any subsequent visual differences detected will be marked for review.

Advanced usage

Customizing Your Builds (Environment Variables)

Below are the environment variables available in the Sauce Visual WebdriverIO plugin. Keep in mind that the variables defined in WebdriverIO configuration have precedence over these variables.

Variable NameDescription
SAUCE_USERNAMErequiredYour Sauce Labs username. You can get this from the header of app.saucelabs.com
SAUCE_ACCESS_KEYrequiredYour Sauce Labs access key. You can get this from the header of app.saucelabs.com
SAUCE_REGIONThe region you'd like to run your Visual tests in. Defaults to us-west-1 if not supplied. Can be one of the following:
'eu-central-1', 'us-west-1' or 'us-east-4'
SAUCE_VISUAL_BUILD_NAMEThe name you would like to appear in the Sauce Visual dashboard.
SAUCE_VISUAL_BRANCHThe branch name you would like to associate this build with. We recommend using your current VCS branch in CI.
SAUCE_VISUAL_DEFAULT_BRANCHThe main branch name you would like to associate this build with. Usually main or master or alternatively the branch name your current branch was derived from. Follow me to learn more
SAUCE_VISUAL_PROJECTThe label / project you would like to associate this build with.
SAUCE_VISUAL_BUILD_IDFor advanced users, a user-supplied SauceLabs Visual build ID. Can be used to create builds in advance using the GraphQL API. This can be used to parallelize tests with multiple browsers, shard, or more.
By default, this is not set and we create / finish a build during setup / teardown.
SAUCE_VISUAL_CUSTOM_IDFor advanced users, a user-supplied custom ID to identify this build. Can be used in CI to identify / check / re-check the status of a single build. Usage suggestions: CI pipeline ID.

Test results summary

browser.sauceVisualResults() returns a summary of test results in format:

{
QUEUED: number; // Diffs that are pending for processing. Should be 0 in case the test is completed without any timeouts
EQUAL: number; // Diffs that have no changes detected
UNAPPROVED: number; // Diffs that have detected changes and waiting for action
APPROVED: number; // Diffs that have detected changes and have been approved
REJECTED: number; // Diffs that have detected changes and have been rejected
}

Sample output:

{ APPROVED: 0, EQUAL: 0, UNAPPROVED: 2, REJECTED: 0, QUEUED: 0 }

Sample usage:

const EXPECTED_TOTAL_UNAPPROVED_DIFFS = 0;

expect((await browser.sauceVisualResults()).UNAPPROVED).toBe(EXPECTED_TOTAL_UNAPPROVED_DIFFS);

Build attributes

When creating the service in WebdriverIO's configuration, extra fields can be set to define the context, thus acting on which baselines new snapshots will be compared to. (More info on baseline matching)

Options:

  • buildName: Name of the build
  • project: Name of the project
  • branch: Name of the branch, used for matching
  • defaultBranch: Name of the default branch, used for matching

They need to be set through the options parameter.

Example:

...
export const config: Options.Testrunner = {
...
services: [
'sauce',
[
'@saucelabs/wdio-sauce-visual-service',
{
buildName: 'Sauce Demo Test',
branch: 'main',
project: 'WDIO examples',
},
],
],
...
}

Ignored regions

Component-based ignored region

Sauce Visual provides a way to ignore a list of components.

An ignored component can be a specific element from the page.

Those ignored components are specified when requesting a new snapshot.

Example:

await browser.sauceVisualCheck('Inventory Page', {
ignore: [
// addBackPackToCartButton will be ignored
InventoryPage.addBackPackToCartButton,
],
});

User-specified ignored region

Alternatively, ignored regions can be user-specified areas. A region is defined by four elements.

  • x, y: The location of the top-left corner of the ignored region
  • width: The width of the region to ignore
  • height: The height of the region to ignore

Note: all values are pixels

Example:

await browser.sauceVisualCheck('Before Login', {
ignore: [
{
x: 100,
y: 100,
width: 200,
height: 200,
},
],
});

Selective Diffing

Sauce Visual allows selective diffing that permits to ignore changes from a certain kind (more information here).

warning

Selective diffing is only available with Balanced diffing method AND with DOM capture enabled.

Screenshot-wide configuration

Sauce Visual Binding allows to configure which kinds of changes should be effective on snapshot.

Example:

    await browser.sauceVisualCheck('Inventory Page', {
diffingMethod: DiffingMethod.Balanced,
captureDom: true,
// Every content change will be ignored
disable: ['content'],
});

Area-specific configuration

Sauce Visual Binding allows to configure which kinds of changes should be effective specific regions of the snapshot.

    await browser.sauceVisualCheck('login-page', {
diffingMethod: DiffingMethod.Balanced,
captureDom: true,
regions: [
// Any change will be ignored.
{ element: $('[id="user-name"]'), enableOnly: [] },
// Only style changes won't be ignored.
{ element: $('[id="password"]'), enableOnly: ['style'] },
],
});

Capturing the DOM snapshot

Sauce Visual does not capture dom snapshot by default. It can be changed in sauceVisualCheck options.

Example:

browser.sauceVisualCheck('Before Login', {
captureDom: true
});

Full page screenshots

Full Page Screenshots capture the entire webpage, including content beyond the visible viewport, to ensure comprehensive visual testing. This feature helps teams identify layout or rendering issues across the full page and ensures consistency across devices and browsers.

By default, only the viewport is captured when .sauceVisualCheck is used. You can opt in to capturing the entire page by using the fullPage option. It will capture everything by scrolling and stitching multiple screenshots together.

The maximum number of scrolls and stitches in a full page screenshot is 10.

note

Use full page screenshots only when necessary, as they slow down test execution.

Web

Options:

  • delayAfterScrollMs: Delay in ms after scrolling and before taking screenshots. The default value is 0. We recommend using this option for lazy loading content.
  • disableCSSAnimation: Disable CSS animations and the input caret in the app. The default value is true.
  • hideAfterFirstScroll: One or more CSS selectors that we should remove from the page after the first scroll. Useful for hiding fixed elements such as headers, cookie banners, etc.
  • hideScrollBars: Hide all scrollbars in the app. The default value is true.
  • scrollLimit: Limit the number of screenshots taken for scrolling and stitching. The default value is 10. The value needs to be between 1 and 10.
note

It's recommended to use the hideAfterFirstScroll option for fixed or sticky position elements such as sticky headers or consent banners.

Example:

await browser.sauceVisualCheck('Long content page', {
// Enable full page screenshot using the default options
fullPage: true,
});

await browser.sauceVisualCheck('Long content page', {
// Enable full page screenshot and customize the behavior
fullPage: {
delayAfterScrollMs: 500,
disableCSSAnimation: false,
hideAfterFirstScroll: ["#header"],
hideScrollBars: false,
scrollLimit: 5
},
});

Mobile Native (beta)

Options:

  • delayAfterScrollMs: Delay in ms after scrolling and before taking screenshots. The default value is 0. We recommend using this option for lazy loading content.
  • nativeClipSelector: Selector used to identify the first element to which clipping will be applied.
  • scrollElement: Scrollable element used for scrolling. The default is root element.
  • scrollLimit: Limit the number of screenshots taken for scrolling and stitching. The default value is 10. The value needs to be between 1 and 10.
note

It is recommended to set scrollElement to the appropriate scrollable container.

await browser.sauceVisualCheck('Long content page', {
// Enable full page screenshot and customize the behavior
fullPage: {
scrollElement: $('//XCUIElementTypeCollectionView'),
scrollLimit: 5
},
});

Use only XPath selectors for ignore regions and clipping to an element.

note

On iOS, selectors must be contained within the scrollElement.

await browser.sauceVisualCheck('Ignore regions - Long content page', {
// Enable full page screenshot and ignore elements
ignore: [
{
selector: {
value: '//XCUIElementTypeStaticText[@name="Product Price"]',
type: 'XPATH'
}
}
],
fullPage: {
scrollElement: $('//XCUIElementTypeCollectionView'),
},
});
await browser.sauceVisualCheck('Clip - Long content page', {
// Enable full page screenshot and clip to an element
fullPage: {
scrollElement: $('//XCUIElementTypeCollectionView'),
nativeClipSelector: {
value: '//XCUIElementTypeCollectionView/XCUIElementTypeOther',
type: 'XPATH'
}
},
});
note

Full page screenshot for mobile native testing is in beta. Read more about mobile native limitation

Clip to an Element

You can clip to a specific element on the page by using the clipElement option when calling Sauce Visual.

Notes:

  • Clipping is done by taking a screenshot of the page then clipping it to the location of the requested element.
  • We will attempt to scroll the element into view before taking the snapshot.
  • We can only take a screenshot of what is visible in the current viewport, however, this can be combined with full page option to enable clipping large vertical elements.

Example:

await browser.sauceVisualCheck('Visible Sale Banner', {
// An element that we should crop the screenshot to
clipElement: await $('.your-css-selector')
})

Using Baseline Overrides

At the global / service level

import { Browser, OperatingSystem } from '@saucelabs/visual';
export const config = {
// ...
services: [
'sauce',
[
'@saucelabs/wdio-sauce-visual-service',
{
baselineOverride: {
browser: Browser.Chrome,
device: "Desktop (1024x627)",
operatingSystem: OperatingSystem.Windows,
operatingSystemVersion: '10',
},
},
],
],
}

Or at the snapshot level

import { Browser, OperatingSystem } from '@saucelabs/visual';
// ...
// Passing on a per-snapshot level
await browser.sauceVisualCheck('Inventory Page', {
baselineOverride: {
browser: Browser.Chrome,
device: "Desktop (1024x627)",
operatingSystem: OperatingSystem.Windows,
operatingSystemVersion: '10',
}
});

Example

An example project is available here.