### Quick wdi5 Dev Setup (Shell) Source: https://github.com/ui5-community/wdi5/blob/main/docs/contributing.md A sequence of commands for a quick wdi5 development setup, including using the reference Node.js version, installing dependencies, and starting the build watcher. ```shell # use reference node version $> nvm use # will also install all deps in workspaces + setup pre-commit hooks $> npm i # turn on build watcher for both esm and cjs $> npm run build:watch ``` -------------------------------- ### Start WebdriverIO Guided Setup (shell) Source: https://github.com/ui5-community/wdi5/blob/main/docs/installation.md Execute the `npx wdio` command to initiate the interactive WebdriverIO configuration process, including the installation of services like wdi5. ```shell $> npx wdio ``` -------------------------------- ### Starting Sample UI5 App (Shell) Source: https://github.com/ui5-community/wdi5/blob/main/docs/contributing.md Command to start the sample JavaScript UI5 application used for testing wdi5 functionality. ```shell # start the sample js app $> npm run _startApp:js ``` -------------------------------- ### Install wdi5 Dependencies (Shell) Source: https://github.com/ui5-community/wdi5/blob/main/docs/contributing.md Command to install all project dependencies, including those in workspaces and setting up pre-commit hooks. ```shell $> npm install ``` -------------------------------- ### Initialize wdi5 Project with Custom Options (JavaScript) - Shell Source: https://github.com/ui5-community/wdi5/blob/main/docs/installation.md Initialize a wdi5 project with custom configuration options using `npm init wdi5`. This example shows how to specify a custom config path, test file glob pattern, and base URL for a JavaScript project. ```shell $> npm init wdi5@latest --configPath some/sub/folder/ \ --specs ./my/test/**/*.js \ --baseUrl http://localhost:4004/app/index.html ``` -------------------------------- ### Initialize wdi5 Project (JavaScript) - Shell Source: https://github.com/ui5-community/wdi5/blob/main/docs/installation.md Use `npm init wdi5` to quickly set up a wdi5 project in a JavaScript environment. This command installs dependencies, creates a default config file (`wdio.conf.js`), and adds an npm script. ```shell $> cd any/ui5/app $> npm init wdi5@latest ``` -------------------------------- ### Start UI5 App for Testing (Shell) Source: https://github.com/ui5-community/wdi5/blob/main/docs/contributing.md Runs the sample UI5 JavaScript application using an npm script. This application serves as the target under test for wdi5 end-to-end tests. ```Shell npm run _startApp:js ``` -------------------------------- ### Change Directory for Guided Install (shell) Source: https://github.com/ui5-community/wdi5/blob/main/docs/installation.md Navigate to the root directory of your UI5 application in the terminal before starting the guided WebdriverIO setup. ```shell $> cd any/ui5/app ``` -------------------------------- ### Start wdi5 Build Watcher (Shell) Source: https://github.com/ui5-community/wdi5/blob/main/docs/contributing.md Command to start the build watcher, which automatically transpiles TypeScript files on changes. ```shell $> npm run build:watch ``` -------------------------------- ### Running Webapp and Test with wdi5 Source: https://github.com/ui5-community/wdi5/blob/main/docs/usage.md These terminal commands show how to start a local web server for the UI5 application using `soerver` and then execute the wdi5 tests using `wdio run`. ```zsh # terminal 1: run webapp on port 8888 $> npx soerver -d -p 8888 # terminal 2: run test $> npx wdio run --spec 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", // ... ] ``` -------------------------------- ### Initialize wdi5 Project (TypeScript) - Shell Source: https://github.com/ui5-community/wdi5/blob/main/docs/installation.md Use `npm init wdi5 -- --ts` to set up a wdi5 project for a TypeScript environment. This installs dependencies, creates config files (`wdio.conf.ts`, `tsconfig.json`) in a `test` folder, and adds an npm script. ```shell $> cd any/ui5/app $> npm init wdi5@latest -- --ts # yeah, it's "-- --ts" b/c of the way # `npm init` works: # https://docs.npmjs.com/cli/v8/commands/npm-init#forwarding-additional-options ``` -------------------------------- ### Testing Performance with marky and wdi5 Source: https://github.com/ui5-community/wdi5/blob/main/docs/usage.md Provides an example test case demonstrating how to use the 'marky' library in conjunction with wdi5 to measure the duration of a UI action and assert its responsiveness. ```js 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) } ``` -------------------------------- ### Reinitialize WebdriverIO Configuration (shell) Source: https://github.com/ui5-community/wdi5/blob/main/docs/installation.md Run the `npx wdio config` command to re-run the guided configuration wizard, useful for fixing issues or changing setup options. ```shell $> npx wdio config ``` -------------------------------- ### Initialize wdi5 Project with Custom Options (TypeScript) - Shell Source: https://github.com/ui5-community/wdi5/blob/main/docs/installation.md Initialize a wdi5 project for TypeScript with custom configuration options using `npm init wdi5 -- --ts`. This example shows how to specify a custom config path, test file glob pattern, and base URL for a TypeScript project. ```shell $> npm init wdi5@latest -- --ts --configPath some/other/folder/ \ --specs ./ts-tests/**/*.test.ts \ --baseUrl http://localhost:4004/ts-app/index.html ``` -------------------------------- ### wdi5 Logger Output Example with Tag Source: https://github.com/ui5-community/wdi5/blob/main/docs/usage.md Shows the format of the console output when a tag is provided to the wdi5 logger. ```cmd [TAG] any number of log parts ``` -------------------------------- ### Initializing Reveal.js Presentation Source: https://github.com/ui5-community/wdi5/blob/main/docs/presentation/wdi5-presentation.html Initializes the Reveal.js presentation framework. Sets the 'hash' option to true and loads the Markdown, Highlight, and Notes plugins. This setup is typically used for creating interactive slide decks. ```JavaScript // More info about initialization & config: // - https://revealjs.com/initialization/ // - https://revealjs.com/config/ Reveal.initialize({ hash: true, // Learn about plugins: https://revealjs.com/plugins/ plugins: [RevealMarkdown, RevealHighlight, RevealNotes] }) ``` -------------------------------- ### Execute wdi5 Test Directly with npx wdio (Shell) Source: https://github.com/ui5-community/wdi5/blob/main/docs/contributing.md Navigates to a sample application directory and runs a specific wdi5 test file using the locally installed `wdio` command via `npx`. This provides an alternative method for executing tests without relying on the npm script wrapper. ```Shell cd examples/ui5-js-app npx wdio run wdio-ui5tooling.conf.js --spec ./webapp/test/e2e/basic.test.js ``` -------------------------------- ### Install wdi5 Manually (shell) Source: https://github.com/ui5-community/wdi5/blob/main/docs/installation.md Use npm to install the wdi5 service (`wdio-ui5-service`) as a development dependency in your project. ```shell $> npm install --save-dev wdio-ui5-service ``` -------------------------------- ### Use Reference Node.js Version (Shell) Source: https://github.com/ui5-community/wdi5/blob/main/docs/contributing.md Command using nvm to switch to the recommended Node.js version for wdi5 development. ```shell $> nvm use ``` -------------------------------- ### Build wdi5 Project (Shell) Source: https://github.com/ui5-community/wdi5/blob/main/docs/contributing.md Command to perform a one-time build of the wdi5 project, transpiling TypeScript to JavaScript. ```shell $> npm run build ``` -------------------------------- ### Conventional Commit Message Format Example (Shell) Source: https://github.com/ui5-community/wdi5/blob/main/docs/contributing.md Illustrates the required format for Git commit messages used in the project, adhering to conventional commits guidelines. It shows the structure including type, optional scope, subject, body, and footer. ```Shell wip(optional scope): the subject of the message optional body some more text optional 1-line footer ``` -------------------------------- ### Bootstrap SAPUI5 Core and Render UShell (JavaScript) Source: https://github.com/ui5-community/wdi5/blob/main/examples/fe-app/webapp/index.html Attaches an initialization function to the SAPUI5 core's init event. Upon initialization, it creates the SAP Fiori Launchpad renderer and places it into the DOM element with the ID 'content', effectively starting the application within the UShell sandbox. ```JavaScript sap.ui.getCore().attachInit(function () { sap.ushell.Container.createRenderer().placeAt("content") }) ``` -------------------------------- ### Add ui5 Service to wdio.conf.js (JavaScript) Source: https://github.com/ui5-community/wdi5/blob/main/docs/installation.md Include the `'ui5'` service string within the `services` array in your WebdriverIO configuration file (`wdio.conf.js` or `wdio.conf.ts`) to enable wdi5. ```javascript //... services: [ // ... "ui5" ] //... ``` -------------------------------- ### Sample Verbose Output from wdi5 Test Library - Bash Source: https://github.com/ui5-community/wdi5/blob/main/docs/fe-testlib.md Provides an example of the detailed output generated by the wdi5 test library when the `logLevel` is set to "verbose". This output is useful for troubleshooting test failures by showing internal steps and checks performed by the test framework and Opa5. ```bash Error: the string "Checking table '{id: fe::table::Products::LineItem}' having 2 rows with values='', state='' and empty columns='' - FAILURE Opa timeout after 15 secosds This is what Opa logged: Found 0 blocking out of 613 tracked timeouts - sap.ui.test.autowaiter._timeoutWaiter#hasPending AutoWaiter syncpoint - sap.ui.test.autowaiter._autoWaiter Found view with ID 'product.manage::ProductsList' and viewName 'undefined' - sap.ui.test.Opa5 Found control with ID 'fe::table::Products::LineItem' and controlType 'sap.ui.mdc.Table' in view 'sap.fe.templates.ListReport.ListReport' - sap.ui.test.Opa5 1 out of 1 controls met the matchers pipeline requirements - sap.ui.test.pipelines.MatcherPipeline 0 out of 1 controls met the matchers pipeline requirements - sap.ui.test.pipelines.MatcherPipeline Matchers found no controls so check function will be skipped - sap.ui.test.Opa5 ... ``` -------------------------------- ### Change Directory for Manual Install (shell) Source: https://github.com/ui5-community/wdi5/blob/main/docs/installation.md Change into the directory containing your existing WebdriverIO configuration file before manually installing wdi5. ```shell $> cd any/ui5/app ``` -------------------------------- ### Retrieving Control Information in wdi5 Source: https://github.com/ui5-community/wdi5/blob/main/docs/usage.md Explains how to get detailed information about a wdi5 control using the 'getControlInfo()' method and describes the properties available in the returned object. ```js 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 // list of UwdioI5 methods attached to wdi5 control * key?: string // wdio_ui_key */ }) ``` -------------------------------- ### Using FioriElementsFacade for Standard Actions (JavaScript) Source: https://github.com/ui5-community/wdi5/blob/main/docs/fe-testlib.md Demonstrates how to use the `FioriElementsFacade.execute` method to perform standard SAP Fiori Elements actions like searching, creating, editing, saving, and navigation within test cases. It shows examples for interacting with filter bars, tables, forms, footers, and the shell. ```javascript it("I search product 'Office Plant'", async () => { await FioriElementsFacade.execute((Given, When, Then) => { When.onTheMainPage.onFilterBar().iChangeSearchField("Office Plant").and.iExecuteSearch() Then.onTheMainPage.onTable().iCheckRows(3) }) }) it("I trigger create product", async () => { await FioriElementsFacade.execute((Given, When, Then) => { When.onTheMainPage.onTable().iExecuteAction("Create") Then.onTheDetailPage.iSeeThisPage() }) }) it("I enter product details", async () => { await FioriElementsFacade.execute((Given, When, Then) => { When.onTheDetailPage .onForm("General Information") .iChangeField("Product", productId) .and.iChangeField("Category", "Office Plants") Then.onTheDetailPage.iSeeThisPage() }) }) it("I create and save the product", async () => { await FioriElementsFacade.execute((Given, When, Then) => { When.onTheDetailPage.onFooter().iExecuteSave() Then.onTheDetailPage.onHeader().iCheckEdit({ visible: true }) }) }) it("I navigate back to list report", async () => { await FioriElementsFacade.execute((Given, When, Then) => { When.onTheShell.iNavigateBack() Then.onTheMainPage.iSeeThisPage() }) }) ``` -------------------------------- ### Example wdi5 Selector Structure - JavaScript Source: https://github.com/ui5-community/wdi5/blob/main/docs/locators.md Demonstrates the basic structure of a wdi5 selector object, including the `wdio_ui5_key`, `forceSelect`, and the nested `selector` object which contains the actual locators/matchers like `i18NText`, `controlType`, and `viewName`. Shows how to retrieve and interact with a control using this selector. ```javascript // this is the overall selector const identifier = { wdio_ui5_key: "someCustomIdInWdi5Test", forceSelect: true, // this is the locator/matcher (sorry for not naming it as such 😨) selector: { i18NText: { propertyName: "text", key: "startPage.navButton.text" }, controlType: "sap.m.Button", viewName: "test.Sample.view.Main" } } // get it const control = await browser.asControl(identifier) // use it await control.press() ``` -------------------------------- ### Initialize Fiori Elements Facade (wdi5) Source: https://github.com/ui5-community/wdi5/blob/main/docs/fe-testlib.md Initializes the FioriElementsFacade object, which is the entry point for using the Fiori Elements test library functions within wdi5 tests. This setup is typically done once before the test suite runs, providing configuration details about the Fiori Elements application's components and entity sets. ```javascript before(async () => { FioriElementsFacade = await browser.fe.initialize({ onTheMainPage: { ListReport: { appId: 'sap.fe.demo.travellist', // MANDATORY: Compare sap.app.id in manifest.json componentId: 'TravelList', // MANDATORY: Compare sap.ui5.routing.targets.id in manifest.json entitySet: 'Travel' // MANDATORY: Compare entityset in manifest.json } }, onTheDetailPage: { ObjectPage: { ... } }, onTheShell: { Shell: {} } }) }) ``` -------------------------------- ### Mocha Test Suite Structure (JS CJS) Source: https://github.com/ui5-community/wdi5/blob/main/docs/usage.md Provides a basic structure for a Mocha test suite using `wdi5` in a CommonJS environment. It includes importing `wdi5`, defining a `describe` block for the suite, a `before` hook for setup (like navigating), and `it` blocks for individual tests, demonstrating control retrieval and assertion. ```js 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 () => { //... }) }) ``` -------------------------------- ### Pasting into HTML Input via wdi5 and wdio - JavaScript Source: https://github.com/ui5-community/wdi5/blob/main/docs/recipes.md Demonstrates how to get a UI5 control using wdi5, then access a native HTML input element within it using wdio's '$()' method. It shows how to click the input to give it focus and then use 'browser.keys()' to simulate pasting from the clipboard. ```javascript // get the UI5 control via wdi5, then "subselect" the native HTML input field const htmlInput = await browser.asControl(selector).$().$("input") await htmlInput.click("") // dummy to bring focus to the await browser.keys(["Ctrl", "v"]) // paste! ``` -------------------------------- ### Mocha Test Suite Structure (JS ESM) Source: https://github.com/ui5-community/wdi5/blob/main/docs/usage.md Provides a basic structure for a Mocha test suite using `wdi5` in an ES Module environment. It includes importing `wdi5`, defining a `describe` block for the suite, a `before` hook for setup (like navigating), and `it` blocks for individual tests, demonstrating control retrieval and assertion. ```js 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 () => { //... }) }) ``` -------------------------------- ### Mocha Test Suite Structure (TypeScript) Source: https://github.com/ui5-community/wdi5/blob/main/docs/usage.md Provides a basic structure for a Mocha test suite using `wdi5` in TypeScript. It includes importing `wdi5` and necessary types, defining a `describe` block for the suite, a `before` hook for setup (like navigating), and `it` blocks for individual tests, demonstrating control retrieval with type annotations and assertion. ```ts 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 () => { //... }) }) ``` -------------------------------- ### Locating Control by Properties (JavaScript) Source: https://github.com/ui5-community/wdi5/blob/main/docs/locators.md Illustrates how to refine control selection by specifying one or more of the control's properties within the selector. This example finds a button based on its `icon` property and asserts its text. ```javascript it("should find a button by the icon property", async () => { const selectorWithIconProperty = { selector: { controlType: "sap.m.Button", viewName: "test.Sample.view.Main", properties: { icon: "sap-icon://forward" } } } const buttonText = await browser.asControl(selectorWithIconProperty).getText() expect(buttonText).toEqual("to Other view") }) ``` -------------------------------- ### Late Injection of wdi5 Service Source: https://github.com/ui5-community/wdi5/blob/main/docs/configuration.md This JavaScript snippet demonstrates how to manually inject the `wdi5` service at a later point in the test execution flow. This is useful when the test scenario starts on non-UI5 pages and `wdi5` is only needed once a UI5 page is reached. It requires setting the `skipInjectUI5OnStart` option to `true`. ```javascript const { default: _ui5Service } = require("wdio-ui5-service") const ui5Service = new _ui5Service() // later in a test step: await ui5Service.injectUI5() ``` -------------------------------- ### Accessing Control Across All wdi5 Multiremote Instances (JS) Source: https://github.com/ui5-community/wdi5/blob/main/docs/usage.md Shows how to query for a UI5 control across all configured browser instances simultaneously in a wdi5 multiremote setup. Calling `browser.asControl` directly returns an array containing the control instance found in each browser. ```js const buttonFromAllInstances = await browser.asControl({ selector: { id: "openDialogButton", viewName: "test.Sample.view.Main" } }) ``` -------------------------------- ### Configure Chrome Headless Mode in wdio.conf.js Source: https://github.com/ui5-community/wdi5/blob/main/docs/recipes.md Configure the Chrome browser capability in the WebdriverIO configuration file (wdio.conf.js) to run in headless mode. This is useful for CI environments. The example also shows how to set a specific window size. ```javascript exports.config = { wdi5: { // ... }, // ... capabilities: [ { maxInstances: 5, browserName: "chrome", acceptInsecureCerts: true, "goog:chromeOptions": { args: ["--window-size=1440,800", "--headless"] // <-- } } ] } ``` -------------------------------- ### Configure SAP Cloud IdP (BTP) Single Browser Authentication Source: https://github.com/ui5-community/wdi5/blob/main/docs/authentication.md Provides a specific configuration example for authenticating against the default SAP BTP Identity Provider for a single browser. It shows the mandatory "provider" setting ("BTP") and optional selectors for username, password, and submit button. ```javascript baseUrl: "https://your-deployed-ui5-on-btp.app", capabilities: { // browserName: "..." "wdi5:authentication": { provider: "BTP", //> mandatory usernameSelector: "#j_username", //> optional; default: "#j_username" passwordSelector: "#j_password", //> optional; default: "#j_password" submitSelector: "#logOnFormSubmit" //> optional; default: "#logOnFormSubmit" } } ``` -------------------------------- ### Setting wdi5 Multiremote Credentials (Shell) Source: https://github.com/ui5-community/wdi5/blob/main/docs/authentication.md Illustrates how to set environment variables for providing credentials in a wdi5 multiremote setup. The variable names must follow the pattern `wdi5_$browserInstanceName_username` and `wdi5_$browserInstanceName_password`, where `$browserInstanceName` matches the key used in the capabilities configuration. ```shell # multiremote browser capability config is "one" wdi5_one_username='brian@kernighan.org' wdi5_one_password='/.,/.,' # multiremote browser capability config is "two" wdi5_two_username='steve@bourne.org' wdi5_two_password='bourne' # multiremote browser capability config is "nix" wdi5_nix_username='dennis@ritchie.org' wdi5_nix_password='dmac' ``` -------------------------------- ### Retrieve UI5 Control with asControl (JavaScript) Source: https://github.com/ui5-community/wdi5/blob/main/docs/usage.md Demonstrates two ways to use `browser.asControl(selector)`: first, retrieving the control object and then calling its methods; second, using the fluent async API to directly call a method on the result of `asControl`. This method is the primary way to get a single UI5 control in wdi5. ```javascript // 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() ``` -------------------------------- ### Configuring wdi5 Multiremote Capabilities in wdio.conf.js (JS) Source: https://github.com/ui5-community/wdi5/blob/main/docs/usage.md Configures WebdriverIO's multiremote feature within the wdi5 test setup by defining multiple browser instances (e.g., 'one', 'two') under the 'capabilities' property in the wdio.conf.(j|t)s file. Each instance can have its own browser configuration. ```js // ... capabilities: { one: { capabilities: { browserName: "chrome", acceptInsecureCerts: true } }, two: { capabilities: { browserName: "chrome", acceptInsecureCerts: true } } } // ... ``` -------------------------------- ### Validate Downloaded File Size with Node.js Source: https://github.com/ui5-community/wdi5/blob/main/docs/recipes.md Uses Node.js file system promises to get the statistics of a downloaded file located in a predefined directory. It then asserts that the file size is greater than 1 byte, confirming that a file was successfully downloaded and is not empty. ```javascript 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) ``` -------------------------------- ### Configure SAP Cloud IdP (BTP) Multiremote Authentication Source: https://github.com/ui5-community/wdi5/blob/main/docs/authentication.md Demonstrates how to configure authentication against the default SAP BTP Identity Provider for multiple browser instances in a multiremote setup. Each browser instance's capabilities block includes the "wdi5:authentication" settings with the "BTP" provider and optional selectors. ```javascript baseUrl: "https://your-deployed-ui5-on-btp.app", capabilities: { // "one" is the literal reference to a browser instance one: { capabilities: { // browserName: "..." "wdi5:authentication": { provider: "BTP", //> mandatory usernameSelector: "#j_username", //> optional; default: "#j_username" passwordSelector: "#j_password", //> optional; default: "#j_password" submitSelector: "#logOnFormSubmit" //> optional; default: "#logOnFormSubmit" } } }, // "two" is the literal reference to a browser instance two: { capabilities: { // browserName: "..." "wdi5:authentication": { provider: "BTP", //> mandatory usernameSelector: "#j_username", //> optional; default: "#j_username" passwordSelector: "#j_password", //> optional; default: "#j_password" submitSelector: "#logOnFormSubmit" //> optional; default: "#logOnFormSubmit" } } } } ``` -------------------------------- ### Configure Client Certificate Authentication - wdi5 Single Browser - JavaScript Source: https://github.com/ui5-community/wdi5/blob/main/docs/authentication.md Configures wdi5 capabilities for client certificate authentication using an SAP Passport in a single browser setup. Requires wdi5 >= 2. Specifies the Certificate provider, the origin and URL for the certificate, the path to the PFX file, and the passphrase (recommended via environment variable). ```JavaScript baseUrl: "https://your-deployed-ui5-on-btp.app", capabilities: { // browserName: "..." "wdi5:authentication": { provider: "Certificate", certificateOrigin: "https://accounts.sap.com", // this should always be accounts.sap.com certificateUrl: "https://emea.cockpit.btp.cloud.sap/cockpit#/", // this is opened in the browser for authentication, if not specified the configured `baseUrl` is used certificatePfxPath: "./sap.pfx", certificatePfxPassword: process.env.SAPPFX_PASSPHRASE } } ``` -------------------------------- ### Using wdi5 Helper for Navigation Source: https://github.com/ui5-community/wdi5/blob/main/docs/usage.md Demonstrates using the 'wdi5' helper class's 'goTo' method for navigation, showing options for route objects, plain hash strings, and hash objects. ```javascript 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" }) ``` -------------------------------- ### Re-fetching UI5 Object with asObject (JavaScript) Source: https://github.com/ui5-community/wdi5/blob/main/docs/usage.md Demonstrates how to use `browser.asObject($uuid)` to retrieve a UI5 managed object previously obtained from a control method call (like `getBinding`). The example shows getting a binding object, obtaining its UUID, and then using `asObject` to re-fetch it and access its metadata. ```javascript // 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") ``` -------------------------------- ### package.json Configuration for wdi5 Source: https://github.com/ui5-community/wdi5/blob/main/docs/configuration.md This JSON snippet shows recommended entries for the `scripts` and `devDependencies` sections in a UI5 application's `package.json` file. It includes scripts to run `wdio` tests and lists `wdio-ui5-service` as a development dependency. ```json { "name": "ui5-app", // ... "scripts": { // ... "test": "wdio run wdio.conf.js --headless", "wdi5": "wdio run wdio.conf.js" // ... }, "devDependencies": { // ... "wdio-ui5-service": "*" } // ... } ``` -------------------------------- ### Configure SAP Fiori Launchpad Sandbox (JavaScript) Source: https://github.com/ui5-community/wdi5/blob/main/examples/fe-app/webapp/index.html Configures the SAP Fiori Launchpad sandbox environment by setting the default renderer and defining an application entry point. This allows testing UI5 applications within a simulated Launchpad shell. ```JavaScript window["sap-ushell-config"] = { defaultRenderer: "fiori2", applications: { "fe-lrop-v4": { title: "Incidents Management", description: "SAP Fiori elements", additionalInformation: "SAPUI5.Component=sap.fe.demo.incidents", applicationType: "URL", url: "./", navigationMode: "embedded" } } } ``` -------------------------------- ### Checking Firefox Version in BAS Terminal (Shell) Source: https://github.com/ui5-community/wdi5/blob/main/docs/usage.md Provides the shell command to check the installed version of the Firefox browser within the SAP Business Application Studio terminal. This is a verification step after installing the Headless Testing Framework extension. ```shell # terminal 1: the Firefox version $> firefox --version Mozilla Firefox 102.8.0esr ``` -------------------------------- ### Using wdi5 Logger in JavaScript Source: https://github.com/ui5-community/wdi5/blob/main/docs/usage.md Demonstrates how to obtain and use the wdi5 logger instance to output messages with various parts. Explains the basic 'log' method usage. ```javascript const { wdi5 } = require("wdio-ui5-service") wdi5.getLogger().log("any", "number", "of", "log", "parts") ``` -------------------------------- ### Configure wdi5 for SAP Build Workzone (Basic) - JS/TS Source: https://github.com/ui5-community/wdi5/blob/main/docs/fe-testlib.md Shows the basic wdi5 configuration required to enable support for SAP Build Workzone, standard edition, by setting the `btpWorkZoneEnablement` flag to `true`. It also includes setting the `logLevel` to "verbose". ```js // typescript syntax sample export const config: wdi5Config = { wdi5: { btpWorkZoneEnablement: true, logLevel: "verbose" } // ... additional config } ``` -------------------------------- ### Initialize wdi5 Fiori Elements Facade in Workzone - JS/TS Source: https://github.com/ui5-community/wdi5/blob/main/docs/fe-testlib.md Demonstrates how to initialize the wdi5 Fiori Elements facade (`browser.fe.initialize`) within a test suite's `before` hook when testing in SAP Build Workzone. It defines page objects for a CAP SFLIGHT app, including List Report and Object Pages, and shows a basic test execution using the facade. ```js // sample page obects from the CAP SFLIGHT app describe("drive in Work Zone with testlib support", () => { let FioriElementsFacade before(async () => { FioriElementsFacade = await browser.fe.initialize({ onTheMainPage: { ListReport: { appId: "sap.fe.cap.travel", componentId: "TravelList", entitySet: "Travel" } }, onTheDetailPage: { ObjectPage: { appId: "sap.fe.cap.travel", componentId: "TravelObjectPage", entitySet: "Travel" } }, onTheItemPage: { ObjectPage: { appId: "sap.fe.cap.travel", componentId: "BookingObjectPage", entitySet: "Booking" } }, onTheShell: { Shell: {} } }) }) it("...", async () => { await FioriElementsFacade.execute((Given, When, Then) => { Then.onTheMainPage.iSeeThisPage() }) }) // further its }) ``` -------------------------------- ### Configure SAP Fiori Launchpad Shell (JavaScript) Source: https://github.com/ui5-community/wdi5/blob/main/examples/fe-app/webapp/test/flpSandbox.html This JavaScript object assigns the configuration for the SAP Fiori Launchpad shell to the global window object. It defines the default renderer, includes the Runtime Authoring plugin (with validation disabled for testing), configures the fiori2 renderer, and registers an application tile named 'incidents-tile'. The configuration includes a note about being non-secure for testing purposes. ```javascript window["sap-ushell-config"] = { defaultRenderer: "fiori2", bootstrapPlugins: { RuntimeAuthoringPlugin: { component: "sap.ushell.plugins.rta", config: { validateAppVersion: false } } }, renderers: { fiori2: { componentData: { config: { search: "hidden" } } } }, applications: { "incidents-tile": { title: "Incident Management", description: "SAP Fiori elements", additionalInformation: "SAPUI5.Component=sap.fe.demo.incidents", applicationType: "URL", url: "../" } } } // NON-SECURE setting for testing environment ``` -------------------------------- ### Configure wdi5 Certificate Authentication (Multiremote) Source: https://github.com/ui5-community/wdi5/blob/main/docs/authentication.md Configures wdi5 for certificate-based authentication in a multiremote setup. Specifies the certificate provider, origin, URL for authentication, certificate path, and password environment variable. ```Javascript baseUrl: "https://your-deployed-ui5-on-btp.app", capabilities: { // "one" is the literal reference to a browser instance one: { capabilities: { // browserName: "..." "wdi5:authentication": { provider: "Certificate", certificateOrigin: "https://accounts.sap.com", // default value for certificateOrigin is accounts.sap.com, should not be changed certificateUrl: "https://emea.cockpit.btp.cloud.sap/cockpit#/", // this is opened in the browser for authentication, if not specified the configured `baseUrl` is used certificatePfxPath: "./sap.pfx", certificatePfxPassword: process.env.SAPPFX_PASSPHRASE } } }, // "two" is the literal reference to a browser instance two: { capabilities: { // browserName: "..." "wdi5:authentication": { provider: "Certificate", certificateOrigin: "https://accounts.sap.com", // default value for certificateOrigin is accounts.sap.com, should not be changed certificateUrl: "https://emea.cockpit.btp.cloud.sap/cockpit#/", // this is opened in the browser for authentication, if not specified the configured `baseUrl` is used certificatePfxPath: "./sap.pfx", certificatePfxPassword: process.env.SAPPFX_PASSPHRASE } } } } ``` -------------------------------- ### Running Single wdi5 Test in Watch Mode (Shell) Source: https://github.com/ui5-community/wdi5/blob/main/docs/contributing.md Command to execute a specific wdi5 test file in watch mode, keeping the browser open and rerunning the test on file changes for TDD. ```shell # run a single test with wdi5/wdio ### runs the "test:websever" script from /examples/ui5-js-app/package.json ### in workspace "examples/ui5-js-app" ### but only the one test file (./webapp/test/e2e/basic.test.js) ### in watch mode (browser stays open, test reruns when file changes) ### for true TDD $> npm run test:webserver \ -w examples/ui5-js-app \ -- --spec ./webapp/test/e2e/basic.test.js \ --watch ``` -------------------------------- ### Selecting Control by Regex ID (JavaScript) Source: https://github.com/ui5-community/wdi5/blob/main/docs/usage.md Shows how to use a regular expression within the `id` property of a selector to find a control. This example finds a button whose ID ends with 'MyButton' across all views. ```javascript // 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() ``` -------------------------------- ### Configure wdi5 Office 365 Authentication (Multiremote) Source: https://github.com/ui5-community/wdi5/blob/main/docs/authentication.md Configures wdi5 for Office 365 authentication in a multiremote setup. Specifies the provider and optional selectors for username, password, submit button, and the 'stay signed in' option for each browser instance. ```Javascript baseUrl: "https://your-deployed-ui5-with-o365-idp.app", capabilities: { // "one" is the literal reference to a browser instance one: { capabilities: { // browserName: "..." "wdi5:authentication": { provider: "Office365", //> mandatory usernameSelector: "[name=loginfmt]", //> optional; default: "[name=loginfmt]" passwordSelector: "[name=passwd]", //> optional; default: "[name=passwd]" submitSelector: "[data-report-event=Signin_Submit]", //> optional; default: "[data-report-event=Signin_Submit]" staySignedIn: true //> optional: whether the "Stay Signed In?"-checkbox should be checked; default: true } } }, // "two" is the literal reference to a browser instance two: { capabilities: { // browserName: "..." "wdi5:authentication": { provider: "Office365", //> mandatory usernameSelector: "[name=loginfmt]", //> optional; default: "[name=loginfmt]" passwordSelector: "[name=passwd]", //> optional; default: "[name=passwd]" submitSelector: "[data-report-event=Signin_Submit]", //> optional; default: "[data-report-event=Signin_Submit]" staySignedIn: true //> optional: whether the "Stay Signed In?"-checkbox should be checked; default: true } } } } ``` -------------------------------- ### Configure wdi5 Office 365 Authentication (Single Browser) Source: https://github.com/ui5-community/wdi5/blob/main/docs/authentication.md Configures wdi5 for Office 365 authentication in a single browser setup. Specifies the provider and optional selectors for username, password, submit button, and the 'stay signed in' option. ```Javascript baseUrl: "https://your-deployed-ui5-with-o365-idp.app", capabilities: { // browserName: "..." "wdi5:authentication": { provider: "Office365", //> mandatory usernameSelector: "[name=loginfmt]", //> optional; default: "[name=loginfmt]" passwordSelector: "[name=passwd]", //> optional; default: "[name=passwd]" submitSelector: "[data-report-event=Signin_Submit]", //> optional; default: "[data-report-event=Signin_Submit]" staySignedIn: true //> optional: whether the "Stay Signed In?"-checkbox should be checked; default: true } } ``` -------------------------------- ### Navigating via Browser Hash in wdi5 Source: https://github.com/ui5-community/wdi5/blob/main/docs/usage.md Illustrates how to use the 'browser.goTo' method to navigate within the UI5 application by updating the browser's URL hash. ```javascript await browser.goTo({ sHash: "#/test" }) ``` -------------------------------- ### Navigating via UI5 Router navTo in wdi5 Source: https://github.com/ui5-community/wdi5/blob/main/docs/usage.md Shows how to use the 'browser.goTo' method to navigate using the UI5 router's 'navTo' functionality, providing route options. ```javascript await browser.goTo( oRoute: { sComponentId, sName, oParameters, oComponentTargetInfo, bReplace } ) ``` -------------------------------- ### Locating Control by ControlType and Properties - wdi5 JavaScript Source: https://github.com/ui5-community/wdi5/blob/main/docs/locators.md Demonstrates how to find a specific control (`sap.m.StandardListItem`) by combining its `controlType` with specific `properties`, such as the `title`. This is a common way to uniquely identify controls. The example retrieves the title and asserts it matches the expected value. ```javascript it("get a specific list item", async () => { const selectorWithTitleProperty = { selector: { controlType: "sap.m.StandardListItem", viewName: "test.Sample.view.Other", properties: { title: "Margaret Peacock" } } } const titleFromListItem = await browser.asControl(selectorWithTitleProperty).getTitle() expect(titleFromListItem).toEqual("Margaret Peacock") }) ``` -------------------------------- ### Configure Devtools Protocol (wdio.conf.ts) Source: https://github.com/ui5-community/wdi5/blob/main/docs/migration.md Demonstrates how to explicitly configure the `devtools` automation protocol in `wdio.conf.ts` by adding the `automationProtocol` property. This is required when using the devtools protocol with `wdi5` v2. ```diff diff export const config: wdi5Config = { baseUrl: "https://your-app", services: ["ui5"], specs: [resolve("test/e2e/Protocol.test.ts")], + automationProtocol: "devtools", capabilities: [ { //... } ] } ``` -------------------------------- ### Configuring wdi5 Multiremote Basic Authentication (JS) Source: https://github.com/ui5-community/wdi5/blob/main/docs/authentication.md Configures Basic Authentication for multiple browser instances in a wdi5 multiremote setup. Each instance's capabilities must specify the 'BasicAuth' provider and can optionally list specific URLs where Basic Authentication should be used. ```js baseUrl: "https://caution_your-deployed-ui5-with-basic-auth.app", capabilities: { // "one" is the literal reference to a browser instance one: { capabilities: { // browserName: "..." "wdi5:authentication": { provider: "BasicAuth", //> mandatory basicAuthUrls: ["https://your-custom-basic-auth-endpoint"] //> optional: default is the configured `baseUrl` } } }, // "two" is the literal reference to a browser instance two: { capabilities: { // browserName: "..." "wdi5:authentication": { provider: "BasicAuth", //> mandatory basicAuthUrls: ["https://your-custom-basic-auth-endpoint"] //> optional: default is the configured `baseUrl` } } } } ``` -------------------------------- ### Using browser.asControl with Options (JavaScript) Source: https://github.com/ui5-community/wdi5/blob/main/docs/usage.md Demonstrates how to use `browser.asControl` with a detailed selector object including optional properties like `wdio_ui5_key`, `forceSelect`, `timeout`, and `logging`. It shows how to retrieve a UI5 control and then call one of its methods, like `getText()`, for assertion. ```javascript 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("...") }) ``` -------------------------------- ### Configuring wdi5 Multiremote Custom Authentication (JS) Source: https://github.com/ui5-community/wdi5/blob/main/docs/authentication.md Configures custom authentication for multiple browser instances in a wdi5 multiremote setup. It requires specifying the 'custom' provider and CSS selectors for the username input, password input, and submit button for each browser instance. ```js baseUrl: "https://your-deployed-ui5-with-custom-idp.app", capabilities: { // "one" is the literal reference to a browser instance one: { capabilities: { // browserName: "..." "wdi5:authentication": { provider: "custom", //> mandatory usernameSelector: "input[id='username']", //> mandatory passwordSelector: "input[id='password']", //> mandatory submitSelector: "button[type='submit']" //> mandatory } } }, // "two" is the literal reference to a browser instance two: { capabilities: { // browserName: "..." "wdi5:authentication": { provider: "custom", //> mandatory usernameSelector: "input[id='username']", //> mandatory passwordSelector: "input[id='password']", //> mandatory submitSelector: "button[type='submit']" //> mandatory } } } } ``` -------------------------------- ### Configure baseUrl for ui5-tooling Source: https://github.com/ui5-community/wdi5/blob/main/docs/configuration.md This diff snippet shows the recommended change to replace the deprecated `wdi5.url` configuration with the standard `baseUrl` for applications served using `ui5-tooling`. The `baseUrl` should point directly to the application's entry HTML file. ```diff - wdi5: { - url: "index.html" - }, - baseUrl: "http://localhost:8080" + baseUrl: "http://localhost:8080/index.html" ```