With wdi5
being a service to WebdriverIO, it provides a superset of wdio
's functionality.
When a control is located via wdi5
, its' methods in Node.js-scope are aligned with those of the UI5 control.
// assuming input is of type sap.m.Input
const input = await browser.asControl(selector)
await input.getValue() // same .getValue in wdi5 and UI5!
Additionally, all object APIs in wdi5
are aligned with their UI5 Managed Object counterpart.
// assuming title is a sap.m.Title
const title = await browser.asControl(selector)
// bindingInfo is a UI5 Managed Object, not a UI5 control!
const bindingInfo = await title.getModel()
const name = await bindingInfo.getProperty("/path/in/model") // same .getProperty in wdi5 and UI5!
?> there is no fluent async api available for both the aligned Managed Object API and .asObject
At the same time, the wdi5
-api can be mixed with wdio
's api during tests at will - there is no restriction to use either one. Even a fluent async transition between the two is possible:
// from wdi5 -> wdio
const htmlInput = await browser.asControl(selector).$().$("input")
await htmlInput.click("") // dummy to bring focus to the <input>
await browser.keys(["Ctrl", "v"])
See below for many more examples on both using wdi5
- and wdio
-APIs, denoting which API is used where.
The files containing tests should reside in $ui5-app/webapp/test/
and be named *.test.(j|t)s
.
Yet both test file directory and naming pattern can be specified via WebdriverIO's specs
in wdio.conf.(j|t)s
.
?> wdi5
can be used both in a CJS- and an ESM-environment. The code examples sometimes use either or, but in no favor of one over the other.
WebdriverIO and wdi5
can be used with Mocha, Jasmine, and Cucumber, with Mocha being used in all examples in wdi5
.
Mocha tests are structured with describe
-blocks ("suite"), containing it
s ("tests"). They can contain hooks, e.g. to run code before all tests (before
).
const { wdi5 } = require("wdio-ui5-service")
describe("test suite description", () => {
before(async () => {
await wdi5.goTo("#/Page")
})
it("should do this", async () => {
const selector = {
/* ... */
}
const prop = await browser.asControl(selector).getProperty("...")
expect(prop).toEqual("...")
})
it("should do that", async () => {
//...
})
})
import { wdi5 } from "wdio-ui5-service"
describe("test suite description", () => {
before(async () => {
await wdi5.goTo("#/Page")
})
it("should do this", async () => {
const selector = {
/* ... */
}
const prop = await browser.asControl(selector).getProperty("...")
expect(prop).toEqual("...")
})
it("should do that", async () => {
//...
})
})
import { wdi5 } from "wdio-ui5-service"
import { wdi5Selector } from "wdio-ui5-service/dist/types/wdi5.types"
describe("test suite description", () => {
before(async () => {
await wdi5.goTo("#/Page")
})
it("should do this", async () => {
const selector: wdi5Selector = {
/* ... */
}
const prop: string = await browser.asControl(selector).getProperty("...")
expect(prop).toEqual("...")
})
it("should do that", async () => {
//...
})
})
Another recommendation is to only use one describe
per test file, named similar to the file name, in order to stay organized.
The entry point to retrieve a control is always await browser.asControl(selector)
(for selector
as locator, see 👇). It transfers the UI control from the browser into the Node.js-scope and make the UI5 control's API available to the test.
Internally, wdi5
uses sap.ui.test.RecordReplay.findDOMElementByControlSelector
to locate the control via a selector.
You can either retrieve the control specifically and subsequently operate on its' UI5 API methods or use the fluent async api to query a specific method:
// retrieve specfically
const control = await browser.asControl(selector)
const text = await control.getText()
const property = await control.getProperty("...")
// use fluent async api
const text = await browser.asControl(selector).getText()
The alternative to browser.asControl
is await browser.allControls(selector)
to retrieve all controls of a certain type.
// get all sap.m.Buttons on that view
const selector = {
selector: {
controlType: "sap.m.Button",
viewName: "test.Sample.view.Main"
}
}
const buttons = await browser.allControls(selector)
// query one of the buttons
const textOfButton1 = await buttons[0].getText()
Internally, wdi5
uses sap.ui.test.RecordReplay.findAllDOMElementsByControlSelector
to locate the UI5 controls.
!> the findAllDOMElementsByControlSelector
UI5 API is only available in UI5 >= 1.87.7, so you can use browser.allControls(...)
only with UI5 (apps) >= 1.87.7
?> the selector
is used to establish a cache for all controls. So when providing the forceSelect: true
selector option, the cache for all controls of that type will be invalidated.
?> there is no fluent async api available for .allControls
.
Switching between wdi5
- and WebdriverIO-API is possible on any of the controls retrieved by allControls
just as it is for a single control located via .asControl
const buttons = await browser.allControls(manySelector)
// $button0 and $button have the WebdriverIO api
const $button0 = await buttons[0].getWebElement()
const $button = await browser.asControl(singleSelector).getWebElement()
If wdi5
detects a UI5 managed object as a result of a method call on a retrieved UI5 control (e.g. await control.getBindingContext()
), it will transparently deliver that object back to Node.js-scope as a wdi5-object
. This allows for an API alignment between Node.js- and browser-/UI5-scope.
?> there is no fluent async api available for .asObject
and for the aligned Managed Object API
The dedicated browser.asObject($uuid)
re-fetches a previously retrieved UI5 Object from the browser-scope. $uuid
can be obtained by querying the UI5 Object with .getUUID()
.
// earlier...
const bindingInfo = await control.getBinding("text")
//...
// later:
const object = await browser.asObject(bindingInfo.getUUID())
const bindingInfoMetadata = await object.getMetadata()
const bindingTypeName = await bindingInfoMetadata.getName()
expect(bindingTypeName).toEqual("sap.ui.model.resource.ResourcePropertyBinding")
The entry point to retrieve a control is always awaiting the async
function browser.asControl(oSelector)
.
oSelector
re-uses the OPA5 control selectors, supplemented by the optional wdio_ui5_key
and forceSelect
properties.
wdi5
stores control references internally in order to save browser roundtrip time on repeatedly using a control across different test cases. For that, wdi5
computes unique identifiers for controls - but providing a wdio_ui5_key
in the selector, you can assign such an ID manually if required.
The forceSelect
(default: false
) property can be set to true
to force wdi5
to again retrieve the control from the browser context and update the internally stored reference as well as available control methods. This might be useful if the tested application has destroyed the initial control and recreated it.
The forceSelect
option also updates the wdio
control reference each time a method is executed on a wdi5
control.
The timeout
option (default based on the global configuration waitForUI5Timeout
setting) controls the maximum waiting time while checking for UI5 availability (meaning no pending requests / promises / timeouts).
The logging
(default: true
) property can be set to false
to disable the log for this specific selector. This can be useful when you want to assert, that specific controls should not be visible on the UI to decrease the amount of pointless error messages.
it("validates that $control's text is ...", async () => {
const oSelector = {
wdio_ui5_key: "wdio-ui5-button", // optional unique internal key to map and find a control
forceSelect: true, // forces the test framework to again retrieve the control from the browser context
timeout: 15000, // maximum waiting time (ms) before failing the search
logging: false, // optional (default: `true`) disables the log for this specific selector
selector: {
// sap.ui.test.RecordReplay.ControlSelector
id: "UI5control_ID",
viewName: "your.namespace.App"
}
}
const control = await browser.asControl(oSelector)
// now use one of the UI5 API methods of `control`
// e.g. assuming UI5 `control` has a `getText()` method:
expect(await control.getText()).toEqual("...")
})
These are the supported selectors from sap.ui.test.RecordReplay.ControlSelector:
selector | supported in wdi5 |
---|---|
ancestor |
✓ |
bindingPath |
✓ |
controlType |
✓ |
descendant |
✓ |
I18NText |
✓ |
id |
✓ |
interactable |
✓ |
labelFor |
✓ |
properties |
✓ |
RegEx |
✓ |
sibling |
✓ |
viewName |
✓ |
?> Please see the dedicated section on "locators" for more usage examples for each locator
/matcher
!
const bindingPathSelector = {
selector: {
// sap.ui.test.RecordReplay.ControlSelector
bindingPath: {
propertyPath: "/Customers('TRAIH')/ContactName"
},
properties: {
value: "Helvetius Nagy"
},
viewName: "test.Sample.view.Main",
controlType: "sap.m.Input"
}
}
const control = await browser.asControl(bindingPathSelector)
// now use one of the below API methods on `control`
Locating a UI5 control via a regular expression works as well:
// select a Button with Id ending in "MyButton"
// across all views in the UI5 app
const crossViewById = {
selector: {
id: /.*MyButton$/
}
}
const control = await browser.asControl(crossViewById)
expect(await control.getVisible()).toBeTruthy()
In case you are not able to create an explicit selector for a control, but you are able to find it via any webdriver strategy, you can use the getSelectorForElement
method. It returns a selector which can subsequently be used in asControl
:
const webdriverLocatorSelector = {
selector: await browser.getSelectorForElement({
domElement: $("/xpath/to/button"),
settings: { preferViewId: true }
})
}
const control = await browser.asControl(webdriverLocatorSelector)
// now use any of the UI5 native controls' API methods on `control`
Once the control is retrieved in a test, use any of the native UI5 control's methods on it.
This is possible because of a runtime proxy wdi5
provides that transistions the UI5 control's methods from browser- to Node.js-runtime.
# terminal 1: run webapp on port 8888
$> npx soerver -d <path/to/webapp> -p 8888
# terminal 2: run test
$> npx wdio run <path/to/conf> --spec <path/to/test>
Execution of 1 spec files started at 2020-08-24T15:49:54.625Z
# ...
# breakpoint is hit after retrieving a control
# in the test via "browser.asControl(buttonSelector)"
# snippet of output of "Object.getOwnPropertyNames(ui5Button)"
length: 220
[
// ...
"extractBindingInfo",
"findAggregatedObjects",
"findElements",
"fireEvent",
"fireFormatError",
"fireModelContextChange",
"fireParseError",
"firePress",
"fireTap",
"fireValidateFieldGroup",
"fireValidationError",
"fireValidationSuccess",
"focus",
// ...
"getBinding",
"getBindingContext",
"getBindingInfo",
"getBindingPath",
"getBlocked",
"getBusy",
"getBusyIndicatorDelay",
"getBusyIndicatorSize",
"getContextMenu",
"getControlsByFieldGroupId",
"getCustomData",
"getDependents",
"getDomRef",
"getDomRefForSetting",
"getDragDropConfig",
// ...
"getLayoutData",
"getModel",
"getObjectBinding",
"getOriginInfo",
"getParent",
"getPopupAnchorDomRef",
"getPropagationListeners",
"getProperty",
"getText",
"getTextDirection",
"getTooltip",
"getTooltip_AsString",
"getTooltip_Text",
"getType",
"getUIArea",
"getVisible",
"getWidth",
"hasListeners",
// ...
]
!> This method bridge does not proxy private control methods (starting with _
), getAggregation
(and getMetadata
) though.
getAggregation
(see below) is provided by wdi5
separately with a UI5-compatible API signature.
getAggregation(sAggregationName) => wdi5Controls[]
: retrieve the elements of aggregation sAggregationName
of a control getAggregation
const control = await browser.asControl(oListSelector)
const ui5ListItems = await control.getAggregation("items")
for (const listItem of ui5ListItems) {
expect(await listItem.getTitle()).not.toBe("")
}
If getAggregation
is called via a shorthand such as sap.m.ListBase.getItems()
, additional convenience functions are available:
-
get$Shorthand(true)
(e.g.getItems(true)
): iftrue
retrieves the aggregation aswebdriver
elements only (not as UI5 controls!). This is a huge performance improvement in case you don't need all elements of the aggregation as fully qualified UI5 controls. -
get$Shorthand(2)
(e.g.getItems(2)
): if set asNumber
, the result array contains a single UI5 control from the aggregation at indexNumber
(here: 2). This is a huge performance improvement in case you dont need all controls of the aggegation as fully qualified UI5 controls, but rather one specific single control.
enterText(text)
: input text
(string
) into a (input-capable) control via EnterText
const control = await browser.asControl(inputSelector)
await control.enterText("new Text")
For (well) pressing a UI5 control (e.g. sap.m.Button
), wdi5
provides the explicit $control.press()
api.
const button = await browser.asControl(buttonSelector)
await button.press()
Under the hoode, this first retrieves the UI5 control, then feeds it to WebdriverIO's click()
method.
You can execute a given function, optionally with arguments, on any UI5 control and return an arbitrary result of a basic type, or even an object or array. This is for example helpful to boost performance when verifying many entries in a single table, since there is only one round trip to the browser to return the data.
The this
keyword will refer to the UI5 control you execute the exec
function on.
Regular functions are accepted as well as arrow functions.
const button = await browser.asControl(buttonSelector)
let buttonText = await button.exec(function () {
//regular function
return this.getText()
})
buttonText = await button.exec(() => this.getText()) //inline arrow function
buttonText = await button.exec(() => {
return this.getText()
}) //arrow function
//passing arguments is possible, example for using it to verify on browser side and returning only a boolean value
const textIsEqualToArguments = await button.exec(
(textHardcodedArg, textVariableArg) => {
return this.getText() === textHardcodedArg && this.getText() === textVariableArg
},
"open Dialog",
expectedText
)
//example what could be done with a list
const listData = await browser.asControl(listSelector).exec(function () {
return {
listTitle: this.getHeaderText(),
listEntries: this.getItems().map((item) => item.getTitle())
}
})
wdi5
supports async
method chaining. This means you can directly call a UI5
control's methods after retrieveing it via browser.asControl(selector)
:
// sap.m.List has .getItems()
// sap.m.StandardListItem has .getTitle()
const title = await browser.asControl(listSelector).getItems(1).getTitle()
// `title` is "Andrew Fuller"
// the long version of the above command would be:
// list = await browser.asControl(listSelector)
// const item = await list.getItems(1)
// const title = await item.getTitle()
Note that chaining only works if you start your call with browser.asControl()
. The fluent async api will not work starting with an already retrieved UI5 element.
The this
context of each step in the async
chain changes to the retrieved/referenced UI5
element.
In the above example:
browser.asControl(listSelector)
exposes thesap.m.List
getItems(1)
exposes asap.m.StandardListItem
getTitle()
delivers astring
The fluent async
api also works with event triggers, such as pressing a sap.m.Button
:
const text = await browser.asControl(button).press().getText()
While this leads to more concise code, bear in mind that (as mentioned above) the this
context changes with every call in the chain. So after arriving at a function returning an atomic value (such as a string
), the reference any UI5
control is lost and the chain can only work on the atomic value:
// on a sap.m.Text
await browser.asControl(text).getText().getMaxLines() // will throw!
// ^
// |
// -----------------------------------
// returns a `string`,
// thus `this` context is the `string` (that doesn't have a getMaxLines method)
// and not `sap.m.Text` anymore
If an item has a custom attribute defined (eg. data:key="exampleKey"
) which is needed in the event handler function, the access of the data()
function to retrieve the key can be done by specifying an eval
property as (object) argument to the event handler.
Can be accessed in standard UI5 manner (await oEvent.getParameter("listItem")).data("key")
.
// example for the [sap.m.List](https://sapui5.hana.ondemand.com/#/api/sap.m.ListBase%23events/itemPress) event `itemPress`
const control = await browser.asControl(listSelector)
await control.fireEvent("itemPress", {
eval: () => {
return {
listItem: {
data: () => {
return "account.relationships"
}
}
}
}
})
Recommendation is to use the Webdriver.IO
-native extension to JEST's expect and matchers as described in https://webdriver.io/docs/assertion.html.
At any point in your test(s), you can screenshot the current state of the UI via browser.screenshot()
:
it("...", async () => {
// ...
await browser.screenshot("some-id")
// ...
})
This puts a png
into the configured wdi5.screenshotPath
(from wdio.conf.js
).
The file name is prepended with a date indicator (M-d-hh-mm-ss
), holds screenshot
in the filename and is appended with the id
you provide (here: some-id
).
Example: 5-5-17-46-47-screenshot--some-id.png
For convenient console output, use wdi5.getLogger('tag')
. It supports the syslog
-like levels log
, info
, warn
and error
:
const { wdi5 } = require("wdio-ui5-service")
wdi5.getLogger().log("any", "number", "of", "log", "parts")
The log level is either set in wdio.conf.js
via wdi5.logLevel
or
by wdi5.getLogger().setLoglevel(level = {string} "error"| "verbose" | "silent")
The 'tag' is an optional parameter and when passed will display logs on the console log with a prefix as follows:
[TAG] any number of log parts
In the test, you can navigate the UI5 webapp via goTo(options)
in one of two ways:
-
updating the browser hash
await browser.goTo({ sHash: "#/test" })
-
using the UI5 router navTo function
await browser.goTo( oRoute: { sComponentId, sName, oParameters, oComponentTargetInfo, bReplace } )
-
also, the
wdi5
helper class exposes the same API, and additionally a "plain" string option for navigating:const { wdi5 } = require("wdio-ui5-service") //... const oRouteOptions = { sComponentId: "container-Sample", sName: "RouteOther" } await wdi5.goTo(oRouteOptions) // or: await wdi5.goTo("#/Other") // or: await wdi5.goTo({ sHash: "#/Other" })
Control info is an object which can be retrieved from any wdi5 control by calling getControlInfo()
. The control information object is loosely based on the UI5 metadata and also contains className
and id
.
The list of attached wdio methods can be found in $
and the UI5 control methods in the property methods
.
These properties can help to identify the received control or test the control correctness.
const button = browser.asControl(oButtonSelector)
const controlInfo = button.getControlInfo() // <--
/*
* id?: string // full UI5 control id as it is in DOM
* methods?: string[] // list of UI5 methods attached to wdi5 control
* className?: string // UI5 class name
* $?: Array<string> // list of UwdioI5 methods attached to wdi5 control
* key?: string // wdio_ui_key
*/
})
There is no tooling included with wdi5
for asserting runtime performance metrics. Reason for this is to keep wdi5
's dependencies to a minimum - plus there are easy to use tools for that job such as marky.
Here's an example test to check the responsiveness via marky
of an application opening a sap.m.Dialog
after a clicking a button:
const marky = require("marky")
// ...
it("test responsiveness of button action", async () => {
marky.mark("start_action")
const response = await browser.asControl(buttonSelector).press().getText()
const entry = marky.stop("stop_action")
// verify the result of the button action
expect(response).toEqual("open Dialog")
// check the duration of the operation
expect(entry.duration).toBeLessThan(3000)
// logger can be used in combination
wdi5.getLogger().info(entry)
}
wdi5
allows for operating multiple browser instances with a single test (suite) - think of a usecase such as "instant messaging test between two people". This is built on top of WebdriverIO's "multiremote" feature of the same name ("running multiple automated sessions in a single test") and provides the same configuration options.
Basic usage: change capabilities
in your wdio.conf.(j|t)s
to
// ...
capabilities: {
one: {
capabilities: {
browserName: "chrome",
acceptInsecureCerts: true
}
},
two: {
capabilities: {
browserName: "chrome",
acceptInsecureCerts: true
}
}
}
// ...
Now you can access each browser instances by calling them by their capabilities
name, using the regular wdi5
APIs browser.asControl($selector)
and browser.allControls($selector)
(just like in "single remote" test):
const button1 = await browser.one.asControl({
selector: {
id: "openDialogButton",
viewName: "test.Sample.view.Main"
}
})
const button2 = await browser.two.asControl({
selector: {
id: "openDialogButton",
viewName: "test.Sample.view.Main"
}
})
Or operate all browser instances at the same time:
const buttonFromAllInstances = await browser.asControl({
selector: {
id: "openDialogButton",
viewName: "test.Sample.view.Main"
}
})
...and get an array of controls back as retrieved by all instances. Subsequently, the control retrieved by each instance is accessible at the array index corresponding to the browser defined in the capabilities
sequence in wdio.conf.(j|t)s
:
const buttonOne = buttonFromAllInstances[0]
const buttonTwo = buttonFromAllInstances[1]
Some example tests are located at /examples/ui5-js-app/webapp/test/e2e/multiremote.test.js
.
The Headless Testing Framework
extension enables you to use the wdi5 capabilities when working in SAP Business Application Studio.
To enable the extension:
-
Add the
Headless Testing Framework
extension to your dev space. This will install a Firefox driver in the dev space. -
Verify that the Firefox driver has been installed correctly using the following commands on the Terminal:
# terminal 1: the Firefox version
$> firefox --version
Mozilla Firefox 102.8.0esr
# terminal 2: the location of the executable
$> which firefox
/extbin/bin/firefox
- Adapt your configuration file (
wdio.conf.(j|t)s
) to run your tests headless.
- Replace
capabilities
with the following code. Thefirefox version
andpath/to/firefox
values appear in the results from the command you ran in the previous step.
// ...
capabilities: [
{
acceptInsecureCerts: true,
browserName: "firefox",
browserVersion: "<firefox version>",
"moz:firefoxOptions": {
binary: "<path/to/firefox>",
args: ["-headless"],
log: { level: "trace" }
}
}
]
// ...
- Replace
sevices
with the following code:
// ...
services: [
[
"geckodriver",
// service options
{
// OPTIONAL: Arguments passed to geckdriver executable.
// Check geckodriver --help for all options. Example:
// ['--log=debug', '--binary=/var/ff50/firefox']
// Default: empty array
args: ["--log=trace"],
// The path where the output of the Geckodriver server should
// be stored (uses the config.outputDir by default when not set).
outputDir: "./logs"
}
],
"ui5"
]
// ...
For example:
// ...
const path = require("path")
exports.config = {
runner: "local",
//
// ====================
// Runner Configuration
// ====================
//
//
// ==================
// Specify Test Files
// ==================
// Define which test specs should run. The pattern is relative to the directory
// from which `wdio` was called.
//
// The specs are defined as an array of spec files (optionally using wildcards
// that will be expanded). The test for each spec file will be run in a separate
// worker process. In order to have a group of spec files run in the same worker
// process simply enclose them in an array within the specs array.
//
// If you are calling `wdio` from an NPM script (see https://docs.npmjs.com/cli/run-script),
// then the current working directory is where your `package.json` resides, so `wdio`
// will be called from there.
//
specs: ["./webapp/test/**/*.test.js"],
// Patterns to exclude.
exclude: [
// 'path/to/excluded/files'
],
//
// ============
// Capabilities
// ============
// Define your capabilities here. WebdriverIO can run multiple capabilities at the same
// time. Depending on the number of capabilities, WebdriverIO launches several test
// sessions. Within your capabilities you can overwrite the spec and exclude options in
// order to group specific specs to a specific capability.
//
// First, you can define how many instances should be started at the same time. Let's
// say you have 3 different capabilities (Chrome, Firefox, and Safari) and you have
// set maxInstances to 1; wdio will spawn 3 processes. Therefore, if you have 10 spec
// files and you set maxInstances to 10, all spec files will get tested at the same time
// and 30 processes will get spawned. The property handles how many capabilities
// from the same test should run tests.
//
maxInstances: 1,
//
// If you have trouble getting all important capabilities together, check out the
// Sauce Labs platform configurator - a great tool to configure your capabilities:
// https://saucelabs.com/platform/platform-configurator
//
capabilities: [
{
acceptInsecureCerts: true,
browserName: "firefox",
browserVersion: "102",
platformName: "linux",
"moz:firefoxOptions": {
binary: "/extbin/bin/firefox",
args: ["-headless"],
log: { level: "trace" }
}
}
],
// If outputDir is provided WebdriverIO can capture driver session logs
// it is possible to configure which logTypes to include/exclude.
// excludeDriverLogs: ['*'], // pass '*' to exclude all driver session logs
// excludeDriverLogs: ['bugreport', 'server'],
wdi5: {
screenshotPath: path.join("wdio-ui5-service", "test", "report", "screenshots"),
logLevel: "verbose",
platform: "browser",
url: "index.html",
deviceType: "web"
},
//
// ===================
// Test Configurations
// ===================
// Define all options that are relevant for the WebdriverIO instance here
//
// Level of logging verbosity: trace | debug | info | warn | error | silent
logLevel: "trace",
//
// Set specific log levels per logger
// loggers:
// - webdriver, webdriverio
// - @wdio/browserstack-service, @wdio/devtools-service, @wdio/sauce-service
// - @wdio/mocha-framework, @wdio/jasmine-framework
// - @wdio/local-runner
// - @wdio/sumologic-reporter
// - @wdio/cli, @wdio/config, @wdio/utils
// Level of logging verbosity: trace | debug | info | warn | error | silent
logLevels: {
webdriver: "trace"
},
//
// If you only want to run your tests until a specific amount of tests have failed use
// bail (default is 0 - don't bail, run all tests).
bail: 0,
//
// Set a base URL in order to shorten url command calls. If your `url` parameter starts
// with `/`, the base url gets prepended, not including the path portion of your baseUrl.
// If your `url` parameter starts without a scheme or `/` (like `some/path`), the base url
// gets prepended directly.
baseUrl: "http:https://localhost:8080/index.html",
//
// Default timeout for all waitFor* commands.
waitforTimeout: 10000,
//
// Default timeout in milliseconds for request
// if browser driver or grid doesn't send response
connectionRetryTimeout: 120000,
//
// Default request retries count
connectionRetryCount: 3,
//
// Test runner services
// Services take over a specific job you don't want to take care of. They enhance
// your test setup with almost no effort. Unlike plugins, they don't add new
// commands. Instead, they hook themselves up into the test process.
//services: ['chromedriver', 'ui5'],
services: [
[
"geckodriver",
// service options
{
// OPTIONAL: Arguments passed to geckdriver executable.
// Check geckodriver --help for all options. Example:
// ['--log=debug', '--binary=/var/ff50/firefox']
// Default: empty array
args: ["--log=trace"],
// The path where the output of the Geckodriver server should
// be stored (uses the config.outputDir by default when not set).
outputDir: "./logs"
}
],
"ui5"
],
before: function (capabilities, specs) {
browser.setWindowSize(1600, 1200)
},
// Framework you want to run your specs with.
// The following are supported: Mocha, Jasmine, and Cucumber
// see also: https://webdriver.io/docs/frameworks
//
// Make sure you have the wdio adapter package for the specific framework installed
// before running any tests.
framework: "mocha",
//
// The number of times to retry the entire specfile when it fails as a whole
// specFileRetries: 1,
//
// Delay in seconds between the spec file retry attempts
// specFileRetriesDelay: 0,
//
// Whether or not retried specfiles should be retried immediately or deferred to the end of the queue
// specFileRetriesDeferred: false,
//
// Test reporter for stdout.
// The only one supported by default is 'dot'
// see also: https://webdriver.io/docs/dot-reporter
reporters: ["spec"],
//
// Options to be passed to Mocha.
// See the full list at http:https://mochajs.org/
mochaOpts: {
ui: "bdd",
timeout: 60000
}
}
// ...
See the documentation for more information on the webdriver configuration.
- Make sure that UI5 app is running and Run the tests using the
wdio run wdio.conf.js
command.