Skip to content
New issue

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

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

Already on GitHub? # to your account

feat: using custom waitForUI5 with callbacks instead of Promises #217

Merged
Merged
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ dist/**/*
# multi-version test artifacts
examples/ui5-js-app/wdio-wdi5*
examples/ui5-js-app/webapp/index-*.html
examples/ui5-js-app/dist/**/*


# .env
Expand Down
113 changes: 60 additions & 53 deletions client-side-js/executeControlMethod.js
Original file line number Diff line number Diff line change
@@ -1,68 +1,75 @@
async function clientSide_executeControlMethod(webElement, methodName, args) {
return await browser.executeAsync(
(webElement, methodName, args, done) => {
window.bridge.waitForUI5(window.wdi5.waitForUI5Options).then(() => {
// DOM to UI5
const oControl = window.wdi5.getUI5CtlForWebObj(webElement)
// execute the function
let result = oControl[methodName].apply(oControl, args)
const metadata = oControl.getMetadata()
if (Array.isArray(result)) {
if (result.length === 0) {
done(["success", result, "empty"])
} else if (result[0]?.getParent) {
// expect the method call delivers non-primitive results (like getId())
// but delivers a complex/structured type
// -> currenlty, only getAggregation(...) is supported
window.wdi5.waitForUI5(
window.wdi5.waitForUI5Options,
() => {
// DOM to UI5
const oControl = window.wdi5.getUI5CtlForWebObj(webElement)
// execute the function
let result = oControl[methodName].apply(oControl, args)
const metadata = oControl.getMetadata()
if (Array.isArray(result)) {
if (result.length === 0) {
done(["success", result, "empty"])
} else if (result[0]?.getParent) {
// expect the method call delivers non-primitive results (like getId())
// but delivers a complex/structured type
// -> currenlty, only getAggregation(...) is supported

// read classname eg. sap.m.ComboBox
controlType = oControl.getMetadata()._sClassName
// read classname eg. sap.m.ComboBox
controlType = oControl.getMetadata()._sClassName

result = window.wdi5.createControlIdMap(result, controlType)
done(["success", result, "aggregation"])
} else {
done(["success", result, "result"])
}
} else {
// ui5 api <control>.focus() doesn't have return value
if (methodName === "focus" && result === undefined) {
done([
"success",
`called focus() on wdi5 representation of a ${metadata.getElementName()}`,
"element"
])
} else if (result === undefined || result === null) {
done([
"error",
`function ${methodName} does not exist on control ${metadata.getElementName()}!`,
"none"
])
} else {
// result mus be a primitive
if (window.wdi5.isPrimitive(result)) {
// getter
result = window.wdi5.createControlIdMap(result, controlType)
done(["success", result, "aggregation"])
} else {
done(["success", result, "result"])
}
} else {
// ui5 api <control>.focus() doesn't have return value
if (methodName === "focus" && result === undefined) {
done([
"success",
`called focus() on wdi5 representation of a ${metadata.getElementName()}`,
"element"
])
} else if (result === undefined || result === null) {
done([
"error",
`function ${methodName} does not exist on control ${metadata.getElementName()}!`,
"none"
])
} else {
// object, replacer function
// TODO: create usefull content from result
// result = JSON.stringify(result, window.wdi5.circularReplacer());

// check if of control to verify if the method result is a different control
if (result && result.getId && oControl.getId() !== result.getId()) {
// ui5 function like get parent might return another ui5 control -> return it to check with this wdi5 instance
result = window.wdi5.createControlId(result)
done(["success", result, "newElement"])
// result mus be a primitive
if (window.wdi5.isPrimitive(result)) {
// getter
done(["success", result, "result"])
} else {
done([
"success",
`instance of wdi5 representation of a ${metadata.getElementName()}`,
"element"
])
// object, replacer function
// TODO: create usefull content from result
// result = JSON.stringify(result, window.wdi5.circularReplacer());

// check if of control to verify if the method result is a different control
if (result && result.getId && oControl.getId() !== result.getId()) {
// ui5 function like get parent might return another ui5 control -> return it to check with this wdi5 instance
result = window.wdi5.createControlId(result)
done(["success", result, "newElement"])
} else {
done([
"success",
`instance of wdi5 representation of a ${metadata.getElementName()}`,
"element"
])
}
}
}
}
},
(error) => {
window.wdi5.Log.error("[browser wdi5] ERR: ", error)
done(["error", error.toString()])
}
})
)
},
webElement,
methodName,
Expand Down
50 changes: 29 additions & 21 deletions client-side-js/fireEvent.js
Original file line number Diff line number Diff line change
@@ -1,29 +1,37 @@
async function clientSide_fireEvent(webElement, eventName, oOptions) {
return await browser.executeAsync(
(webElement, eventName, oOptions, done) => {
window.bridge.waitForUI5(window.wdi5.waitForUI5Options).then(() => {
window.wdi5.Log.info("[browser wdi5] working " + eventName + " for " + webElement)
// DOM to ui5
let oControl = window.wdi5.getUI5CtlForWebObj(webElement)
if (oControl && oControl.hasListeners(eventName)) {
window.wdi5.Log.info("[browser wdi5] firing " + eventName + " on " + webElement)
// element existent and has the target event
try {
// eval the options indicated by option of type string
if (typeof oOptions === "string") {
oOptions = eval(oOptions)()
const errorHandling = () => {
window.wdi5.Log.error("[browser wdi5] couldn't find " + webElement)
done(["error", false])
}

window.wdi5.waitForUI5(
window.wdi5.waitForUI5Options,
() => {
window.wdi5.Log.info("[browser wdi5] working " + eventName + " for " + webElement)
// DOM to ui5
let oControl = window.wdi5.getUI5CtlForWebObj(webElement)
if (oControl && oControl.hasListeners(eventName)) {
window.wdi5.Log.info("[browser wdi5] firing " + eventName + " on " + webElement)
// element existent and has the target event
try {
// eval the options indicated by option of type string
if (typeof oOptions === "string") {
oOptions = eval(oOptions)()
}
oControl.fireEvent(eventName, oOptions)
// convert to boolean
done(["success", true])
} catch (e) {
done(["error", e.toString()])
}
oControl.fireEvent(eventName, oOptions)
// convert to boolean
done(["success", true])
} catch (e) {
done(["error", e.toString()])
} else {
errorHandling()
}
} else {
window.wdi5.Log.error("[browser wdi5] couldn't find " + webElement)
done(["error", false])
}
})
},
errorHandling
)
},
webElement,
eventName,
Expand Down
43 changes: 24 additions & 19 deletions client-side-js/getControl.js
Original file line number Diff line number Diff line change
@@ -1,31 +1,36 @@
async function clientSide_getControl(controlSelector) {
controlSelector = await Promise.resolve(controlSelector) // to plug into fluent async api
return await browser.executeAsync((controlSelector, done) => {
const errorHandling = (error) => {
window.wdi5.Log.error("[browser wdi5] ERR: ", error)
done(["error", error.toString()])
}

const waitForUI5Options = Object.assign({}, window.wdi5.waitForUI5Options)
if (controlSelector.timeout) {
waitForUI5Options.timeout = controlSelector.timeout
}
window.bridge
.waitForUI5(waitForUI5Options)
.then(() => {
window.wdi5.waitForUI5(
waitForUI5Options,
() => {
window.wdi5.Log.info("[browser wdi5] locating " + JSON.stringify(controlSelector))
controlSelector.selector = window.wdi5.createMatcher(controlSelector.selector)
return window.bridge.findDOMElementByControlSelector(controlSelector)
})
.then((domElement) => {
// window.wdi5.Log.info('[browser wdi5] control located! - Message: ' + JSON.stringify(domElement));
// ui5 control
const ui5Control = window.wdi5.getUI5CtlForWebObj(domElement)
const id = ui5Control.getId()
window.wdi5.Log.info(`[browser wdi5] control with id: ${id} located!`)
const aProtoFunctions = window.wdi5.retrieveControlMethods(ui5Control)
// @type [String, String?, String, "Array of Strings"]
done(["success", domElement, id, aProtoFunctions])
})
.catch((error) => {
window.wdi5.Log.error("[browser wdi5] ERR: ", error)
done(["error", error.toString()])
})
window.bridge
.findDOMElementByControlSelector(controlSelector)
.then((domElement) => {
// window.wdi5.Log.info('[browser wdi5] control located! - Message: ' + JSON.stringify(domElement));
// ui5 control
const ui5Control = window.wdi5.getUI5CtlForWebObj(domElement)
const id = ui5Control.getId()
window.wdi5.Log.info(`[browser wdi5] control with id: ${id} located!`)
const aProtoFunctions = window.wdi5.retrieveControlMethods(ui5Control)
// @type [String, String?, String, "Array of Strings"]
done(["success", domElement, id, aProtoFunctions])
})
.catch(errorHandling)
},
errorHandling
)
}, controlSelector)
}

Expand Down
35 changes: 20 additions & 15 deletions client-side-js/getSelectorForElement.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,26 @@
async function clientSide_getSelectorForElement(oOptions) {
return await browser.executeAsync((oOptions, done) => {
window.bridge
.waitForUI5(window.wdi5.waitForUI5Options)
.then(() => {
const errorHandling = (error) => {
window.wdi5.Log.error("[browser wdi5] ERR: ", error)
done(["error", error.toString()])
return error
}

window.wdi5.waitForUI5(
window.wdi5.waitForUI5Options,
() => {
window.wdi5.Log.info("[browser wdi5] locating domElement")
return window.bridge.findControlSelectorByDOMElement(oOptions)
})
.then((controlSelector) => {
window.wdi5.Log.info("[browser wdi5] controlLocator created!")
done(["success", controlSelector])
return controlSelector
})
.catch((error) => {
window.wdi5.Log.error("[browser wdi5] ERR: ", error)
done(["error", error.toString()])
return error
})
window.bridge
.findControlSelectorByDOMElement(oOptions)
.then((controlSelector) => {
window.wdi5.Log.info("[browser wdi5] controlLocator created!")
done(["success", controlSelector])
return controlSelector
})
.catch(errorHandling)
},
errorHandling
)
}, oOptions)
}

Expand Down
16 changes: 16 additions & 0 deletions client-side-js/injectUI5.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,22 @@ async function clientSide_injectUI5(config, waitForUI5Timeout) {
window.wdi5.Log.info("[browser wdi5] injected!")
})

sap.ui.require(["sap/ui/test/autowaiter/_autoWaiterAsync"], (_autoWaiterAsync) => {
window.wdi5.waitForUI5 = function (oOptions, callback, errorCallback) {
oOptions = oOptions || {}
_autoWaiterAsync.extendConfig(oOptions)

_autoWaiterAsync.waitAsync(function (sError) {
if (sError) {
errorCallback(new Error(sError))
} else {
callback()
}
})
}
window.wdi5.Log.info("[browser wdi5] window._autoWaiterAsync used in waitForUI5 function")
})

// attach new bridge
sap.ui.require(["sap/ui/test/RecordReplay"], (RecordReplay) => {
window.bridge = RecordReplay
Expand Down
31 changes: 18 additions & 13 deletions client-side-js/interactWithControl.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
async function clientSide_interactWithControl(oOptions) {
return await browser.executeAsync((oOptions, done) => {
window.bridge
.waitForUI5(window.wdi5.waitForUI5Options)
.then(() => {
const errorHandling = (error) => {
window.wdi5.Log.error("[browser wdi5] ERR: ", error)
done(["error", error.toString()])
}

window.wdi5.waitForUI5(
window.wdi5.waitForUI5Options,
() => {
window.wdi5.Log.info("[browser wdi5] locating controlSelector")
oOptions.selector = window.wdi5.createMatcher(oOptions.selector)
return window.bridge.interactWithControl(oOptions)
})
.then((result) => {
window.wdi5.Log.info("[browser wdi5] interaction complete! - Message: " + result)
done(["success", result])
})
.catch((error) => {
window.wdi5.Log.error("[browser wdi5] ERR: ", error)
done(["error", error.toString()])
})
window.bridge
.interactWithControl(oOptions)
.then((result) => {
window.wdi5.Log.info("[browser wdi5] interaction complete! - Message: " + result)
done(["success", result])
})
.catch(errorHandling)
},
errorHandling
)
}, oOptions)
}

Expand Down