@sap_oss/wdio-qmate-service
Version:
[](https://api.reuse.software/info/github.com/SAP/wdio-qmate-service)[](http
156 lines • 7.26 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.FunctionModule = void 0;
const verboseLogger_1 = require("../../helper/verboseLogger");
const errorHandler_1 = __importDefault(require("../../helper/errorHandler"));
/**
* @class function
* @memberof util
*/
class FunctionModule {
vlf = new verboseLogger_1.VerboseLoggerFactory("util", "function");
ErrorHandler = new errorHandler_1.default();
maxCurrentRetries = 3;
// =================================== MAIN ===================================
/**
* @function retry
* @memberOf util.function
* @description Retries the passed function n times with a specific interval until it executed successfully.
* @param {Function} fct - The function to retry.
* @param {Array} args - An array of the arguments passed to the function.
* @param {Integer} [retries=3] - The number of retries. Can be set in config for all functions under "params" - "stepsRetries".
* @param {Integer} [interval=5000] - The interval of the retries (ms). Can be set in config for all functions under "params" - "stepRetriesIntervals".
* @param {Object} [scope=null] - The function scope. Defaults is the global object.
* @example await util.function.retry(ui5.userInteraction.fill, [selector, value], 4, 10000);
* @example await util.function.retry(async () => {
* await ui5.userInteraction.fill(selector, "ABC");
* }, [], 2, 30000);
*/
// NOTE: Don't set default values since they will be calculated with "_getRetryProperties".
async retry(fct, args, retries, interval, scope = null) {
const vl = this.vlf.initLog(this.retry);
vl.log(`${retries} retries were configured`);
const res = await this._getRetryProperties(retries, interval);
this.maxCurrentRetries = res.retries;
await this._retry(fct, args, res.retries, res.interval, scope);
}
/**
* @function executeOptional
* @memberOf util.function
* @description Executes the given function optionally. If it fails, a promise will be returned anyway.
* @param {Function} fct - The function to execute.
* @param {Array} args - An array of the arguments passed to the function.
* @example await util.function.executeOptional(ui5.userInteraction.fill, [selector, value]);
* @example await util.function.executeOptional(async () => {
* await ui5.userInteraction.fill(selector, "ABC");
* }, []);
*/
async executeOptional(fct, args = []) {
const vl = this.vlf.initLog(this.retry);
try {
await fct.apply(this, args);
}
catch (e) {
if (fct.name) {
util.console.info(`Optional function '${fct.name}' not executed, continue ...`);
}
else {
util.console.info(`Optional anonymous function not executed, continue ...`);
}
return Promise.resolve();
}
}
// =================================== HELPER ===================================
/**
* @function mapWdioErrorToQmateErrorMessage
* @memberOf util.function
* @private
* @description Maps Wdio Error to Qmate Error Message
* @param {Error} wdioError - The wdio error
* @param {string} action - An action performed upon the element ("click", "fill")
* @example await util.function.mapWdioErrorToQmateErrorMessage(error, "click");
*/
async mapWdioErrorToQmateErrorMessage(wdioError, action) {
const errorMessage = wdioError.message;
let qmateMessage = "";
if (action === "fill") {
if (errorMessage.match(new RegExp(/(invalid element state|element not interactable)/))) {
qmateMessage = `Function fill failed. Element can not be filled - make sure that the selector matches input \n\n` + wdioError.stack;
}
}
else if (action === "click") {
if (errorMessage.match(new RegExp(/is not clickable at point/))) {
const reg = new RegExp(/(?<=Element <.* )(.*)(?=>...<)/).exec(errorMessage);
const foundAttributes = reg ? reg[0] : undefined;
let elementAttributes = foundAttributes;
if (reg && foundAttributes) {
if (foundAttributes.includes("id=")) {
// @ts-ignore
elementAttributes = foundAttributes.match(new RegExp(/(?=id)(.*)(?<=")/));
}
else if (foundAttributes.includes("class=")) {
// @ts-ignore
elementAttributes = foundAttributes.match(new RegExp(/(?=class)(.*)(?<=")/));
}
}
if (wdioError && wdioError.stack && elementAttributes) {
qmateMessage = `Element with attribute(s) ${elementAttributes[0]} is hidden by another element \n\n` + wdioError.stack;
}
else {
qmateMessage = "Error clicking element \n\n" + wdioError;
}
}
}
return qmateMessage;
}
// =================================== HELPER ===================================
async _getRetryProperties(retries, interval) {
const vl = this.vlf.initLog(this._getRetryProperties);
const res = {
retries: retries,
interval: interval
};
if (res.retries === undefined) {
res.retries = browser.config.params.stepsRetries;
if (res.retries === undefined) {
res.retries = 3;
}
}
if (res.interval === undefined) {
res.interval = browser.config.params.stepRetriesIntervals;
if (res.interval === undefined) {
res.interval = 5000;
}
}
vl.log(`Got retry properties: ${res}`);
return res;
}
async _retry(fct, args, retries, interval, scope = null) {
const vl = this.vlf.initLog(this._retry);
try {
vl.log(`Executing ${fct.name ? fct.name : "anonymous"} function via retry mechanism`);
return await fct.apply(scope, args);
}
catch (e) {
let errorMessage = e.message;
errorMessage = errorMessage
? errorMessage.trim().includes("failed with:")
? errorMessage.substring(errorMessage.search("failed with:") + 12)
: errorMessage
: "";
retries = retries - 1;
if (retries < 0) {
this.ErrorHandler.logException(e, `Retries done. Failed to execute the function:${errorMessage}`);
}
await browser.pause(interval);
util.console.log(`Retrying function again (${this.maxCurrentRetries - retries}/${this.maxCurrentRetries})`);
await this._retry(fct, args, retries, interval, scope);
}
}
}
exports.FunctionModule = FunctionModule;
exports.default = new FunctionModule();
//# sourceMappingURL=function.js.map