@waldoapp/wdio-service v1.1.1
WebdriverIO Waldo Service
A WebdriverIO service that provides better integration with Waldo.
This package provides:
- Automatic configuration of Waldo as the webdriver endpoint.
- A collection of additional commands to ease mobile testing.
- A TypeScript definition for the options and mobile-specific capabilities.
Table of contents:
Requirements
- Node.js version 18 or later
- WebdriverIO version 8 or 9
- A Waldo account: sign up here
Installation
Starting from a sample project
The easiest way to get started with this package if you aren't already using WebDriverIO is to clone the sample repository and follow the instructions directly in Waldo or in it's readme.
Starting from scratch
Full instructions on how to install WebdriverIO can be found here,
but the easiest way is to use the CLI:
npm init wdio@latest .Here are the steps to follow for an optimal configuration with Waldo (The only steps listed are the one that affect Waldo usage, the rest of the configuration is up to you):
- What type of testing would you like to do? E2E Testing - of Web or Mobile Applications
- Where is your automation backend located? On my local machine (We'll switch to Waldo later)
- Which environment you would like to automate? Mobile - native, hybrid and mobile web apps, on Android or iOS
- Which mobile environment you'ld like to automate? Android (We won't use the package but it's required)
- Do you want to add a service to your test setup? Remove appium if that was added by default
- Continue with Appium setup using appium-installer? No
You'll get a project where you can remove the automatically added appium-uiautomator2-driver:
npm uninstall @wdio/appium-service appium-uiautomator2-driverYou can then proceed to add Waldo to the project.
In an existing WebDriverIO project
To add this package in an existing WebDriverIO project is to add the @waldoapp/wdio-service package as a
devDependency in your package.json:
npm install @waldoapp/wdio-service --save-devIf you use TypeScript you'll also need to reference package for the types to be available,
in tsconfig.json add @waldoapp/wdio-service to the types array:
{
"compilerOptions": {
"types": [
"node",
"@wdio/globals/types",
"expect-webdriverio",
"@wdio/mocha-framework",
"@waldoapp/wdio-service"
]
}
}The next step would be to configure the package.
Configuration
Sample configuration file
// wdio.conf.ts
export const config: WebdriverIO.Config = {
// This is only for illustration purposes,
// this is done automatically if no key is provided,
// the WALDO_API_TOKEN environment variable is used
key: process.env.WALDO_API_TOKEN,
services: [
[
'@waldoapp/wdio-service',
{
showSession: true,
},
],
],
capabilities: [
{
platformName: 'Android',
// 'wiki' targets the sample Wikipedia application
// Replace with your application version ID
'appium:app': 'wiki',
'waldo:options': {
deviceName: 'Pixel 7',
},
},
],
mochaOpts: {
// The default value is pretty low for mobile testing
timeout: 10 * 60 * 1000,
},
};Authentication
To use the Waldo service, you need to provide a valid Waldo API token.
This token can be specified by defining the WALDO_API_TOKEN environment variable,
or by including the key option in your wdio.conf.ts file.
The API token can be either a user-scoped token for development found in the “Profile” tab of your Waldo account settings, or an application-scoped CI token found in the “General” tab of the “Configuration” for your app.
On developer machines the token can also be stored in a local profile ~/.waldo/profile.yml and is automatically picked
up, a script is provided in this package to fill it:
npx waldo-auth [YourToken]Specifying the application binary/build to target
In order to run, you must upload your application binary to Waldo. To do so, follow the instructions on the Upload page while logged in or check the documentation.
A successful upload generates a build version ID of the form appv-0123456789abcdef that can be copied via the
Copy build id option in the 3 dots menu on the web and that is provided in the output when the CLI is used to
upload.
This version ID must then be provided in either the versionId option, or the appium:app capability.
You do not need to provide the versionId if instead you specify an existing running session with the sessionId
option (The application version and device type are selected when the session is started).
Usage
When you execute a script that uses Waldo Scripting, the script always uses a remote device session on a simulator/emulator running within the Waldo infrastructure.
There are multiple ways to start a session depending on if you are developing a new script, running tests locally to verify a change or running the test during Continuous Integration (CI).
Interactive execution
In this mode, your script interacts with an ongoing remote session that remains alive when execution reaches the end of the script.
In order to run in this mode, you must first launch a session manually in Waldo by going to the Live view and starting a session.
As long as this session remains alive, you can execute your script against it.
To do so you need to provide the session ID that can be obtained by using the Use for script
button of the Info tab or from the URL (they are prefixed with sess-, such as sess-1234567890abcdef).
SESSION_ID=[SessionID] npm run wdio -- --spec [YourScript]ℹ️ Note
in this mode, it is not necessary to specify
VERSION_IDsince the remote session was already started with a specific app version.⚠️️ Warning
If you have multiple test files and don't specify a
--specoption, all of them will be executed at the same time, on the SAME device session.
This mode is very useful for creating a new script or editing an existing one, since it allows you to quickly relaunch your app over and over without waiting for session initialization. In addition, this mode also allows you to perform some actions manually on the session in the browser, as well as use the tree inspector to determine the best way to locate an element.
Live execution
In this mode, your script interacts with a freshly created remote session, where you can watch its execution in a browser in real time.
It is enabled by setting the SHOW_SESSION environment variable to 1:
VERSION_ID=[VersionID] SHOW_SESSION=1 npm run wdio -- --spec [YourScript]💡 Tip
It's often better to always specify a single test file via the
--specoption to avoid a lot of browser tabs openning at the same time.
This mode is very useful when you want to watch the current behavior of a script against a new application version or to reproduce an issue noticed in CI.
Background execution
In this mode, your script interacts via Waldo Scripting with a freshly created remote session that is killed when execution reaches the end of the script.
You do not have any visual feedback of what is happening; however, you can watch the replay of the execution at a later time.
It is the default mode and simply needs a version ID to target:
VERSION_ID=[VersionID] npm run wdioThis is the most common mode of execution when you have a full suite of scripts to run in parallel (for instance from your CI). In such a case, you are usually only interested in accessing the session replay of a script that failed.
Waldo service options
ℹ️ Note To authorize the Waldo service your configuration must contain a token for example in the
keyoption.
token
The security token.
This can also be specified with either key in the test runner options, or the WALDO_API_TOKEN environment variable.
Type: string
Default: undefined
showSession
Opens the Waldo interactive session viewer in a browser when the test is started.
This option has no effect when the sessionId option is specified.
This option can also be configured by setting the WALDO_SHOW_SESSION (or SHOW_SESSION) environment variable to 1.
Type: boolean
Default: false
waitSessionReady
Waits for the session to be fully ready, and the application launched, before starting the test. Otherwise, the test starts as soon as the device is available.
Type: boolean
Default: true
sessionId
The ID of an existing Waldo session (created via Sessions > Live > Start session) to connect to.
This is useful for interactive development.
The session ID can also be specified with the WALDO_SESSION_ID (or SESSION_ID) environment variable.
Type: string
Default: undefined
versionId
The ID of the app (build) version to use for the test session (for example, appv-0123456789abcdef).
The version ID can also be specified with the WALDO_APP_VERSION_ID (or VERSION_ID) environment variable.
For Appium compatibility, this option can also be specified in the appium:app capability field.
Type: string
Default: undefined
coordinateMode
⚠️️ Warning
This is iOS specific, sessions on Android will fail to start if this property is specified.
'waldo:options': {
automationName: 'Waldo',
coordinateMode: 'logical',
},All coordinates sent in commands or received via the /source endpoint can either be in 'logical' mode, expressed
in points or in 'device' mode, expressed in pixels.
const points = pixel / screenScale;- When emulating Appium, the coordinates are always expressed in points (
'logical') and specifying any other value will fail. - In waldo mode the default is to use pixel coordinates (
'device') but this option/capability allow to change it .
Type: 'logical' | 'device'
Default: undefined for Android, 'logical' for Appium iOS, 'device' for Waldo iOS
Device capabilities
All the service options can also be specified in the capabilities object for a specific device inside the
waldo:options key:
capabilities: [
{
platformName: 'Android',
'waldo:options': {
deviceName: 'Pixel 3a',
showSession: true,
},
},
];And all capabilities can also be specified without nesting them inside waldo:options by prefixing them with waldo:.
The previous example is equivalent to:
capabilities: [
{
platformName: 'Android',
'waldo:deviceName': 'Pixel 3a',
'waldo:showSession': true,
},
];automationName
'waldo:options': {
automationName: 'Waldo',
},This option can also be specified as appium:automationName or non-prefixed automationName directly in the
capabilities object.
For compatibility, the default behavior of the Waldo service is to return a tree similar to the one returned by Appium,
this is the equivalent of providing UiAutomator2, UiAutomator2 or Appium as the automation name.
This makes it easy to port existing Appium scripts to Waldo but is based mainly on the accessibility view of the application.
The Waldo automation name can also be used to enable same mode that is used by Waldo Automate.
In this mode the tree returned is typically more complete as it unifies native elements, Web views, React Native,
and Flutter elements.
The Waldo automation name is required to use some of the additional commands added by this service like
getWaldoTree, getNodes and tapElementWith.
Type: string
Default: Appium
deviceName
'waldo:options': {
deviceName: 'Pixel 3a',
},The name of the device to use for the test session (for example, iPhone 15 or Pixel 7).
If this option is not specified, the default device configured for the app in Waldo is used.
Type: string
Default: undefined
osVersion
'waldo:options': {
osVersion: '17.0',
},The operating system version to use (for example, 17.0 or 33.0).
If this option is not specified, the default device configured for the app in Waldo is used.
Type: string
Default: undefined
Language
To set the language for a session you can use the appium:language capability.
This key allows you to specify the language in which the app will run during the session.
{
"capabilities": [{ "appium:language": "fr" }]
}Please note that each device supports a different set of languages. To determine which languages a specific device
supports, you can make a call to the []GET /devices endpoint](https://docs.waldo.com/reference/getdevices)
on https://core.waldo.com and check supportedLanguages.
Type: string
Default: en
Intercept Network
The interceptNetwork field determines whether Waldo intercepts and displays the content of HTTP calls made by the application during a session.
To enable or disable interceptNetwork for a specific session, include it in the waldo:options object during session creation:
{
"capabilities": [{
"waldo:options": {
"interceptNetwork": true
}
}]
}If you don't specify the interceptNetwork field, the default value is the one set on the application level (check here) under the Network Application Configuration section.
This setting applies globally to all sessions for the application.
Type: boolean
Default: The value configured for the application.
Additional commands
In addition to configuring Waldo as a remote WebDriver endpoint this package also adds the following commands on the driver object:
waitForElement
Wait until an element appears that has the property equal to value and returns it.
An error will be thrown if the element can't be found after the timeout.
Example:
const element = await driver.waitForElement('text', 'Hello, World!');Parameters:
propertyName of the property to match on elementsvalueExpected value of the propertytimeoutMaximum time in milliseconds to wait for the element to appear. Default to5000.delayInterval in milliseconds between checks for the element. Default to500.waitForStabilityIf enabled wait for the element position to stabilize before tapping. Default tofalse.
tap
Simulate a 'tap' gesture at the given coordinates.
This is equivalent to the following actions: pointerMove, pointerDown, pause, pointerUp.
Example:
await driver.tap(100, 100);tapElement
Wait until an element appears that has the property equal to value and then tap on it.
An error will be thrown if the element can't be found after the timeout.
Example:
await driver.tapElement('text', 'Skip');propertyName of the property to match on elementsvalueExpected value of the propertytimeoutMaximum time in milliseconds to wait for the element to appear. Default to5000.delayInterval in milliseconds between checks for the element. Default to500.waitForStabilityIf enabled wait for the element position to stabilize before tapping. Default tofalse.
tapElementWith
Wait until an element appears that matches the predicate in the Waldo tree and then tap on it.
An error will be thrown if the element can't be found after the retries.
Example:
await driver.tapElementWith((n) => n.text === 'Skip');ℹ️ Note
This command is only available when using the Waldo automation via the
'waldo:automationName': 'Waldo'capability.
predicateA function that returnstruefor the element to tap onpositionIndex of the element to match if there are multiple matches, or'first'or'last'. Default to0.retriesMaximum number of retries to find the element. Default to3.delayInterval in milliseconds between retries. Default to500.
typeInElement
Wait until an element appears that has the property equal to value and then type text in it.
An error will be thrown if the element can't be found after the timeout.
Example:
await driver.typeInElement('placeholder', 'email address', 'test@example.com');propertyName of the property to match on elementsvalueExpected value of the propertytextThe text to type in the elementtimeoutMaximum time in milliseconds to wait for the element to appear. Default to5000.delayInterval in milliseconds between checks for the element. Default to500.waitForStabilityIf enabled wait for the element position to stabilize before tapping. Default tofalse.
tapCenterOfBox
Simulate a 'tap' gesture at the center of the given bounding box.
Example:
const box = await driver.getNodes((n) => n.text === 'Skip')[0];
await driver.tapCenterOfBox(box);getNodes
Get all nodes in the Waldo tree that match the given predicate
ℹ️ Note
This command is only available when using the Waldo automation via the
'waldo:automationName': 'Waldo'capability.
Example:
const okButtons = await driver.getNodes(
// Find all nodes with a text that contains 'ok' case insensitive
(n) => n.text && n.text.match(/ok/i) !== null,
);getWaldoTree
Parse the current Waldo tree returned by getPageSource() and return it as a JSON object.
ℹ️ Note
This command is only available when using the Waldo automation via the
'waldo:automationName': 'Waldo'capability.
swipeScreen
Simulate a 'swipe' gesture in the given direction.
The default movement without any options is a horizontal swipe from right (95) to left (5).
This is equivalent to the following actions: pointerMove, pointerDown, pause, pointerMove, pointerUp.
Example:
// Swipe from top to bottom
await driver.swipeScreen('vertical', 10, 90);Parameters:
direction: The direction of the swipe, eitherverticalorhorizontal. Default tohorizontal.fromScreenPercent: The starting point of the swipe as a percentage of the screen size. Default to95.toScreenPercent: The ending point of the swipe as a percentage of the screen size. Default to5.
screenshot
A simplified wrapper around the saveScreenshot command that saves the screenshot to a file in the
./screenshots/ directory, creating it if necessary.
ℹ️ Note
If an absolute path is provided, this function is equivalent to calling
saveScreenshotdirectly.
Example:
// Final path will be ./screenshots/screenshot.png
await driver.screenshot('screenshot.png');log
Send a log line that will be visible in the Waldo Session Viewer
Example:
await driver.log('Found logged in user', { name: detectedUserName }, 'debug');Parameters:
message: The message to logpayload: Additional data to log that will be visible when the log line is selected. Default to{}.level: The log level, one ofdebug,info,warn, orerror. Default toinfo.