@sap_oss/wdio-qmate-service
Version:
[](https://api.reuse.software/info/github.com/SAP/wdio-qmate-service)[](http
410 lines • 19.2 kB
JavaScript
;
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