Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiremote support for TestLibrary #489

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion examples/fe-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
"main": "webapp/index.html",
"scripts": {
"deploy": "npx -p @sap/ux-ui5-tooling fiori add deploy-config cf",
"test": "karma start --singleRun",
"test": "run-s test:*",
"test:multiremote": "wdio run wdio-multiremote.conf.js --headless",
"test:wdi5": "wdio run wdio.conf.js --headless",
"serve": "ui5 serve --port 8088"
},
Expand Down
63 changes: 63 additions & 0 deletions examples/fe-app/wdio-multiremote.conf.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
const { join } = require("path")

exports.config = {
wdi5: {
screenshotPath: join("app", "incidents", "webapp", "wdi5-test", "__screenshots__"),
logLevel: "verbose", // error | verbose | silent
waitForUI5Timeout: 30000
},
//// wdio runner config
specs: [join("webapp", "wdi5-test", "**/Multiremote.test.js")],
// Patterns to exclude.
exclude: [],
//// capabilities ("browser") config
maxInstances: 10,
capabilities: {
one: {
capabilities: {
browserName: "chrome",
acceptInsecureCerts: true,
"goog:chromeOptions": {
args:
process.argv.indexOf("--headless") > -1
? ["window-size=1440,800", "--headless"]
: process.argv.indexOf("--debug") > -1
? ["window-size=1920,1280", "--auto-open-devtools-for-tabs"]
: ["window-size=1440,800"]
}
}
},
two: {
capabilities: {
browserName: "chrome",
acceptInsecureCerts: true,
"goog:chromeOptions": {
args:
process.argv.indexOf("--headless") > -1
? ["window-size=1440,800", "--headless"]
: process.argv.indexOf("--debug") > -1
? ["window-size=1920,1280", "--auto-open-devtools-for-tabs"]
: ["window-size=1440,800"]
}
}
}
},
//// test config
// Level of logging verbosity: trace | debug | info | warn | error | silent
logLevel: "error",
bail: 0,
baseUrl: "http://localhost:8088/index.html#fe-lrop-v4",

waitforTimeout: 10000,
connectionRetryTimeout: 120000,
connectionRetryCount: 3,

services: ["chromedriver", "ui5"],

framework: "mocha",
mochaOpts: {
ui: "bdd",
timeout: 120000
},
reporters: ["spec"]
}
2 changes: 1 addition & 1 deletion examples/fe-app/wdio.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ exports.config = {
//// wdio runner config
specs: [join("webapp", "wdi5-test", "**/*.test.js")],
// Patterns to exclude.
exclude: [],
exclude: [join("webapp", "wdi5-test", "**/Multiremote.test.js")],
//// capabilities ("browser") config
maxInstances: 10,
capabilities: [
Expand Down
40 changes: 40 additions & 0 deletions examples/fe-app/webapp/wdi5-test/Multiremote.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
describe("FE basics", () => {
let FioriElementsFacades
before(async () => {
FioriElementsFacades = await browser.fe.initialize({
onTheMainPage: {
ListReport: {
appId: "sap.fe.demo.incidents",
componentId: "IncidentsList",
entitySet: "Incidents"
}
},
onTheDetailPage: {
ObjectPage: {
appId: "sap.fe.demo.incidents",
componentId: "IncidentsObjectPage",
entitySet: "Incidents"
}
},
onTheShell: {
Shell: {}
}
})
})

it("should trigger search on ListReport page on browser one and two", async () => {
await FioriElementsFacades.one.execute((Given, When, Then) => {
Given.onTheMainPage.onFilterBar().iExecuteSearch()
Then.onTheMainPage.onTable().iCheckRows(12)
Then.onTheMainPage.onTable().iCheckRows({ identifier: "inc_0002", title: "Password Reset" })
When.onTheMainPage.onTable().iPressRow({ identifier: "inc_0002" })
})

await FioriElementsFacades.two.execute((Given, When, Then) => {
Given.onTheMainPage.onFilterBar().iExecuteSearch()
Then.onTheMainPage.onTable().iCheckRows(12)
Then.onTheMainPage.onTable().iCheckRows({ identifier: "inc_0002", title: "Password Reset" })
When.onTheMainPage.onTable().iPressRow({ identifier: "inc_0002" })
})
})
})
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
"test:cucumber": "npm run test --workspace=examples/cucumber",
"test-h:ts-app": "run-p -r _startApp:ts _test-h:ts-app",
"test:js-app": "run-p -r _startApp:js _startApp:js-tooling _test:js-app",
"_test:fe-app": "wait-on tcp:8088 && npm run test:wdi5 --workspace=examples/fe-app",
"_test:fe-app": "wait-on tcp:8088 && npm run test --workspace=examples/fe-app",
"test:fe-app": "run-p -r _startApp:fe _test:fe-app",
"//test:auth": "this runs either locally or on browserstack depending on the env variable BROWSERSTACK",
"test:auth": "npm run test:authentication:bstack -w examples/ui5-ts-app",
Expand Down
4 changes: 2 additions & 2 deletions src/lib/wdi5-bridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,8 @@ function initBrowser(browserInstance: WebdriverIO.Browser) {

_addWdi5Commands(browserInstance)

if (!(browserInstance as any).fe) {
;(browserInstance as any).fe = WDI5FE
if (!(browser as any).fe) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hm, browserInstance is explicitly passed in here → why is it not supposed to be used? IMO the browserInstance helps retain scope within the fn by explicitly not referencing the global browser

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then we would have to initialize the facade as often as we have defined browsers in the config. That would look like something like this:

fioriElementsFacadeOne = await one.fe.initialize{...}

fioriElementsFacadeTwo = await two.fe.initialize{...}

We can do that of course, I just don't now if this is the best way

;(browser as any).fe = WDI5FE
}

_setupComplete = true
Expand Down
18 changes: 14 additions & 4 deletions src/lib/wdi5-fe.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { initOPA, addToQueue, emptyQueue, loadFELibraries } from "../../client-side-js/testLibrary"
import { Logger as _Logger } from "./Logger"
import { MultiRemoteDriver } from "webdriverio/build/multiremote"
const Logger = _Logger.getInstance()

const commonFunctions = ["and", "when", "then"]
Expand All @@ -24,10 +25,19 @@ function createProxy(myObj: any, type: string, methodCalls: any[], pageKeys: str
}
export class WDI5FE {
constructor(private appConfig: any, private browserInstance: any) {}
static async initialize(appConfig, browserInstance = browser) {
await loadFELibraries(browserInstance)
await initOPA(appConfig, browserInstance)
return new WDI5FE(appConfig, browserInstance)
static async initialize(appConfig) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

similar here - why remove browserInstance as parameter and instead break scope of the otherwise "pure" function?

Copy link
Collaborator Author

@Siolto Siolto Jun 20, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we never passed the second parameter to the initialize function. We only passed the config and just took the default for browserInstance

We could stick to that pattern, but then we have to pass the relevant browserInstance for the multiRemote in the before hook:

before(async () => {
        FioriElementsFacade = await browser.fe.initialize({appconfig}, browserInstance)
})

I guess we just have to decide what is cleaner

if (browser instanceof MultiRemoteDriver) {
// create for every instance a new facade and load all relevant libraries
return (browser["instances"] as []).reduce(async (facade, browserName) => {
await loadFELibraries(browser[browserName])
await initOPA(appConfig, browser[browserName])
return Object.assign(await facade, { [browserName]: new WDI5FE(appConfig, browser[browserName]) })
}, {})
} else {
await loadFELibraries(browser)
await initOPA(appConfig, browser)
return new WDI5FE(appConfig, browser)
}
}

async execute(fnFunction) {
Expand Down