UNPKG

wdio-ui5-service

Version:

WebdriverIO plugin for testing UI5 browser-based apps

161 lines 8.32 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.clientSide_executeControlMethod = clientSide_executeControlMethod; const Logger_js_1 = require("../lib/Logger.js"); const logger = Logger_js_1.Logger.getInstance(); /** * Execute method on the ui5 control through the browser. Here the real magic happens :) * @param {Object} webElement representation of a webElement in node depending on the protocol * @param {String} methodName function name to be called on the ui5 control * @param {WebdriverIO.Browser} browserInstance * @param {Object} args proxied arguments to UI5 control method at runtime */ async function executeControlMethod(webElement, methodName, browserInstance, args) { return await browserInstance.execute(async function wdi5_executeControlMethod(webElement, methodName, args) { try { await window.bridge.waitForUI5(window.wdi5.waitForUI5Options); // DOM to UI5 const oControl = window.wdi5.getUI5CtlForWebObj(webElement); // execute the function // eslint-disable-next-line prefer-spread let result = oControl[methodName].apply(oControl, args); const metadata = oControl.getMetadata(); if (Array.isArray(result)) { if (result.length === 0) { return { status: 0, result: result, returnType: "empty" }; } else if (result[0]?.getParent) { // expect the method call delivers non-primitive results (like getId()) // but delivers a complex/structured type // -> currently, only getAggregation(...) is supported // read classname eg. sap.m.ComboBox const controlType = oControl.getMetadata().getName(); result = window.wdi5.createControlIdMap(result, controlType); return { status: 0, result: result, returnType: "aggregation" }; } else { return { status: 0, result: result, returnType: "result" }; } } else { const [ControlRef, ItemRef, UI5ObjectRef] = await new Promise((resolve, reject) => { sap.ui.require(["sap/ui/core/Control", "sap/ui/core/Item", "sap/ui/base/Object"], function (...args) { resolve(args); }, reject); }); // ui5 api <control>.focus() doesn't have return value if (methodName === "focus" && result === undefined) { return { status: 0, result: `called focus() on wdi5 representation of a ${metadata.getElementName()}`, returnType: "element" }; } else if (methodName === "exec" && result && result.status > 0) { return { status: result.status, message: result.message }; } else if (result === undefined || result === null) { return { status: 1, result: `function ${methodName} does not exist on control ${metadata.getElementName()}!`, returnType: "none" }; } else { if (window.wdi5.isPrimitive(result)) { return { status: 0, result: result, returnType: "result" }; } else if ( // we have an object that is not a UI5 control typeof result === "object" && result !== null && // @ts-expect-error: Property 'core' does not exist on type 'typeof ui' !(result instanceof ControlRef) && // @ts-expect-error: Property 'core' does not exist on type 'typeof ui' !(result instanceof ItemRef)) { // save before manipulate const uuid = window.wdi5.saveObject(result); // FIXME: extract, collapse and remove cyclic in 1 step // extract the methods first const aProtoFunctions = window.wdi5.retrieveControlMethods(result); // flatten the prototype so we have all funcs available const collapsed = window.wdi5.collapseObject(result); // exclude cyclic references const collapsedAndNonCyclic = JSON.parse(JSON.stringify(collapsed, window.wdi5.getCircularReplacer())); // remove all empty Array elements, including private keys (starting with "_") const semanticCleanedElements = window.wdi5.removeEmptyElements(collapsedAndNonCyclic); return { status: 0, object: semanticCleanedElements, returnType: "object", aProtoFunctions: aProtoFunctions, uuid: uuid, nonCircularResultObject: semanticCleanedElements }; } else if (typeof result === "object" && result !== null && // wdi5 returns a wdi5 control if the UI5 api return its control // allows method chaining // @ts-expect-error: Property 'base' does not exist on type 'typeof ui' !(result instanceof UI5ObjectRef)) { return { status: 1, returnType: "unknown" }; } else { // we got ourselves a regular UI5 control // check that we're not working against ourselves :) 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); return { status: 0, result: result, returnType: "newElement" }; } else { return { status: 0, result: `instance of wdi5 representation of a ${metadata.getElementName()}`, returnType: "element" }; } } } } } catch (error) { window.wdi5.errorHandling.bind(error); return { status: 0, message: "ERROR" }; } }, webElement, methodName, args); } /** * Execute method on the ui5 control through the browser. If element "is stale" we first retrieve it * from the browser again * @param {Object} webElement representation of a webElement in node depending on the protocol * @param {String} methodName function name to be called on the ui5 control * @param {WebdriverIO.Browser} browserInstance * @param {Object} args proxied arguments to UI5 control method at runtime * @param {WDI5Control} wdi5Control wdi5 representation of the ui5 control */ async function clientSide_executeControlMethod(webElement, methodName, browserInstance, args, wdi5Control) { let result; try { result = await executeControlMethod(webElement, methodName, browserInstance, args); } catch (err) { logger.error("failed executing control method", methodName, err); result = { status: 1, message: `${methodName} could not be executed on control with selector: ${JSON.stringify(wdi5Control._controlSelector)}` }; } return result; } //# sourceMappingURL=executeControlMethod.js.map