Skip to main content

Advanced configuration

Configure server URL

By default, Eyes-WebdriverIO communicates with the Applitools public Eyes cloud server, located at https://eyesapi.applitools.com.

If you have a dedicated cloud or an on-premise server, configure a different Eyes server URL as follows:

eyes.setServerUrl('https://mycompanyeyesapi.applitools.com')

Configure proxy

If your company's network requires requests to go through the corporate proxy, you can configure it as follows:

eyes.setProxy('http://yourproxy.com')

// provide username and password:
eyes.setProxy('http://user:pass@yourproxy.com')
// OR
eyes.setProxy({
url: 'https://yourproxy.com',
username: 'user',
password: 'pass'
})

// use tunneling in case of HTTP over HTTPS proxy:
eyes.setProxy({
url: 'http://yourproxy.com',
isHttpOnly: true
})

Make every visual test correspond to a functional test

Every call to eyes.open and eyes.close defines a test in Applitools Eyes, and all the calls to eyes.check between them are called "steps". In order to get a test structure in Applitools that corresponds to the test structure in your functional test, you should open/close tests in every test call.

For example, when running with Mocha as a test runner:

describe('My first visual test', function() {
beforeEach(async () => {
await eyes.open(browser, "webdriver.io website", "My first webdriver.io test!")
})
afterEach(async () => {
await eyes.close()
})
it('...', async function() {
// ...
});
});

Organize tests in batches

You can manage how visual tests are aggregated into batches. Here are two methods for clustering tests into a single batch:

Method 1: environment variable

Run all the processes that execute webdriver.io with the same value for APPLITOOLS_BATCH_ID. For example, execute all webdriver.io files specified in the configuration file wdio.conf.js with the same randomly generated UUID:

#! Unix based machines:
APPLITOOLS_BATCH_ID=`uuidgen` npx wdio wdio.conf.js

You can control the batch name that is displayed in the Test Manager. For example:

export APPLITOOLS_BATCH_ID=`uuidgen`
export APPLITOOLS_BATCH_NAME="Login tests"
npm test

Method 2: eyes.setBatch

Provide all Eyes instances with the same value for batch ID. For example:

eyes.setBatch({
id: SOME_SHARED_VALUE_THAT_WILL_BE_THE_SAME_FOR_ALL_TEST_FILES,
name: 'My batch'
})

Stitch mode

The default stitch mode is Scroll. In order to change it:

const {Eyes, StitchMode} = require('@applitools/eyes-webdriverio')

const eyes = new Eyes()
eyes.setStitchMode(StitchMode.CSS)

// to go back to scroll:
eyes.setStitchMode(StitchMode.SCROLL)

Background information

Eyes-WebdriverIO allows you to control if the checkpoint image should include only the viewport - i.e. what you see in the browser window when you first load a page, or if it should also include the full page - i.e. what you would see if you manually scrolled down, or across, a page that is larger than the viewport.

When Eyes-WebdriverIO takes a full page screenshot, it does so by taking multiple screenshots of the viewport at different locations of the page (via the webdriver.io browser driver), and then "stitching" them together. The output is one clear, potentially very large, screenshot of what can be revealed on the page when it is scrolled.

There are two methods for creating the stitched screenshot, and they are both related to the way the page is moved relative to the viewport:

1. Stitch mode: Scroll

Using this method, the page is scrolled, just as a user would scroll. Eyes-WebdriverIO takes the viewport screenshot, then scrolls the page to calculated locations. The issue with this method is that the page might respond to scroll events, and change the way it appears visually between the screenshots.

2. Stitch mode: CSS

Using this method, the page is moved around by changing the CSS property transform on the HTML element with different values for translate(x,y). This method is not sensitive to scroll events, and is usually the recommended method for stitching.

Stitch overlap

The stitch overlap is the length of the intersecting area between two screenshots that are stitched together. It's like placing two printed pictures one on top of the other with some overlapping area between them.

This is useful in cases of fixed elements, like a footer, that show up in each of the sub-screenshots. Using a stitch overlap bigger than the size of the footer would make it disappear from every image, and only show up at the bottom of the full page screenshot.

The default stitch overlap is 50 pixels. To change it:

eyes.setStitchOverlap(60)

Match level

The match level determines the way by which Eyes compares the checkpoint image with the baseline image.

The default match level is Strict. To change it:

// Option 1: For the rest of the execution
const {MatchLevel} = require('@applitools/eyes-webdriverio')
eyes.setMatchLevel(MatchLevel.Layout)

// Option 2: For a single checkpoint
eyes.check(Target.window().layout())
eyes.check(Target.window().strict())
eyes.check(Target.window().ignoreColors ())
eyes.check(Target.window().exact())

For more information, see How to use Eyes match levels in the Eyes Knowledge Center.

Ignore displacements

You can use ignore displacements to hide diffs that arise from content whose position on the page has changed, and focus on mismatches caused by actual changes in the content.

The default is false. To change it:

