UNPKG

@sap_oss/wdio-qmate-service

Version:

[![REUSE status](https://api.reuse.software/badge/github.com/SAP/wdio-qmate-service)](https://api.reuse.software/info/github.com/SAP/wdio-qmate-service)[![Node.js CI](https://github.com/SAP/wdio-qmate-service/actions/workflows/node.js.yml/badge.svg)](http

410 lines 19.2 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 __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.File = void 0; const verboseLogger_1 = require("../../helper/verboseLogger"); const path = __importStar(require("path")); const pdf_parse_1 = __importDefault(require("pdf-parse")); const fs = __importStar(require("fs")); const xlsx = __importStar(require("xlsx")); const os = __importStar(require("os")); const xml2js = __importStar(require("xml2js")); const errorHandler_1 = __importDefault(require("../../helper/errorHandler")); const constants_1 = require("../constants"); /** * @class file * @memberof util */ class File { vlf = new verboseLogger_1.VerboseLoggerFactory("util", "file"); ErrorHandler = new errorHandler_1.default(); // =================================== UPLOAD =================================== /** * @function upload * @memberOf util.file * @description Uploads all the file/s by the paths given in the Array. * @param {String[]} files - Array with path/s of file/s to be uploaded. * @param {String} [selector="input[type='file']"] - Custom selector of uploader control (in case there are more then one present). * @example await util.file.upload(["path/to/text1.txt", "path/to/text2.txt"]); // uses the default uploader control * @example await util.file.upload(["path/to/text1.txt", "path/to/text2.txt"], "input[id='myUpload']"); // upload to file uploader with matching selector */ async upload(files, selector = "input[type = 'file']") { const vl = this.vlf.initLog(this.upload); let elem; try { if (typeof selector === "string") { elem = await $(selector); } else if (typeof selector === "object") { const elemId = await ui5.element.getId(selector); elem = await nonUi5.element.getByXPath(`.//input[contains(@id,'${elemId}')][@type='file']`); } let remoteFiles = ""; for (const file of files) { const filePath = path.resolve(file); vl.log(`Uploading file with a path ${filePath}`); const remoteFilePath = await browser.uploadFile(filePath); if (remoteFiles) { remoteFiles = remoteFiles + "\n"; } remoteFiles = remoteFiles + remoteFilePath; } await elem.addValue(remoteFiles); } catch (error) { this.ErrorHandler.logException(error); } } /** * @function uploadWebGui * @memberOf util.file * @description Uploads all the file/s by the paths given in the Array for SAP WebGUI apps. * @param {String[]} files - Array with path/s of file/s to be uploaded. * @param {String} selector - Custom selector of the input element * @example await util.file.uploadWebGui(["path/to/text1.txt"], "INPUT[title='External file name']"); */ async uploadWebGui(files, selector) { const vl = this.vlf.initLog(this.uploadWebGui); try { const elem = await nonUi5.element.getByCss(selector); await nonUi5.userInteraction.click(elem); await common.userInteraction.pressF4(); const okButton = await nonUi5.element.getByCss("DIV[id='UpDownDialogChoose']"); await nonUi5.assertion.expectToBeVisible(okButton); const fileInput = await nonUi5.element.getByCss(".//input[@id='webgui_filebrowser_file_upload'][@type='file']", 0, constants_1.GLOBAL_DEFAULT_WAIT_TIMEOUT, true); let remoteFiles = ""; for (const file of files) { const filePath = path.resolve(file); vl.log(`Uploading file with path ${filePath}`); const remoteFilePath = await browser.uploadFile(filePath); if (remoteFiles) { remoteFiles = remoteFiles + "\n"; } remoteFiles = remoteFiles + remoteFilePath; } await fileInput.addValue(remoteFiles); } catch (error) { this.ErrorHandler.logException(error); } } // =================================== PDF =================================== /** * @function parsePdf * @memberOf util.file * @description Parses the text from PDF stream. Returned text can be asserted to verify the PDF document content. * @param {Buffer} pdfStream - PDF stream to be downloaded. * @param {Function} renderingMethod - Function to customize the parsing process. * @returns {String} The parsed PDF text. * @see <a href="TODO">Parse PDF</a> * @example await util.file.parsePdf(pdfStream, customRenderingMethod); */ async parsePdf(pdfStream, renderingMethod = this._renderPage) { const vl = this.vlf.initLog(this.parsePdf); if (typeof renderingMethod !== "function") { return this.ErrorHandler.logException(new Error("Please provide a custom rendering method as second parameter.")); } const options = { pagerender: renderingMethod }; // @ts-ignore const data = await (0, pdf_parse_1.default)(pdfStream, options); return data.text; } /** * @function expectPdfContainsText * @memberOf util.file * @description Parses the PDF and checks for given text to be contained in PDF. * @param {Buffer} pdfStream - PDF stream to be downloaded. * @param {String} text - The expected text. * @param {Function} renderingMethod - Function to customize the parsing process. * @see <a href="TODO">Parse pdf</a> * @example await util.file.expectPdfContainsText(pdfStream, "abc"); */ async expectPdfContainsText(pdfStream, text, renderingMethod = this._renderPage) { const vl = this.vlf.initLog(this.expectPdfContainsText); if (!text) { this.ErrorHandler.logException(new Error("Please provide a text as second parameter.")); } const parsedText = await this.parsePdf(pdfStream, renderingMethod); return expect(parsedText).toContain(text); } /** * @function expectPdfNotContainsText * @memberOf util.file * @description Parses the PDF and checks for given text not to be contained in PDF. * @param {Buffer} pdfStream - PDF stream to be downloaded * @param {String} text - The text expected to be not contained in the PDF. * @param {Function} renderingMethod - Function to customize the parsing process. * @see <a href="TODO">Parse pdf</a> * @example await util.file.expectPdfNotContainsText(pdfStream, "abc"); */ async expectPdfNotContainsText(pdfStream, text, renderingMethod = this._renderPage) { const vl = this.vlf.initLog(this.expectPdfNotContainsText); if (!text) { return this.ErrorHandler.logException(new Error("Please provide a text as second parameter.")); } const parsedText = await this.parsePdf(pdfStream, renderingMethod); return expect(parsedText).not.toContain(text); } // =================================== EXCEL =================================== /** * @function getExcelData * @memberof util.file * @description - It returns the excel data based on the conversion type which is passed * @param {string} filePath - File path is required * @param {string} fileName - File Name is required * @param {number} [sheetIndex] - sheetIndex is required * @param {string} [conversionType] - Value for this are [json, csv, txt] * @example const myTableContent = await util.file.getExcelData("/Users/path/myWork", "myTable.xlx"); */ async getExcelData(filePath, fileName, sheetIndex = 0, conversionType = "json") { const vl = this.vlf.initLog(this.getExcelData); const downloadDir = filePath && fs.existsSync(filePath) ? filePath + path.sep : os.homedir() + path.sep + "Downloads"; vl.log(`Download directory path: ${downloadDir}`); const fileNamePath = await this.findFilePathRecursively(downloadDir, fileName); if (!fileNamePath) { return this.ErrorHandler.logException(new Error(`The specified file '${fileName}' doesn't exist in the directory: ${downloadDir}`)); } const workbook = xlsx.readFile(fileNamePath); const sheetList = workbook.SheetNames; if (sheetIndex < 0 || sheetIndex > sheetList.length - 1) { return this.ErrorHandler.logException(new Error(`The specified sheet index '${sheetIndex}' is invalid for the Excel file.`)); } const sheetName = sheetList[sheetIndex]; const sheet = workbook.Sheets[sheetName]; return this._convertSheet(conversionType, sheet); } // =================================== TXT =================================== /** * @function getTextData * @memberof util.file * @description - Returns the content of a .txt file. * @param {string} filePath - Path to the file. * @example const txtData = await util.file.getTextData(path.resolve(__dirname, "./testFiles/test3.txt")); * const isDateIncluded = txtData.includes("26.6.2023"); * common.assertion.expectEqual(isDateIncluded, true); */ async getTextData(filePath) { const vl = this.vlf.initLog(this.getTextData); if (fs.existsSync(filePath) && this._checkFileEnding(filePath, "txt")) { try { return await fs.readFileSync(filePath, { encoding: "utf8" }); } catch (error) { return this.ErrorHandler.logException(error); } } } /** * @function expectTextDataToContain * @memberof util.file * @description - Reads the specified .txt file and asserts if it includes a specific string. * @param {string} filePath - Path to the file. * @example await util.file.expectTextDataToContain("/Users/path/myWork", "supplierList.txt"); */ async expectTextDataToContain(filePath, searchString) { const vl = this.vlf.initLog(this.expectTextDataToContain); if (fs.existsSync(filePath)) { try { const fileContent = fs.readFileSync(filePath, "utf-8"); common.assertion.expectTrue(fileContent.includes(searchString)); } catch (error) { return this.ErrorHandler.logException(error, "Search String not included in .txt file."); } } } // =================================== XML =================================== /** * @function getXmlData * @memberof util.file * @description - Returns the converted JSON object based on the passed XML file. * @param {string} filePath - Path to the file. * @example const xmlData = await util.file.getXmlData(path.resolve(__dirname, "./testFiles/test2.xml")); */ async getXmlData(filePath) { const vl = this.vlf.initLog(this.getXmlData); if (fs.existsSync(filePath) && this._checkFileEnding(filePath, "xml")) { try { const xmlData = await fs.readFileSync(filePath); const parser = new xml2js.Parser({ trim: true, normalize: true }); return await parser.parseStringPromise(xmlData); } catch (error) { return this.ErrorHandler.logException(error); } } } // =================================== JSON =================================== /** * @function getAttributeValuesFromJson * @memberof util.file * @description - Traverses the passed JSON object and returns the value/s of the passed attribute if found. Else returns empty Array. * @param {object} object - The JSON Object to search through. * @example const attribute = util.file.getAttributeValuesFromJson(xmlData, "CtrlSum"); */ getAttributeValuesFromJson(object, attributeName) { const values = []; if (typeof object !== "object" || object === null) { return values; } if (attributeName in object) { values.push(object[attributeName]); } for (const key in object) { const nestedValues = this.getAttributeValuesFromJson(object[key], attributeName); values.push(...nestedValues); } return values.flat(); } // =================================== FILEPATH =================================== /** * @function findFilePathRecursively * @memberof util.file * @description - Returns the absolute path of the file with the given filename. Searches Recursively for the file within the given directory. * @param {string} directory - The name of the directory. * @param {string} fileName - The name of the file. * @example await util.file.findFilePathRecursively("/Users","test.xls"); */ async findFilePathRecursively(directory, fileName) { const vl = this.vlf.initLog(this.findFilePathRecursively); try { const fileList = fs.readdirSync(directory); for (const file of fileList) { const filePath = path.join(directory, file); const stats = fs.statSync(filePath); if (stats.isDirectory()) { const recursiveFilePath = await this.findFilePathRecursively(filePath, fileName); if (recursiveFilePath !== null) { return recursiveFilePath; } } else if (stats.isFile()) { const parsedFileName = path.parse(filePath).base; if (path.extname(parsedFileName).includes(".xls") && parsedFileName === fileName) { return filePath; } } } } catch (error) { return this.ErrorHandler.logException(new Error("Error in getting the file path for the given directory and filename.")); } return null; } // =================================== FILENAME =================================== /** * @function getFileNamesByExtensions * @memberof util.file * @description - Returns the filename/s of the given directory filtered by the given extensions. * @param {string} dirPath - The path to the directory. * @param {string | string[]} fileExtensions - The file extension as string or multiple as string array. * @example const fileName = await util.file.getFileNamesByExtensions("regression/downloads", "xml"); * const fileNames = await util.file.getFileNamesByExtensions("regression/downloads", "["xml", "txt"]"); */ getFileNamesByExtensions(dirPath, fileExtensions) { const files = fs.readdirSync(dirPath); if (!Array.isArray(fileExtensions)) { fileExtensions = [fileExtensions]; } return files.filter((file) => { const extension = path.extname(file).toLowerCase(); return fileExtensions.some((ext) => ext.toLowerCase() === extension.slice(1)); }); } // =================================== HELPER =================================== async _renderPage(pageData) { // should be in scope of render page due to library specific implementation const _parseText = function (textContent) { if (textContent === undefined || textContent === null || !textContent.items || !Array.isArray(textContent.items)) { return; } let lastY, text = ""; for (const item of textContent.items) { if (Array.isArray(item.transform) && item.transform.length === 6) { if (lastY == item.transform[5] || !lastY) { text += " " + item.str; } else { text += "\n" + item.str; } lastY = item.transform[5]; } } return text; }; const render_options = { // replaces all occurrences of whitespace with standard spaces (0x20). The default value is `false`. normalizeWhitespace: false, // do not attempt to combine same line TextItem's. The default value is `false`. disableCombineTextItems: false }; return pageData.getTextContent(render_options).then(_parseText); } _convertSheet(conversionType, sheet) { let excelData; switch (conversionType.toLowerCase().trim()) { case "json": excelData = xlsx.utils.sheet_to_json(sheet); break; case "csv": excelData = xlsx.utils.sheet_to_csv(sheet); break; case "txt": excelData = xlsx.utils.sheet_to_txt(sheet); break; default: throw new Error("Passed conversion type is not supported"); } return excelData; } _checkFileEnding(filePath, expectedFileEnding) { const vl = this.vlf.initLog(this._checkFileEnding); const fileEnding = path.extname(filePath).slice(1); if (fileEnding.toLowerCase() === expectedFileEnding.toLowerCase()) { return true; } else { return this.ErrorHandler.logException(new Error(`Wrong file format '${fileEnding}' was passed to function. Expected file format: ${expectedFileEnding}.`)); } } } exports.File = File; exports.default = new File(); //# sourceMappingURL=file.js.map