UNPKG

wdio-ui5-service

Version:

WebdriverIO plugin for testing UI5 browser-based apps

944 lines 47 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __generator = (this && this.__generator) || function (thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype); return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (g && (g = 0, op[0] && (_ = 0)), _) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; Object.defineProperty(exports, "__esModule", { value: true }); exports.WDI5Control = exports.ELEMENT_KEY = void 0; var util = __importStar(require("util")); exports.ELEMENT_KEY = "element-6066-11e4-a52e-4f735466cecf"; // TODO: import { ELEMENT_KEY } from "webdriverio/build/constants.js" // patch in webdriverio repo? var getControl_cjs_1 = require("../../client-side-js/getControl.cjs"); var interactWithControl_cjs_1 = require("../../client-side-js/interactWithControl.cjs"); var executeControlMethod_cjs_1 = require("../../client-side-js/executeControlMethod.cjs"); var _getAggregation_cjs_1 = require("../../client-side-js/_getAggregation.cjs"); var fireEvent_cjs_1 = require("../../client-side-js/fireEvent.cjs"); var Logger_js_1 = require("./Logger.js"); var wdioApi_js_1 = require("./wdioApi.js"); var wdi5_object_js_1 = require("./wdi5-object.js"); var Logger = Logger_js_1.Logger.getInstance(); /** * This is a bridge object to use from selector to UI5 control, * can be seen as a generic representation of a UI5 control */ var WDI5Control = /** @class */ (function () { function WDI5Control(oOptions) { this._controlSelector = null; // return value of Webdriver interface: JSON web token this._webElement = null; // TODO: type "org.openqa.selenium.WebElement" // wdio element retrieved separately via $() this._webdriverRepresentation = null; this._metadata = {}; // TODO: move to _metadata this._wdio_ui5_key = null; this._initialisation = false; this._forceSelect = false; this._wdioBridge = {}; var browserInstance = oOptions.browserInstance, controlSelector = oOptions.controlSelector, wdio_ui5_key = oOptions.wdio_ui5_key, forceSelect = oOptions.forceSelect, generatedUI5Methods = oOptions.generatedUI5Methods, webdriverRepresentation = oOptions.webdriverRepresentation, webElement = oOptions.webElement, domId = oOptions.domId; this._controlSelector = controlSelector; this._wdio_ui5_key = wdio_ui5_key; this._forceSelect = forceSelect; this._generatedUI5Methods = generatedUI5Methods; this._browserInstance = browserInstance; this._webElement = webElement; this._webdriverRepresentation = webdriverRepresentation; this._domId = domId; if (this._generatedUI5Methods && this._generatedUI5Methods.length > 0) { this._attachControlBridge(this._generatedUI5Methods); } if (this._generatedWdioMethods && this._generatedWdioMethods.length > 0) { this._attachWdioControlBridge(this._generatedWdioMethods); } this.setControlInfo(); return this; } WDI5Control.prototype.init = function () { return __awaiter(this, arguments, void 0, function (controlSelector, forceSelect) { var controlResult; var _a, _b; if (controlSelector === void 0) { controlSelector = this._controlSelector; } if (forceSelect === void 0) { forceSelect = this._forceSelect; } return __generator(this, function (_c) { switch (_c.label) { case 0: this._controlSelector = controlSelector; this._wdio_ui5_key = controlSelector.wdio_ui5_key; this._forceSelect = forceSelect; this._logging = (_b = (_a = this._controlSelector) === null || _a === void 0 ? void 0 : _a.logging) !== null && _b !== void 0 ? _b : true; return [4 /*yield*/, this._getControl()]; case 1: controlResult = _c.sent(); if (controlResult.status === 1) { // result is string and has error text -> its an error if (this._logging) { Logger.error("error retrieving control: ".concat(this._wdio_ui5_key)); } return [2 /*return*/, this]; } else { this._webElement = controlResult.domElement; // dynamic function bridge this._generatedUI5Methods = controlResult.aProtoFunctions; this._attachControlBridge(this._generatedUI5Methods); this._attachWdioControlBridge(this._generatedWdioMethods); this.setControlInfo(); } return [2 /*return*/, this]; } }); }); }; /** * after retrieving the ui5 control and connection this can be false eg. in cases when no DOM element was found by RecordReplay API * @return {Boolean} whether this control was successfully initialized */ WDI5Control.prototype.isInitialized = function () { return this._initialisation; }; WDI5Control.prototype.getControlInfo = function () { return this._metadata; }; WDI5Control.prototype.setControlInfo = function (metadata) { if (metadata === void 0) { metadata = { key: this._wdio_ui5_key, $: this._generatedWdioMethods, methods: this._generatedUI5Methods, id: this._domId }; } this._metadata.$ = metadata.$ ? metadata.$ : this._metadata.$; this._metadata.id = metadata.id ? metadata.id : this._metadata.id; this._metadata.methods = metadata.methods ? metadata.methods : this._metadata.methods; this._metadata.className = metadata.className ? metadata.className : this._metadata.className; this._metadata.key = metadata.key ? metadata.key : this._metadata.key; return this._metadata; }; /** * tries to retrieve the webdriver representation of the current wdi5 control * @return {WebdriverIO.Element} the webdriver Element */ WDI5Control.prototype.getWebElement = function () { return __awaiter(this, void 0, void 0, function () { var error_1; return __generator(this, function (_a) { switch (_a.label) { case 0: _a.trys.push([0, 2, , 3]); return [4 /*yield*/, this._getWebElement()]; case 1: return [2 /*return*/, _a.sent()]; case 2: error_1 = _a.sent(); if (this._logging) { Logger.error("cannot call \"getWebElement()\", because ".concat(error_1.message)); } return [3 /*break*/, 3]; case 3: return [2 /*return*/]; } }); }); }; /** * add convenience to the getWebElement Function * @returns {WebdriverIO.Element} the webdriver Element */ WDI5Control.prototype.$ = function () { return this._wdioBridge; // this.getWebElement() }; /** * bridge to UI5 control api "getAggregation" * @param name name of the aggregation * @return array of UI5 controls representing the aggregation */ WDI5Control.prototype.getAggregation = function (name) { return __awaiter(this, void 0, void 0, function () { var error_2; return __generator(this, function (_a) { switch (_a.label) { case 0: _a.trys.push([0, 2, , 3]); return [4 /*yield*/, this._getAggregation(name)]; case 1: return [2 /*return*/, _a.sent()]; case 2: error_2 = _a.sent(); if (this._logging) { Logger.error("cannot get aggregation \"".concat(name, "\", because ").concat(error_2.message)); } return [3 /*break*/, 3]; case 3: return [2 /*return*/]; } }); }); }; /** * enters a text into a UI5 control * @param text */ WDI5Control.prototype.enterText = function (text) { return __awaiter(this, void 0, void 0, function () { var selector, logging, _controlSelector, oOptions, error_3; return __generator(this, function (_a) { switch (_a.label) { case 0: if (!util.types.isProxy(this._controlSelector)) return [3 /*break*/, 4]; return [4 /*yield*/, Promise.resolve(this._controlSelector)]; case 1: _controlSelector = _a.sent(); return [4 /*yield*/, Promise.resolve(_controlSelector.selector)]; case 2: selector = _a.sent(); return [4 /*yield*/, Promise.resolve(this._logging)]; case 3: logging = _a.sent(); return [3 /*break*/, 5]; case 4: selector = this._controlSelector.selector; logging = this._logging; _a.label = 5; case 5: oOptions = { enterText: text, selector: selector, clearTextFirst: true, interactionType: "ENTER_TEXT" }; _a.label = 6; case 6: _a.trys.push([6, 8, , 9]); return [4 /*yield*/, this._interactWithControl(oOptions)]; case 7: _a.sent(); return [3 /*break*/, 9]; case 8: error_3 = _a.sent(); if (logging) { Logger.error("cannot call enterText(), because ".concat(error_3.message)); } return [3 /*break*/, 9]; case 9: return [2 /*return*/, this]; } }); }); }; /** * click on a UI5 control * this works both on a standalone control as well as with the fluent async api */ WDI5Control.prototype.press = function () { return __awaiter(this, void 0, void 0, function () { var className, controlSelector, logging, _controlInfo, oOptions, error_4, error_5; return __generator(this, function (_a) { switch (_a.label) { case 0: if (!util.types.isProxy(this._domId)) return [3 /*break*/, 4]; return [4 /*yield*/, Promise.resolve(this._metadata)]; case 1: _controlInfo = _a.sent(); className = _controlInfo.className; return [4 /*yield*/, Promise.resolve(this._controlSelector)]; case 2: controlSelector = _a.sent(); return [4 /*yield*/, Promise.resolve(this._logging)]; case 3: logging = _a.sent(); return [3 /*break*/, 5]; case 4: className = this.getControlInfo().className; controlSelector = this._controlSelector; logging = this._logging; _a.label = 5; case 5: if (!controlSelector.selector.interaction) return [3 /*break*/, 10]; if (logging) { Logger.info("using OPA5 Press action to interact with this ".concat(className, "...")); } oOptions = { selector: controlSelector.selector, interactionType: "PRESS" }; _a.label = 6; case 6: _a.trys.push([6, 8, , 9]); return [4 /*yield*/, this._interactWithControl(oOptions)]; case 7: _a.sent(); return [3 /*break*/, 9]; case 8: error_4 = _a.sent(); if (logging) { Logger.error("cannot issue OPA5-press() on control, because ".concat(error_4.message)); } return [3 /*break*/, 9]; case 9: return [3 /*break*/, 14]; case 10: _a.trys.push([10, 13, , 14]); return [4 /*yield*/, this._getWebElement()]; case 11: return [4 /*yield*/, (_a.sent()).click()]; case 12: _a.sent(); return [3 /*break*/, 14]; case 13: error_5 = _a.sent(); if (logging) { Logger.error("cannot call press(), because ".concat(error_5.message)); } return [3 /*break*/, 14]; case 14: return [2 /*return*/, this]; } }); }); }; /** * fire a named event on a UI5 control * @param {String} eventName * @param {any} oOptions * @param {WebdriverIO.Element} webElement */ WDI5Control.prototype.fireEvent = function (eventName_1, oOptions_1) { return __awaiter(this, arguments, void 0, function (eventName, oOptions, webElement) { var result; if (webElement === void 0) { webElement = this._webElement; } return __generator(this, function (_a) { switch (_a.label) { case 0: // Check the options have a eval property if (oOptions === null || oOptions === void 0 ? void 0 : oOptions.eval) { oOptions = "(" + oOptions.eval.toString() + ")"; } return [4 /*yield*/, (0, fireEvent_cjs_1.clientSide_fireEvent)(webElement, eventName, oOptions, this._browserInstance)]; case 1: result = (_a.sent()); if (this._logging) { this._writeObjectResultLog(result, "fireEvent()"); } return [2 /*return*/, result.result]; } }); }); }; // --- deprecated --- /** * @deprecated -> use isInitialized() * @return {Boolean} */ WDI5Control.prototype.getInitStatus = function () { return this._initialisation; }; // --- private methods --- /** * Interact with specific control. * @param {object} oOptions * @param {sap.ui.test.RecordReplay.ControlSelector} oOptions.selector - UI5 type * @param {sap.ui.test.RecordReplay.InteractionType} oOptions.interactionType - UI5 type * @param {string} oOptions.enterText * @param {boolean} oOptions.clearTextFirst */ WDI5Control.prototype._interactWithControl = function (oOptions) { return __awaiter(this, void 0, void 0, function () { var domId, logging, browserInstance, _a, result; return __generator(this, function (_b) { switch (_b.label) { case 0: if (!util.types.isProxy(this._domId)) return [3 /*break*/, 3]; return [4 /*yield*/, Promise.resolve(this._domId)]; case 1: domId = _b.sent(); return [4 /*yield*/, Promise.resolve(this._logging)]; case 2: logging = _b.sent(); return [3 /*break*/, 4]; case 3: domId = this._domId; logging = this._logging; _b.label = 4; case 4: if (!util.types.isProxy(this._browserInstance)) return [3 /*break*/, 6]; return [4 /*yield*/, Promise.resolve(this._browserInstance)]; case 5: _a = _b.sent(); return [3 /*break*/, 7]; case 6: _a = this._browserInstance; _b.label = 7; case 7: browserInstance = _a; if (!domId) return [3 /*break*/, 9]; return [4 /*yield*/, (0, interactWithControl_cjs_1.clientSide_interactWithControl)(oOptions, browserInstance)]; case 8: result = (_b.sent()); if (logging) { this._writeObjectResultLog(result, "interactWithControl()"); } // return result.result return [2 /*return*/, this]; case 9: throw Error("control could not be found"); } }); }); }; /** * returns the wdio web element. * @throws will throw an error when no DOM Element was found * @return {WebdriverIO.Element} the webdriver Element */ WDI5Control.prototype._getWebElement = function () { return __awaiter(this, void 0, void 0, function () { var id, webElement; return __generator(this, function (_a) { switch (_a.label) { case 0: if (!util.types.isProxy(this._domId)) return [3 /*break*/, 4]; return [4 /*yield*/, Promise.resolve(this._domId)]; case 1: id = _a.sent(); if (!id) return [3 /*break*/, 3]; return [4 /*yield*/, $("//*[@id=\"".concat(id, "\"]"))]; case 2: webElement = _a.sent(); return [2 /*return*/, webElement]; case 3: throw Error("control could not be found"); case 4: if (!!this._webdriverRepresentation) return [3 /*break*/, 6]; // to enable transition from wdi5 to wdio api in allControls return [4 /*yield*/, this._renewWebElement()]; case 5: // to enable transition from wdi5 to wdio api in allControls _a.sent(); _a.label = 6; case 6: return [2 /*return*/, this._webdriverRepresentation]; } }); }); }; /** * @param id * @returns */ WDI5Control.prototype._renewWebElement = function () { return __awaiter(this, arguments, void 0, function (id) { var _a; if (id === void 0) { id = this._domId; } return __generator(this, function (_b) { switch (_b.label) { case 0: if (!this._domId) return [3 /*break*/, 2]; _a = this; return [4 /*yield*/, this._browserInstance.$("//*[@id=\"".concat(id, "\"]"))]; case 1: _a._webdriverRepresentation = _b.sent(); return [2 /*return*/, this._webdriverRepresentation]; case 2: throw Error("control could not be found"); } }); }); }; /** * retrieve UI5 control representation of a UI5 control's aggregation * * @param aControls strings of IDs of aggregation items * @returns instances of wdi5 class per control in the aggregation */ WDI5Control.prototype._retrieveElements = function (aControls) { return __awaiter(this, void 0, void 0, function () { var aResultOfPromises; var _this = this; return __generator(this, function (_a) { switch (_a.label) { case 0: aResultOfPromises = []; if (!aControls) return [3 /*break*/, 2]; // loop through items aControls.forEach(function (item) { // item id -> create selector var selector = { wdio_ui5_key: item.id, // plugin-internal, not part of RecordReplay.ControlSelector forceSelect: _this._forceSelect, selector: { id: item.id } }; // get wdi5 control aResultOfPromises.push(_this._browserInstance.asControl(selector)); }); return [4 /*yield*/, Promise.all(aResultOfPromises)]; case 1: return [2 /*return*/, _a.sent()]; case 2: if (this._logging) { Logger.warn("".concat(this._wdio_ui5_key, " has no aControls")); } _a.label = 3; case 3: return [2 /*return*/]; } }); }); }; /** * retrieve UI5 control representation of a UI5 control's aggregation * * @param eControl ID * @returns instances of wdi5 class per control in the aggregation */ WDI5Control.prototype._retrieveElement = function (eControl) { return __awaiter(this, void 0, void 0, function () { var eResult, selector; return __generator(this, function (_a) { switch (_a.label) { case 0: eResult = {}; if (!eControl) return [3 /*break*/, 2]; selector = { wdio_ui5_key: eControl.id, // plugin-internal, not part of RecordReplay.ControlSelector forceSelect: this._forceSelect, selector: { id: eControl.id } }; return [4 /*yield*/, this._browserInstance.asControl(selector)]; case 1: // get wdi5 control eResult = _a.sent(); return [3 /*break*/, 3]; case 2: if (this._logging) { Logger.warn("".concat(this._wdio_ui5_key, " has no aControls")); } _a.label = 3; case 3: return [2 /*return*/, eResult]; } }); }); }; /** * attaches to the instance of this class the functions given in the parameter sReplFunctionNames * * @param sReplFunctionNames */ WDI5Control.prototype._attachControlBridge = function (sReplFunctionNames) { var _this = this; // check the validity of param if (sReplFunctionNames) { sReplFunctionNames.forEach(function (sMethodName) { return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_a) { this[sMethodName] = this._executeControlMethod.bind(this, sMethodName, this._webElement); return [2 /*return*/]; }); }); }); } else { if (this._logging) { Logger.warn("".concat(this._wdio_ui5_key, " has no sReplFunctionNames")); } } }; WDI5Control.prototype._attachWdioControlBridge = function (sReplFunctionNames) { var _this = this; // check the validity of param if (sReplFunctionNames) { sReplFunctionNames.forEach(function (sMethodName) { return __awaiter(_this, void 0, void 0, function () { var _this = this; return __generator(this, function (_a) { this._wdioBridge[sMethodName] = function () { return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, this.getWebElement()]; case 1: return [4 /*yield*/, (_a.sent())[sMethodName]()]; case 2: return [2 /*return*/, _a.sent()]; } }); }); }; return [2 /*return*/]; }); }); }); } else { if (this._logging) { Logger.warn("".concat(this._wdio_ui5_key, " has no sReplFunctionNames")); } } }; /** * runtime - proxied browser-time UI5 controls' method at Node.js-runtime * * @param methodName UI5 control method * @param webElement representation of selected UI5 control in wdio * @param args proxied arguments to UI5 control method at runtime */ WDI5Control.prototype._executeControlMethod = function (methodName_1) { return __awaiter(this, arguments, void 0, function (methodName, webElement) { var _i, _a, error_6, result, _b, wdioElement; if (webElement === void 0) { webElement = this._webElement; } var args = []; for (_i = 2; _i < arguments.length; _i++) { args[_i - 2] = arguments[_i]; } return __generator(this, function (_c) { switch (_c.label) { case 0: if (!this._forceSelect) return [3 /*break*/, 4]; _c.label = 1; case 1: _c.trys.push([1, 3, , 4]); _a = this; return [4 /*yield*/, this._renewWebElementReference()]; case 2: _a._webElement = _c.sent(); return [3 /*break*/, 4]; case 3: error_6 = _c.sent(); if (this._logging) { Logger.error("cannot execute ".concat(methodName, "(), because ").concat(error_6.message)); } return [3 /*break*/, 4]; case 4: if (!(methodName === "fireEvent")) return [3 /*break*/, 6]; if (!(args[1] && typeof args[1]["eval"] === "function")) return [3 /*break*/, 6]; return [4 /*yield*/, this.fireEvent(args[0], args[1], webElement)]; case 5: return [2 /*return*/, _c.sent()]; case 6: // returns the array of [0: "status", 1: result] //special case for exec, passed function needs to be converted to string to be passed to the browser if (methodName === "exec") { if (args[0] && typeof args[0] === "function") { args[0] = args[0].toString(); } else if (this._logging) { Logger.error("cannot execute ".concat(methodName, "(), because an argument of type function should be present")); } } return [4 /*yield*/, (0, executeControlMethod_cjs_1.clientSide_executeControlMethod)(webElement, methodName, this._browserInstance, args, // to safeguard "stale" elements in the devtools protocol we pass the whole wdi5 object this)]; case 7: result = (_c.sent()); // create logging this._writeObjectResultLog(result, methodName); _b = result.returnType; switch (_b) { case "newElement": return [3 /*break*/, 8]; case "element": return [3 /*break*/, 10]; case "result": return [3 /*break*/, 11]; case "object": return [3 /*break*/, 12]; case "empty": return [3 /*break*/, 13]; case "aggregation": return [3 /*break*/, 14]; case "unknown": return [3 /*break*/, 21]; case "none": return [3 /*break*/, 22]; } return [3 /*break*/, 23]; case 8: return [4 /*yield*/, this._retrieveElement(result.result)]; case 9: // retrieve and return another instance of a wdi5 control return [2 /*return*/, _c.sent()]; case 10: // return $self after a called method of the wdi5 instance to allow method chaining return [2 /*return*/, this]; case 11: return [2 /*return*/, result.nonCircularResultObject ? result.nonCircularResultObject : result.result]; case 12: // enhance with uuid return [2 /*return*/, new wdi5_object_js_1.WDI5Object(result.uuid, result.aProtoFunctions, result.object)]; case 13: if (this._logging) { Logger.warn("No data found in property or aggregation"); } return [2 /*return*/, result.result]; case 14: if (!((args.length > 0 && typeof args[0] === "boolean" && args[0] === false) || args.length === 0)) return [3 /*break*/, 16]; return [4 /*yield*/, this._retrieveElements(result.result)]; case 15: // get all if param is false or undefined return [2 /*return*/, _c.sent()]; case 16: if (!(String(args[0]) && typeof args[0] === "number")) return [3 /*break*/, 20]; if (!(args[0] <= result.result.length)) return [3 /*break*/, 18]; wdioElement = result.result[args[0]]; return [4 /*yield*/, this._retrieveElement(wdioElement)]; case 17: return [2 /*return*/, _c.sent()]; case 18: console.error("tried to get an control at index: ".concat(args[0], " of an aggregation outside of aggregation length: ").concat(result.result.length)); _c.label = 19; case 19: return [3 /*break*/, 21]; case 20: // return wdio elements return [2 /*return*/, result.result]; case 21: Logger.warn("".concat(methodName, " returned unknown status")); return [2 /*return*/, null]; case 22: return [2 /*return*/, null]; case 23: return [2 /*return*/, null]; } }); }); }; /** * retrieve an aggregation's members as UI5 controls * * @param aggregationName * @param webElement * @throws will throw an error when no webElement was found * @return {any} */ WDI5Control.prototype._getAggregation = function (aggregationName_1) { return __awaiter(this, arguments, void 0, function (aggregationName, webElement) { var _forceSelect, _a, _logging, _b, result, wdiItems; if (webElement === void 0) { webElement = this._webElement; } return __generator(this, function (_c) { switch (_c.label) { case 0: if (!util.types.isProxy(this._forceSelect)) return [3 /*break*/, 2]; return [4 /*yield*/, Promise.resolve(this._forceSelect)]; case 1: _a = _c.sent(); return [3 /*break*/, 3]; case 2: _a = this._forceSelect; _c.label = 3; case 3: _forceSelect = _a; if (!util.types.isProxy(this._logging)) return [3 /*break*/, 5]; return [4 /*yield*/, Promise.resolve(this._logging)]; case 4: _b = _c.sent(); return [3 /*break*/, 6]; case 5: _b = this._logging; _c.label = 6; case 6: _logging = _b; if (!_forceSelect) return [3 /*break*/, 8]; return [4 /*yield*/, this._renewWebElementReference()]; case 7: _c.sent(); _c.label = 8; case 8: if (!util.types.isProxy(webElement)) return [3 /*break*/, 10]; return [4 /*yield*/, Promise.resolve(webElement)]; case 9: webElement = _c.sent(); _c.label = 10; case 10: if (!webElement) { throw Error("control could not be found"); } return [4 /*yield*/, (0, _getAggregation_cjs_1.clientSide_getAggregation)(webElement, aggregationName, this._browserInstance)]; case 11: result = (_c.sent()); if (_logging) { this._writeObjectResultLog(result, "_getAggregation()"); } wdiItems = []; if (!(result.status === 0)) return [3 /*break*/, 13]; return [4 /*yield*/, this._retrieveElements(result.result)]; case 12: wdiItems = _c.sent(); _c.label = 13; case 13: // else return empty array return [2 /*return*/, wdiItems]; } }); }); }; /** * used to update the wdio control reference * this can be used to manually trigger an control reference update after a ui5 control rerendering * this method is also used wdi5-internally to implement the extended forceSelect option * @param {Boolean} isRefresh whether to treat the incoming call as a refresh attempt on a stale web element */ WDI5Control.prototype._renewWebElementReference = function () { return __awaiter(this, arguments, void 0, function (isRefresh) { var newWebElement, fromCache; if (isRefresh === void 0) { isRefresh = false; } return __generator(this, function (_a) { switch (_a.label) { case 0: if (!this._domId) return [3 /*break*/, 2]; return [4 /*yield*/, this._getControl(isRefresh ? this._controlSelector : { selector: { id: this._domId } })]; case 1: newWebElement = (_a.sent()).domElement // added to have a more stable retrieval experience ; if (!this.isInitialized()) { this._webElement = undefined; } else { this._webElement = newWebElement; } return [2 /*return*/, newWebElement]; case 2: if (!(this._wdio_ui5_key && !this._forceSelect)) return [3 /*break*/, 4]; return [4 /*yield*/, this._getControl(this._controlSelector)]; case 3: fromCache = _a.sent(); this._webElement = fromCache.domElement; return [2 /*return*/, fromCache.domElement]; case 4: return [2 /*return*/]; } }); }); }; /** * expose internal API to refresh a stale web element reference * @param {Boolean} asRefresh whether to treat the incoming call as a refresh attempt on a stale web element */ WDI5Control.prototype.renewWebElementReference = function () { return __awaiter(this, arguments, void 0, function (asRefresh) { if (asRefresh === void 0) { asRefresh = true; } return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, this._renewWebElementReference(asRefresh)]; case 1: return [2 /*return*/, _a.sent()]; } }); }); }; /** * retrieve a DOM element via UI5 locator * @param {sap.ui.test.RecordReplay.ControlSelector} controlSelector * @return {[WebdriverIO.Element | String, [aProtoFunctions]]} UI5 control or error message, array of function names of this control */ WDI5Control.prototype._getControl = function () { return __awaiter(this, arguments, void 0, function (controlSelector) { var _result, elementReference, status, domElement, id, aProtoFunctions, className; var _a, _b; if (controlSelector === void 0) { controlSelector = this._controlSelector; } return __generator(this, function (_c) { switch (_c.label) { case 0: // check whether we have a "by id regex" locator request if (controlSelector.selector.id && typeof controlSelector.selector.id === "object") { // make it a string for serializing into browser-scope and // further processing there controlSelector.selector.id = controlSelector.selector.id.toString(); } // check whether we have a (partial) text matcher // that should match: // properties: { // text: new RegExp(/.*ersi.*/gm) // } // ...but not: // properties: { // text: { // regex: { // source: '.*ersi.*', // flags: 'gm' // } // } // } if (typeof ((_a = controlSelector.selector.properties) === null || _a === void 0 ? void 0 : _a.text) === "object" && ((_b = controlSelector.selector.properties) === null || _b === void 0 ? void 0 : _b.text) instanceof RegExp) { // make it a string for serializing into browser-scope and // further processing there controlSelector.selector.properties.text = controlSelector.selector.properties.text.toString(); } return [4 /*yield*/, (0, getControl_cjs_1.clientSide_getControl)(controlSelector, this._browserInstance)]; case 1: _result = (_c.sent()); if (!(_result.status === 0 && !_result.domElement[exports.ELEMENT_KEY])) return [3 /*break*/, 3]; return [4 /*yield*/, this._browserInstance.execute(function (id) { var webElement = document.evaluate("//*[@id='".concat(id, "']"), document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; return webElement; }, _result.id)]; case 2: elementReference = (_c.sent()); _result.domElement = elementReference; _c.label = 3; case 3: status = _result.status, domElement = _result.domElement, id = _result.id, aProtoFunctions = _result.aProtoFunctions, className = _result.className; if (status === 0 && id) { // only if the result is valid this._generatedWdioMethods = wdioApi_js_1.wdioApi; // add metadata this._metadata.className = className; this._domId = id; // set the successful init param this._initialisation = true; } else { this._initialisation = false; this._domId = undefined; } if (this._logging) { this._writeObjectResultLog(_result, "_getControl()"); } return [2 /*return*/, { status: status, domElement: domElement, aProtoFunctions: aProtoFunctions }]; } }); }); }; WDI5Control.prototype._writeObjectResultLog = function (response, functionName) { if (response.status > 0) { Logger.error("call of ".concat(functionName, " failed because of: ").concat(response.message)); } else if (response.status === 0) { Logger.success("call of function ".concat(functionName, " returned: ").concat(JSON.stringify(response.id ? response.id : response.result))); } else { Logger.warn("Unknown status: ".concat(functionName, " returned: ").concat(JSON.stringify(response.message))); } }; return WDI5Control; }()); exports.WDI5Control = WDI5Control; //# sourceMappingURL=wdi5-control.js.map