@cuppet/core 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +183 -0
- package/features/app/appiumManager.js +58 -0
- package/features/app/browserManager.js +54 -0
- package/features/app/hooks.js +95 -0
- package/features/app/stepDefinitions/accessibilitySteps.js +17 -0
- package/features/app/stepDefinitions/apiSteps.js +52 -0
- package/features/app/stepDefinitions/appiumSteps.js +15 -0
- package/features/app/stepDefinitions/generalSteps.js +98 -0
- package/features/app/stepDefinitions/helperSteps.js +79 -0
- package/features/app/stepDefinitions/ifVisibleSteps.js +58 -0
- package/features/app/stepDefinitions/iframeSteps.js +61 -0
- package/features/app/stepDefinitions/lighthouseSteps.js +17 -0
- package/features/app/stepDefinitions/pageElements.js +208 -0
- package/features/app/stepDefinitions/pageElementsConfig.js +42 -0
- package/features/app/stepDefinitions/pageElementsJson.js +49 -0
- package/features/app/stepDefinitions/visualRegressionSteps.js +26 -0
- package/features/app/world.js +15 -0
- package/index.js +43 -0
- package/package.json +57 -0
- package/src/accessibilityTesting.js +44 -0
- package/src/apiFunctions.js +290 -0
- package/src/appiumTesting.js +79 -0
- package/src/dataStorage.js +290 -0
- package/src/elementInteraction.js +1003 -0
- package/src/helperFunctions.js +183 -0
- package/src/lighthouse.js +23 -0
- package/src/mainFunctions.js +288 -0
- package/src/visualRegression.js +67 -0
- package/stepDefinitions.js +17 -0
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module dataStorage
|
|
3
|
+
* @typedef {import('puppeteer').Page} Page
|
|
4
|
+
*/
|
|
5
|
+
const config = require('config');
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
const helper = require('./helperFunctions');
|
|
8
|
+
const moment = require('moment');
|
|
9
|
+
const jsonFilePath = config.get('jsonFilePath').toString();
|
|
10
|
+
|
|
11
|
+
module.exports = {
|
|
12
|
+
/**
|
|
13
|
+
* Create the JSON file in which test data will be stored
|
|
14
|
+
* @returns {Promise<void>}
|
|
15
|
+
*/
|
|
16
|
+
createFile: async function () {
|
|
17
|
+
if (jsonFilePath && !fs.existsSync(jsonFilePath)) {
|
|
18
|
+
fs.writeFile(jsonFilePath, '', { flag: 'w+' }, (err) => {
|
|
19
|
+
if (err) {
|
|
20
|
+
console.error('File is not created, please check if the folder exists!');
|
|
21
|
+
} else {
|
|
22
|
+
console.log('File Created');
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Clear the JSON file
|
|
30
|
+
* @returns {void}
|
|
31
|
+
*/
|
|
32
|
+
clearJsonFile: function () {
|
|
33
|
+
if (jsonFilePath) {
|
|
34
|
+
fs.truncate(jsonFilePath, 0, () => {
|
|
35
|
+
console.log('JSON File Cleared successfully!');
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Generate pa11y,lighthouse etc. html reports
|
|
42
|
+
* @param fileName - string with the name of the file
|
|
43
|
+
* @param data - HtmlReporter formatted result
|
|
44
|
+
* @returns {Promise<void>}
|
|
45
|
+
*/
|
|
46
|
+
createHtmlReport: async function (fileName, data) {
|
|
47
|
+
const profile = process.env.NODE_CONFIG_ENV;
|
|
48
|
+
fs.writeFile(`reports/${profile}/${fileName}.html`, data, (err) => {
|
|
49
|
+
if (err) throw err;
|
|
50
|
+
console.log(`Html report: ${fileName}.html is generated!`);
|
|
51
|
+
});
|
|
52
|
+
},
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Load the JSON file
|
|
56
|
+
* @param file
|
|
57
|
+
* @returns {any|{}}
|
|
58
|
+
*/
|
|
59
|
+
getJsonFile: function (file = '') {
|
|
60
|
+
file = file || jsonFilePath;
|
|
61
|
+
const result = fs.readFileSync(file, 'utf-8');
|
|
62
|
+
return result ? JSON.parse(result) : {};
|
|
63
|
+
},
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Save variable to JSON file. Example: {
|
|
67
|
+
* "varName":"Value"
|
|
68
|
+
* }
|
|
69
|
+
* @param data - the value of the variable
|
|
70
|
+
* @param variable - the variable name
|
|
71
|
+
* @returns {Promise<void>}
|
|
72
|
+
*/
|
|
73
|
+
iStoreVariableWithValueToTheJsonFile: async function (data, variable) {
|
|
74
|
+
const tempJson = this.getJsonFile();
|
|
75
|
+
tempJson[variable] = data;
|
|
76
|
+
fs.writeFileSync(jsonFilePath, JSON.stringify(tempJson), { flag: 'w+' });
|
|
77
|
+
},
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Get specific variable and throw error if missing
|
|
81
|
+
* @param variable
|
|
82
|
+
* @param {boolean} stringify - flag to be used when getting values which are object themselves
|
|
83
|
+
* @returns {*}
|
|
84
|
+
*/
|
|
85
|
+
getVariable: function (variable, stringify = false) {
|
|
86
|
+
const tempJson = this.getJsonFile();
|
|
87
|
+
if (!tempJson[variable]) {
|
|
88
|
+
throw new Error(`Variable with name ${variable} not found in the json file!`);
|
|
89
|
+
}
|
|
90
|
+
if (stringify) {
|
|
91
|
+
return JSON.stringify(tempJson[variable]);
|
|
92
|
+
}
|
|
93
|
+
return tempJson[variable];
|
|
94
|
+
},
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Check for variable existence or return the inputted value.
|
|
98
|
+
* To be used in steps which can work both with JSON vars and direct user input
|
|
99
|
+
* @param variable
|
|
100
|
+
* @returns {*}
|
|
101
|
+
*/
|
|
102
|
+
checkForVariable: function (variable) {
|
|
103
|
+
const tempJson = this.getJsonFile();
|
|
104
|
+
return tempJson[variable] ?? variable;
|
|
105
|
+
},
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Replace single occurrence of %% pattern in a string with a stored variable.
|
|
109
|
+
* Example - I go to "/node/%myStoredPage%" -> "/node/test-page-alias"
|
|
110
|
+
* @param data
|
|
111
|
+
* @returns {Promise<*>}
|
|
112
|
+
*/
|
|
113
|
+
checkForSavedVariable: async function (data) {
|
|
114
|
+
return data.replace(/%([a-zA-Z_-]+)%/g, (match, p1) => {
|
|
115
|
+
return this.checkForVariable(p1);
|
|
116
|
+
});
|
|
117
|
+
},
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Similar to checkForSavedVariable but it extracts multiple variable names from the following pattern:
|
|
121
|
+
* Example - "Here are %var1% and %var2%" and replace
|
|
122
|
+
* them with their values - "Here are valueOfVar1 and valueOfVar2"
|
|
123
|
+
* @param text
|
|
124
|
+
* @returns {Promise<*>}
|
|
125
|
+
*/
|
|
126
|
+
checkForMultipleVariables: async function (text) {
|
|
127
|
+
const regex = /%([^%]+)%/g;
|
|
128
|
+
const allVariables = this.getJsonFile();
|
|
129
|
+
// The convention dictates if function argument is not used, it can be replaced by "_".
|
|
130
|
+
const result = text.replace(regex, (_, group) => {
|
|
131
|
+
return allVariables[group];
|
|
132
|
+
});
|
|
133
|
+
return result || text;
|
|
134
|
+
},
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Re-save the JSON file with all it's values in lowercase.
|
|
138
|
+
* @returns {Promise<void>}
|
|
139
|
+
*/
|
|
140
|
+
lowercaseAllVariables: async function () {
|
|
141
|
+
const allVariables = this.getJsonFile();
|
|
142
|
+
const lowercaseJson = Object.fromEntries(
|
|
143
|
+
Object.entries(allVariables).map(([key, value]) => [
|
|
144
|
+
key,
|
|
145
|
+
typeof value === 'string' ? value.toLowerCase() : value,
|
|
146
|
+
])
|
|
147
|
+
);
|
|
148
|
+
fs.writeFileSync(jsonFilePath, JSON.stringify(lowercaseJson), { flag: 'w+' });
|
|
149
|
+
},
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Cut the value of a variable on special char occurrence. The regex can be changed via the config json.
|
|
153
|
+
* Example - valueOf@Variable -> valueOf.
|
|
154
|
+
* @param variable
|
|
155
|
+
* @returns {Promise<void>}
|
|
156
|
+
*/
|
|
157
|
+
trimVariableOnFirstSpecialChar: async function (variable) {
|
|
158
|
+
let regex = /[?&@$#:,;]/;
|
|
159
|
+
if (config.has('trimRegex')) {
|
|
160
|
+
const configRegex = config.get('trimRegex');
|
|
161
|
+
regex = new RegExp(configRegex.toString());
|
|
162
|
+
}
|
|
163
|
+
const value = this.getVariable(variable);
|
|
164
|
+
let splitArr = value.split(regex);
|
|
165
|
+
const result = splitArr[0].trim();
|
|
166
|
+
await this.iStoreVariableWithValueToTheJsonFile(result, variable);
|
|
167
|
+
},
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Save current page url in both relative and absolute url variants. Predefined json
|
|
171
|
+
* property names are used for easier usage.
|
|
172
|
+
* @param {Page} page - current tab in puppeteer
|
|
173
|
+
* @returns {Promise<void>}
|
|
174
|
+
*/
|
|
175
|
+
saveCurrentPath: async function (page) {
|
|
176
|
+
// Get the current URL
|
|
177
|
+
const url = new URL(page.url());
|
|
178
|
+
const absolutePath = url.href;
|
|
179
|
+
// Get the relative path
|
|
180
|
+
const relativePath = url.pathname;
|
|
181
|
+
// Store paths
|
|
182
|
+
await this.iStoreVariableWithValueToTheJsonFile(absolutePath, 'path');
|
|
183
|
+
await this.iStoreVariableWithValueToTheJsonFile(relativePath, 'relativePath');
|
|
184
|
+
},
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Store ID (in case of Drupal) or the sequence of numbers in url path alias.
|
|
188
|
+
* Example /node/123/edit -> 123 will be extracted and saved
|
|
189
|
+
* @param {Page} page
|
|
190
|
+
* @param variable
|
|
191
|
+
* @returns {Promise<void>}
|
|
192
|
+
*/
|
|
193
|
+
iStoreEntityId: async function (page, variable) {
|
|
194
|
+
const currentUrl = new URL(page.url());
|
|
195
|
+
const alias = currentUrl.pathname;
|
|
196
|
+
const matches = /[1-9]\d*/.exec(alias);
|
|
197
|
+
if (!matches) {
|
|
198
|
+
throw new Error(`The url path doesn't contain an ID:${alias}`);
|
|
199
|
+
}
|
|
200
|
+
await this.iStoreVariableWithValueToTheJsonFile(matches[0], variable);
|
|
201
|
+
},
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Saves the href from a link <a>.
|
|
205
|
+
* TO DO: Can be done with more generic method to save specific attribute of element, instead of the hardcoded href.
|
|
206
|
+
* @param {Page} page
|
|
207
|
+
* @param selector
|
|
208
|
+
* @param variable
|
|
209
|
+
* @returns {Promise<void>}
|
|
210
|
+
*/
|
|
211
|
+
storeHrefOfElement: async function (page, selector, variable) {
|
|
212
|
+
await page.waitForSelector(selector);
|
|
213
|
+
let href = await page.$eval(selector, (el) => el.getAttribute('href'));
|
|
214
|
+
href = encodeURI(href);
|
|
215
|
+
await this.iStoreVariableWithValueToTheJsonFile(href, variable);
|
|
216
|
+
},
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Save the text from a page element matching specific pattern.
|
|
220
|
+
* Example: "This is your code for password reset: 123456"
|
|
221
|
+
* You can create a regex to find the 123456 number and extract it from that text.
|
|
222
|
+
* @param {Page} page - current puppeteer tab
|
|
223
|
+
* @param pattern - regex
|
|
224
|
+
* @param text - text in which this pattern needs to be searched for
|
|
225
|
+
* @returns {Promise<void>}
|
|
226
|
+
*/
|
|
227
|
+
storeTextFromPattern: async function (page, pattern, text) {
|
|
228
|
+
const element = await page.$('xpath/' + `//body//*[text()[contains(.,'${text}')]]`);
|
|
229
|
+
let textValue = await (await page.evaluateHandle((el) => el.textContent, element)).jsonValue();
|
|
230
|
+
const regex = new RegExp(pattern);
|
|
231
|
+
const matches = regex.exec(textValue);
|
|
232
|
+
if (!matches) {
|
|
233
|
+
throw new Error(`There isn't a string matching the pattern:${regex}`);
|
|
234
|
+
}
|
|
235
|
+
await this.iStoreVariableWithValueToTheJsonFile(matches[0], 'storedString');
|
|
236
|
+
},
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Store the value of the element (input, button, option, li etc.)
|
|
240
|
+
* @param {Page} page
|
|
241
|
+
* @param cssSelector
|
|
242
|
+
* @param variable
|
|
243
|
+
* @returns {Promise<void>}
|
|
244
|
+
*/
|
|
245
|
+
storeValueOfElement: async function (page, cssSelector, variable) {
|
|
246
|
+
await page.waitForSelector(cssSelector);
|
|
247
|
+
const value = await page.$eval(cssSelector, (el) => el.value);
|
|
248
|
+
if (!value) {
|
|
249
|
+
throw new Error(`Element with selector ${cssSelector} doesn't have value!`);
|
|
250
|
+
}
|
|
251
|
+
await this.iStoreVariableWithValueToTheJsonFile(value, variable);
|
|
252
|
+
},
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Generate mail extension with specific length.
|
|
256
|
+
* Example test@example.com -> test+zy62a@example.com
|
|
257
|
+
* @param number
|
|
258
|
+
* @param emailVariable
|
|
259
|
+
* @param varName
|
|
260
|
+
* @returns {Promise<void>}
|
|
261
|
+
*/
|
|
262
|
+
generateExtensionAndStoreVar: async function (number, emailVariable, varName) {
|
|
263
|
+
let email = emailVariable;
|
|
264
|
+
if (config.has(emailVariable)) {
|
|
265
|
+
email = config.get(emailVariable);
|
|
266
|
+
}
|
|
267
|
+
let splitVar = email.split('@');
|
|
268
|
+
if (splitVar.length === 0) {
|
|
269
|
+
throw new Error(`The provided string: ${email} is not an email!`);
|
|
270
|
+
}
|
|
271
|
+
let randomStr = helper.generateRandomString(number);
|
|
272
|
+
const value = splitVar[0] + '+' + randomStr + '@' + splitVar[1];
|
|
273
|
+
await this.iStoreVariableWithValueToTheJsonFile(value, varName);
|
|
274
|
+
},
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
*
|
|
278
|
+
* @param format
|
|
279
|
+
* @param variable
|
|
280
|
+
* @param days
|
|
281
|
+
* @returns {Promise<void>}
|
|
282
|
+
*/
|
|
283
|
+
generateAndSaveDateWithCustomFormat: async function (format, variable, days = 0) {
|
|
284
|
+
let date = moment()
|
|
285
|
+
.add(days >= 0 ? days : -days, 'days')
|
|
286
|
+
.format(format);
|
|
287
|
+
|
|
288
|
+
await this.iStoreVariableWithValueToTheJsonFile(date, variable);
|
|
289
|
+
},
|
|
290
|
+
};
|