// For the rest of the execution
eyes.setIgnoreDisplacements(true)

// For a single checkpoint
eyes.check(Target.window().ignoreDisplacements())

For more information, see Hide displacement diffs tool in the Eyes Knowledge Center.

Test properties

You can provide additional information about each test in custom fields, which can then show up in Test Manager in their own column.

This is done by calling setProperties on the configuration, and providing it with an array of properties with the structure {name, value}. For example:

const {Eyes} = require('@applitools/eyes-webdriverio')

const eyes = new Eyes()

const configuration = eyes.getConfiguration()
configuration.setProperties([{name: 'my custom property', value: 'some value'}])
eyes.setConfiguration(configuration)

The test properties could also be specified per batch by calling setProperties on the batch info, and providing it with an array of properties with the structure {name, value}. For example:

const {Eyes, BatchInfo} = require('@applitools/eyes-webdriverio')

const eyes = new Eyes()

const batch = new BatchInfo()
batch.setProperties([{name: 'my custom batch property', value: 'some value'}])

const configuration = eyes.getConfiguration()
configuration.setBatch(batch)
eyes.setConfiguration(configuration)

Test results

The results of the test can be consumed as the return value from eyes.close. Here's an example for creating a formatted output string out of the TestResults object:

function formatTestResults(testResults) {
return `
Test name : ${testResults.getName()}
Test status : ${testResults.getStatus()}
URL to results : ${testResults.getUrl()}
Total number of steps : ${testResults.getSteps()}
Number of matching steps : ${testResults.getMatches()}
Number of visual diffs : ${testResults.getMismatches()}
Number of missing steps : ${testResults.getMissing()}
Display size : ${testResults.getHostDisplaySize().toString()}
Steps :
${testResults
.getStepsInfo()
.map(step => {
return ` ${step.getName()} - ${getStepStatus(step)}`
})
.join('\n')}`
}

function getStepStatus(step) {
if (step.getIsDifferent()) {
return 'Diff'
} else if (!step.getHasBaselineImage()) {
return 'New'
} else if (!step.getHasCurrentImage()) {
return 'Missing'
} else {
return 'Passed'
}
}

For the full list of methods, see TestResults class.

Logging

To enable logging to the console, use the ConsoleLogHandler class:

import {Eyes, ConsoleLogHandler} from '@applitools/eyes-webdriverio'

const eyes = new Eyes()
eyes.setLogHandler(new ConsoleLogHandler())

// To enable verbose logging:
eyes.setLogHandler(new ConsoleLogHandler(true))

To write logs to file, use the FileLogHandler class. You can configure the file path, verbosity, and whether to append to file.

The API is as follows:

new FileLogHandler(isVerbose, filepath, append)

Default values:

  • isVerbose: false
  • filepath: 'eyes.log' - meaning a file with this name will be created in the current working directory.
  • append: true - meaning that every test will append to the file instead of recreating it.

Example

const {Eyes, FileLogHandler} = require('@applitools/eyes-webdriverio')
const path = require('path')

const eyes = new Eyes()

// append non-verbose logs to logs/eyes.log (relative to current working directory)
eyes.setLogHandler(new FileLogHandler(false, path.resolve('logs', 'eyes.log')))

// write verbose logs to a new file at logs/eyes-{timestamp}.log (relative to current working directory)
eyes.setLogHandler(new FileLogHandler(true, path.resolve('logs', `eyes-${Date.now()}.log`), false))

Visual locators

For information about visual locators and how to use them, see Visual locators in the Knowledge Center.

The API to locate a visual locator in Eyes-WebdriverIO has the following TypeScript signature:

// Note: This is a formal TypeScript definition.
// The reason we use the generic type TLocator here is that is shows how the return value of eyes.locate is an object
// with the same keys as the array of locatorNames in the input to eyes.locate.
// We explain this in more detail in the example below.

interface Eyes {
locate<TLocator extends string>(settings: VisualLocatorSettings<TLocator>): Promise<Record<TLocator, Array<Region>>>
}

interface VisualLocatorSettings<TLocator extends string> {
locatorNames: Array<TLocator>;
firstOnly: boolean;
}

interface Region {
x: number;
y: number;
width: number;
height: number;
}

Here is an example for using this API and applying a touch action in Appium:

// first need to call eyes.open
await eyes.open(browser, 'Test app', 'Test visual locators')

// example for using eyes.locate
const regionsMap = await eyes.locate({
locatorNames: ['locator_a', 'locator_b', 'locator_c'],
})

// now get the coordinates of one of the locators
const regionsForLocator_A = regionsMap['locator_a']

// if region is found, perform press at the middle
if (regionsForLocator_A && regionsForLocator_A.length > 0) {
const region = regionsForLocator_A[0]
const clickLocation = {
x: region.left + region.width / 2,
y: region.top + region.height / 2,
}
await browser.touchAction([
{action: 'press', x: clickLocation.x, y: clickLocation.y},
{action: 'wait', ms: 500},
'release',
])
}