Technology Blogs by Members
Explore a vibrant mix of technical expertise, industry insights, and tech buzz in member blogs covering SAP products, technology, and events. Get in the mix!
cancel
Showing results for 
Search instead for 
Did you mean: 
vobu
Active Contributor
2,102
wdi5 just received its major version bump, providing full compatibility with WebdriverIO v8 and offering some new features. Migration from v1 is a minimal effort.

New features


wdio^8 compatiblity


With wdi5 being a “service” aka extension to WebdriverIO (wdio), it is now compatible with wdio version 8. Aside from having all features of v8 available, this results in the usage option of wdi5 as CJS- and ESM-module and in a TypeScript environment.

No matter the environment, npm init wdi5@latest will jumpstart setting up wdi5 and get you all ESM- & CJS- or TS-runtime files. Albei configuration in all environments is the same.

The programmatic usage of the wdi5 API differs though. A minimal CJS example - e.g. a UI5 JavaScript app bootstrapped with the help of the easy-ui5 generator:
// this is CJS
const { wdi5 } = require("wdio-ui5-service")
describe("...", () => {
it("...", async () => {
await browser.asControl(...).someMethod()
wdi5.getLogger().info("hello CJS!")
})
})

An ESM example is the same for the describe and it structure, but uses a different “import” syntax for wdi5:
// this is ESM
import { wdi5 } from "wdio-ui5-service"
describe("...", () => {
it("...", async () => {
await browser.asControl(...).someMethod()
const Logger = wdi5.getLogger("esm!")
Logger.log("Hello ESM World!")
})
}

Similar for TypeScript - import syntax is the same, yet we have the option to type things:
import Input from "sap/m/Input"
import { wdi5, wdi5Selector } from "wdio-ui5-service"

const Logger = wdi5.getLogger()

const inputSelector: wdi5Selector = {
selector: {
id: "mainUserInput",
viewName: "test.Sample.tsapp.view.Main"
}
}

describe("...", () => {
it("...", async () => {
const input = await browser.asControl<Input>(inputSelector)
const value = await input.getValue()
expect(value).toEqual("Helvetius Nagy")
Logger.info("Hello TypeScript World!")
})
}

All code samples above are from the examples folder in the wdi5 repository. We’re “dogfooding” wdi5 in the sense of using wdi5 (with sample applications) to test wdi5 itself.

Currently you’ll find in the /examples folder:

That’s why it is always a good idea to look into our sample applications to get some copy-pasta recipes inspiration for your own tests 😄

simplified browser setup


In wdi5^1, it was necessary to specify both the browser and the browser driver for running wdi5 tests. So the Node.js runtime could launch the configured browser and then execute the tests with it:
// in wdio.conf.js
exports.config = {
// ...
capabilities: [{ browserName: "chrome" }],
// ...
services: ["chromedriver", "ui5"], //> "ui5" denotes wdi5
// ...
}

As of wdi5^2, this is no more. Thanks to the excellent improvement in wdio itself, specifying the browserName is sufficient. wdio/wdi5 will download the appropriate binaries or re-use the ones installed on the system wdi5 is running on:
// in wdio.conf.js
exports.config = {
// ...
capabilities: [{ browserName: "safari"}], //> enough for on the fly browser switching
// ...
services: ["ui5"], //> "ui5" denotes wdi5, no more "*-driver"
// ...
}

Note that his is an optional change - wdi5^2 will continue to work also with explicitly denoting the browser driver in services!

enhanced protocol support


En lieu of revisiting the code-base for the 2.0 release, we put in some safeguards for stale DOM elements. An element can become stale if its representation in the DOM is updated while the test is running. A common scenario for this is if a previously retrieved UI5 control is hidden as part of the application logic. Now checking for the state of that UI5 control doesn’t fault the entire test run any more:
it("safeguard 'stale' invisible element", async () => {
// no "forceSelect" in the buttonSelector!
const button = await browser.asControl(buttonSelector)
expect(await button.isInitialized()).toBe(true)
// or: expect(await button.getVisible()).toBeTruthy()

// make the element stale by manipulation DOM
await button.setVisible(false)

// the DOM element is no more -> can't be retrieved
// but the test won't implode
expect(await button.getVisible()).toBe(null)

const invisibleButton = await browser.asControl(buttonSelector)
// we should receive nothing => null
expect(await invisibleButton.getVisible()).toBe(null)
// wdi5 control should be there but ui5 control is not initialized
expect(await invisibleButton.isInitialized()).toBe(false)
})

The above applies to both the devtools- and the WebDriver-protocol.

In addition, wdi5 now allows for using BiDi as the third automation protocol. BiDi is a W3C standard for remote controlling a browser that combines the benefits of the devtool's speed with the cross-browser-support of WebDriver. BiDi is still in its early stages, yet is promising to be the go-to standard with backings from all major browser vendors.

A simple wdio/wdi5 example using BiDi looks like:
describe("bidi", async () => {
it("accessing console.log in the browser", async () => {
let browserConsoleLog

await browser.send({
method: "session.subscribe",
params: { events: ["log.entryAdded"] }
})

/**
* returns: {"method":"log.entryAdded","params":{"type":"console","method":"log","realm":null,"args":[{"type":"string","value":"Hello Bidi at UI5con23!"}],"level":"info","text":"Hello Bidi at UI5con23!","timestamp":1657282076037}}
*/
browser.on("message", (data) => {
browserConsoleLog = JSON.parse(data.toString()).params.text
expect(browserConsoleLog).toBe(msg)
})

const msg = "Hello BiDi!"
await browser.executeScript(`console.log("${msg}")`, [])
})
})

SAP Build Work Zone support


Specific to the SAP environment, wdi5 now supports

  • being bootstrapped in a Work Zone environment

  • authentication against Work Zone’s IdP

  • switching between Work Zone’s shell- and app-area


When used within the Work Zone domain, wdi5 needs to be bootstrapped accordingly, using the new btpWorkZoneEnablement config option. Additionally, an extension to the existing BTP authentication provider needs to be configured:
export const config: wdi5Config = {
wdi5: {
btpWorkZoneEnablement: true,
logLevel: "verbose"
},
// note the "hash"ed URL part at the end pointing to the app!
baseUrl: "https://your.launchpad.cfapps.eu10.hana.ondemand.com/site/you#travel-process"
capabilities: [
{
"wdi5:authentication": {
provider: "BTP",
disableBiometricAuthentication: true,
idpDomain: "custom-ias-domain.accounts.ondemand.com"
}
}
],
}

Please also note that baseUrl needs to point to the UI5 app under test, including the “hashed” part of the URL (#travel-process in the example config above)!

btpWorkZoneEnablement enables using wdi5 both in the shell- and the app-area of WorkZone, which is also reflected in the logs:
[wdi5] delegating wdi5 injection to WorkZone enablement...
# ...
[wdi5] injected wdi5 into the WorkZone std ed's shell!
[wdi5] injected wdi5 into the WorkZone std ed's iframe containing the target app!

The complementary authentication setting allows wdi5 to set a cookie to that the test workflow is not canceled by prompting for biometric characteristics.

Finally, the convenience methods toWorkZoneShell() and toWorkZoneApp() do what their name suggests:
import { wdi5 } from "wdio-ui5-service"
describe("drive in Work Zone with standard wdi5/wdio APIs", () => {
it("shell", async () => {
await wdi5.toWorkZoneShell() // <-- now the context is in the shell area
await browser
.asControl<sap.m.Avatar>({
selector: {
id: "userActionsMenuHeaderButton"
}
})
.press()
// ...
})

it("should find the table in the travel app", async () => {
await wdi5.toWorkZoneApp() // <-- now the context is with the actual app
const table = await browser.asControl<sap.ui.mdc.Table>({
selector: {
id: "sap.fe.cap.travel::TravelList--fe::table::Travel::LineItem"
}
})
// ...
})
//...
})

There’s a full recipe for running wdi5 in SAP Build Work Zone, standard edition, published in the documentation: https://ui5-community.github.io/wdi5/#/recipes?id=navigate-in-sap-build-workzone

CAP basic auth support


SAP’s Cloud Application Programming model provides out of the box Basic Auth for quickly getting up and running with Authentication at dev tim.... In wdi5^2, running automated end to end tests during development is now possible thanks to an extension of the BasicAuth provider:
// in wdio config file
capabilities: {
// browserName: "..."
"wdi5:authentication": {
provider: "BasicAuth",
basicAuthUrls: [
"http://localhost:4004/odata/v4/myEndpoint/$metadata",
"http://localhost:4004/odata/v4/myOtherEndpoint/$metadata"
]
}
}

The above lets wdi5 authenticate not only against the UI5 app, but also against the provided OData URLs, satisfying @requires annotations of CAP services.

Migration from v1


For most projects, there should be little to no changes required for upgrading wdi5 from version 1 to 2. As we’ve moved the WebdriverIO base modules into the peerDependencies, any transient dependencies should be easier to resolve for the package manager of your choice.

The update itself requires wdi5 to be bumped to v2 and all WebdriverIO-related packages to v8. Either do this manually, e.g. by specifying the respective major semver…
// in package.json
{
"devDependencies": {
"@ui5/cli": "^3",
"@wdio/cli": "^8",
"@wdio/local-runner": "^8",
"@wdio/mocha-framework": "^8",
"@wdio/spec-reporter": "^8",
"wdio-ui5-service": "^2"
}
}

…or by using a convenience tool such as npm-check-updates:
$> ncu                      
Checking /Users/you/com.myorg.myapp/package.json
[====================] 16/16 100%

@wdio/cli ^7.32.4 → ^8.16.10
@wdio/local-runner ^7.32.4 → ^8.16.10
@wdio/mocha-framework ^7.30.2 → ^8.16.10
@wdio/spec-reporter ^7.31.1 → ^8.16.9
wdio-chromedriver-service ^7.3.2 → ^8.1.1
wdio-ui5-service ^1.5.6 → ^2.0.0

Run ncu -u to upgrade package.json

In terms of functional changes, the determination of the path to the test (”spec”) files has changes in WebdriverIO v8, which wdi5 needs to adhere to. The directory references start from the directory the config file is in now, not from cwd or project root. More details can be found in the Migration Guide in the wdi5 documentation.

Quickstart also at v2


To cater to new requirements with wdi5 v2, the quickstart tool (npm init wdi5) was adjusted - and also published as major version 2 to clearly indicate the relation to wdi5 2.x.

Two major differences to the v1 quickstart:

  1. the config file (wdio.conf.(j|t)s) is now placed within the default test directory ($ui5-app/webapp/test/e2e/) to better separate concerns. Previously, it was put into the root directory of the UI5 app.

  2. a sample test file is now included, either in TypeScript- or JavaScript, depending on the bootstrap flavour used (npm init wdi5@latest -- --ts or npm init wdi5@latest)


That’s it, folks! wdi5^2 is out, hopefully making the lot of you happy 😅

There’s an extensive test suite in place, breaking changes were avoided and the docs got completely overhauled. Yet history proves that any major version change is a risk - so please watch your setup carefully when upgrading to wdi5 2.x. And in case you’re in need of dedicated support or want to greatly change scope of your Test Infrastructure, there’s commercial support available for wdi5!

A final “Thank You” to the WebdriverIO community for providing such giant shoulders to build and stand on - and to you, the UI5- and wdi5-community, for helping to grow the tool.
Onwards and upwards!
2 Comments
Labels in this area