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
SAP Mentor
SAP Mentor
1,683
Watching dj.adams.sap walk through the latest SAP devs community challenge, it was evident that the "profilepic" UI5 app was missing some tests. Why not put in some wdi5 end-to-end testing flavor? What I thought would be a low hanging fruit to pick turned out to hold quite some challenges:

  1. use in an ES module environment

  2. navigate an FLP tile

  3. conducting a file upload

  4. asserting a file download


But: got all of the above covered with wdi5 💪

Here‘s how.
(note: all of the following will also go in the new "recipes" section of the soon-to-launch new wdi5 documentation site)
(note 2: grab the source over at https://github.com/vobu/sap-community-code-challenge and code-view along)
(note 3: do npm i && npm start in one terminal, then npm test in another to have the test run)


use in an ES module environment


As Thomas Jung had set the project up to live in ESM land, wdi5 had to adhere to that at config- and runtime. This was easy to solve: just a rename of the config- and test-file to a .cjs extension to let the Node.js runtime know we're a CJS module. No coding changes required.

The project launches as a mocked Fiori Launchpad (FLP). Given the FLP is also a UI5 app, wdi5‘s standard mechanism of retrieving controls could be used in the tests.
Via the text property matcher, the tile‘s label is located (a sap.m.Text).
const tile = await browser
.asControl({
selector: {
properties: {
text: "SAP Community Profile Picture Editor"
},
controlType: "sap.m.Text"
}
})

Then we navigate up the control tree with the help of wdi5's fluent async api until we reach the tile itself via .getParent().getParent().
A click on it brings us to the profilepic app itself.
// get wdio element reference
const $tile = await tile.getWebElement()
// use wdio api
await $tile.click()

Why not locating that tile itself directly? Because it doesn‘t use a stable ID, and thus its‘ ID might change in the next UI5 rendering cycle - using a locator id such as __tile0 might break the test eventually then.

conducting a file upload


This part shows wdi5’s excellent foundation, Webdriver.IO (wdio), playing in unison with wdi5.
First, we utilize wdi5 to retrieve the file uploader control.
const uploader = await browser.asControl({
forceSelect: true,
selector: {
id: "fileToUpload",
viewName: "profilePic.view.App"
}
})

Then we use wdio to get the file input element. As per the WebDriver spec, this is the one DOM element capable of receiving a programmatic file upload.
const $uploader = await uploader.getWebElement()
const $fileInput = await $uploader.$("input[type=file]")
await $fileInput.setValue(file)

After doing this, wdi5‘s api is used again to assert that the file was uploaded and to press the enhance/upload button.
// assert the upload
const uploadedImage = await uploader.getValue()
expect(uploadedImage).toEqual(fileName)
// trigger pic enhancement
await browser
.asControl({
selector: {
id: "button",
viewName: "profilePic.view.App"
}
})
.firePress() // this will go away with wdi5 0.9.0 and replaced by .press()

Volià!

asserting a file download


Now time to unpack the bag of tricks for doing and validating a file download.
Chromedriver offers some custom settings that help preparing things.

The config is set so that

  • no download dialog appears

  • a static download dir exists


// in wdio.conf.cjs
"goog:chromeOptions": {
prefs: {
directory_upgrade: true,
prompt_for_download: false,
"download.default_directory": join(__dirname, "test", "__assets__")
}
}

Then the download is triggered via pressing the respective UI5 button.
// wdi5
await browser
.asControl({
selector: {
id: "downloadButton",
viewName: "profilePic.view.App"
}
})
.firePress() // this will go away with wdi5 0.9.0 and replaced by .press()

After the download completes, standard Node.js mechanisms are used to validate the downloaded file in the static download directory specified.
const downloadedFile = join(__dirname, "__assets__", "image.png") // by the books, getting the image name dynamically would be a thing
// stat is from
// const { stat } = require("node:fs/promises")
expect(await (await stat(downloadedFile)).size).toBeGreaterThan(1)

bonus: chrome debug tools


Wouldn't it be cool to have Chrome's debug tool available at test-time to eventually look under the hood while tests are executing? Rhetoric question, of course it would.

This can be achieve with wdi5/wdio by providing a respective flag to the browser config:
// in wdio.conf.cjs
"goog:chromeOptions": {
args: process.env.DEBUG ? ["--auto-open-devtools-for-tabs"] : []
}

If you now execute the test with the DEBUG env var set, e.g. via DEBUG=true npm test, then the debug pane opens.


All in all, quite a concert: wdi5, Webdriver.IO, Chrome and Node.js playing together nicely to test advanced functionality in a UI5 app.
What‘s not to like?!
1 Comment
Labels in this area