artes 1.7.20 → 1.7.21

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.
Files changed (49) hide show
  1. package/README.md +781 -781
  2. package/assets/styles.css +4 -4
  3. package/cucumber.config.js +253 -253
  4. package/docs/ciExecutors.md +198 -198
  5. package/docs/emulationDevicesList.md +152 -152
  6. package/docs/functionDefinitions.md +2401 -2401
  7. package/docs/stepDefinitions.md +435 -435
  8. package/executer.js +266 -266
  9. package/index.js +51 -51
  10. package/package.json +56 -56
  11. package/src/helper/contextManager/browserManager.js +74 -74
  12. package/src/helper/contextManager/requestManager.js +23 -23
  13. package/src/helper/controller/elementController.js +230 -230
  14. package/src/helper/controller/findDuplicateTestNames.js +69 -69
  15. package/src/helper/controller/getEnvInfo.js +97 -97
  16. package/src/helper/controller/getExecutor.js +109 -109
  17. package/src/helper/controller/pomCollector.js +83 -83
  18. package/src/helper/controller/reportCustomizer.js +511 -511
  19. package/src/helper/controller/screenComparer.js +96 -96
  20. package/src/helper/controller/status-formatter.js +137 -137
  21. package/src/helper/controller/testCoverageCalculator.js +111 -111
  22. package/src/helper/executers/cleaner.js +23 -23
  23. package/src/helper/executers/exporter.js +19 -19
  24. package/src/helper/executers/helper.js +193 -193
  25. package/src/helper/executers/projectCreator.js +226 -226
  26. package/src/helper/executers/reportGenerator.js +91 -91
  27. package/src/helper/executers/testRunner.js +28 -28
  28. package/src/helper/executers/versionChecker.js +31 -31
  29. package/src/helper/imports/commons.js +69 -69
  30. package/src/helper/stepFunctions/APIActions.js +582 -582
  31. package/src/helper/stepFunctions/assertions.js +986 -986
  32. package/src/helper/stepFunctions/browserActions.js +87 -87
  33. package/src/helper/stepFunctions/elementInteractions.js +60 -60
  34. package/src/helper/stepFunctions/exporter.js +19 -19
  35. package/src/helper/stepFunctions/frameActions.js +72 -72
  36. package/src/helper/stepFunctions/keyboardActions.js +66 -66
  37. package/src/helper/stepFunctions/mouseActions.js +84 -84
  38. package/src/helper/stepFunctions/pageActions.js +43 -43
  39. package/src/hooks/context.js +18 -18
  40. package/src/hooks/hooks.js +287 -287
  41. package/src/stepDefinitions/API.steps.js +404 -404
  42. package/src/stepDefinitions/assertions.steps.js +1358 -1349
  43. package/src/stepDefinitions/browser.steps.js +74 -74
  44. package/src/stepDefinitions/frameActions.steps.js +76 -76
  45. package/src/stepDefinitions/keyboardActions.steps.js +264 -264
  46. package/src/stepDefinitions/mouseActions.steps.js +374 -374
  47. package/src/stepDefinitions/page.steps.js +71 -71
  48. package/src/stepDefinitions/random.steps.js +199 -199
  49. package/src/stepDefinitions/report.steps.js +5 -5
@@ -1,230 +1,230 @@
1
- const { context } = require("../../hooks/context");
2
- const path = require("path");
3
-
4
- let elements = {};
5
-
6
- function addElements(newElements) {
7
- elements = { ...elements, ...newElements };
8
- }
9
-
10
- // async function locatorExistenceChecker(locator){
11
- // const locatorCount = await locator.count();
12
- // console.log(locator, locatorCount)
13
- // return locatorCount ==0 ? false : true;
14
- // }
15
-
16
- function selectorSeparator(element) {
17
- if (typeof element !== "string") return element;
18
-
19
- const selector = element?.split("=");
20
- const validTypes = [
21
- "xpath",
22
- "name",
23
- "placeholder",
24
- "text",
25
- "label",
26
- "role",
27
- "alt",
28
- "title",
29
- "testid",
30
- ];
31
-
32
- if (selector && validTypes.includes(selector[0]?.trim())) {
33
- return [
34
- selector[0].trim(),
35
- selector[1] !== undefined ? selector[1].trim() : "",
36
- ];
37
- } else {
38
- return selector.join("=");
39
- }
40
- }
41
-
42
- function getSelector(element) {
43
- element = resolveVariable(element);
44
-
45
- const selector =
46
- elements?.[element]?.selector || elements?.[element] || element;
47
- return resolveVariable(selectorSeparator(selector));
48
- }
49
-
50
- function getElement(element) {
51
- if (!context.page) {
52
- throw new Error("Page context is not initialized.");
53
- }
54
-
55
- const selector = getSelector(element);
56
- const waitTime = elements[element]?.waitTime * 1000 || 0;
57
-
58
- let locator;
59
- switch (selector[0]) {
60
- case "xpath":
61
- locator = context.page.locator(`xpath=${selector[1]}`, { exact: true });
62
- break;
63
- case "name":
64
- locator = context.page.locator(`[name="${selector[1]}"]`, {
65
- exact: true,
66
- });
67
- break;
68
- case "placeholder":
69
- locator = context.page.getByPlaceholder(selector[1], { exact: true });
70
- break;
71
- case "text":
72
- locator = context.page.getByText(selector[1], { exact: true });
73
- break;
74
- case "label":
75
- locator = context.page.getByLabel(selector[1], { exact: true });
76
- break;
77
- case "role":
78
- locator = context.page.getByRole(selector[1], { exact: true });
79
- break;
80
- case "alt":
81
- locator = context.page.getByAltText(selector[1], { exact: true });
82
- break;
83
- case "title":
84
- locator = context.page.getByTitle(selector[1], { exact: true });
85
- break;
86
- case "testid":
87
- locator = context.page.getByTestId(selector[1], { exact: true });
88
- break;
89
- default:
90
- locator = context.page.locator(selector, { exact: true });
91
- break;
92
- }
93
-
94
- return locator;
95
- }
96
-
97
- function normalizeCrossplatformPath(inputPath) {
98
- return path.normalize(inputPath.replace(/\\/g, "/"));
99
- }
100
-
101
- function pathToCamelCase(path) {
102
- const cleaned = path.replace(/\[(\d+)\]/g, "_$1");
103
- const parts = cleaned.split(".");
104
- return parts
105
- .map((part, index) => {
106
- if (index === 0) return part;
107
- return part.charAt(0).toUpperCase() + part.slice(1);
108
- })
109
- .join("");
110
- }
111
-
112
- function extractVarsFromResponse(responseBody, vars, customVarNames) {
113
- function getValueByPath(obj, path) {
114
- if (typeof obj === "string") return obj;
115
-
116
- const keys = path.split(".").flatMap((key) => {
117
- const arrayMatch = key.match(/^([^\[]+)\[(\d+)\]$/);
118
- if (arrayMatch) {
119
- return [arrayMatch[1], parseInt(arrayMatch[2])];
120
- }
121
- return [key];
122
- });
123
-
124
- let current = obj;
125
- for (const key of keys) {
126
- if (current == null) return undefined;
127
-
128
- if (typeof key === "number") {
129
- if (!Array.isArray(current)) return undefined;
130
- current = current[key];
131
- } else if (typeof current === "object" && key in current) {
132
- current = current[key];
133
- } else {
134
- return undefined;
135
- }
136
- }
137
-
138
- return current;
139
- }
140
-
141
-
142
- const varPaths = vars.split(",").map((v) => v.trim());
143
- let customNames = [];
144
-
145
- if (!customVarNames) {
146
- customNames = varPaths.map(pathToCamelCase);
147
- } else if (typeof customVarNames === "string") {
148
- customNames = customVarNames.split(",").map((n) => n.trim());
149
- } else if (Array.isArray(customVarNames)) {
150
- customNames = customVarNames;
151
- } else {
152
- throw new Error("customVarNames must be a string or an array");
153
- }
154
-
155
- if (customNames.length !== varPaths.length) {
156
- customNames = varPaths.map(pathToCamelCase);
157
- }
158
-
159
- varPaths.forEach((path, index) => {
160
- const value = getValueByPath(responseBody, path);
161
- if (value !== undefined) {
162
- saveVar(value, customNames[index], path);
163
- }
164
- });
165
- }
166
-
167
- function saveVar(value, customName, path) {
168
- if (!customName) {
169
- const flatKey = path
170
- .split(".")
171
- .map((part, i) =>
172
- i === 0 ? part : part[0].toUpperCase() + part.slice(1),
173
- )
174
- .join("");
175
-
176
- context.vars[flatKey] = value;
177
- } else {
178
- context.vars[customName] = value;
179
- }
180
- }
181
-
182
- function resolveVariable(template) {
183
- if (typeof template === "string") {
184
- return template.replace(/{{\s*(\w+)\s*}}/g, (_, varName) => {
185
- let value = context.vars[varName];
186
-
187
- if (value !== undefined) {
188
- if (typeof value !== "string") {
189
- try {
190
- value = JSON.stringify(value);
191
- } catch {
192
- value = String(value);
193
- }
194
- }
195
-
196
- return value
197
- .replace(/\n/g, "\\n")
198
- .replace(/\r/g, "\\r")
199
- .replace(/\t/g, "\\t");
200
- }
201
-
202
- return `{{${varName}}}`;
203
- });
204
- }
205
-
206
- if (Array.isArray(template)) {
207
- return template.map((item) => resolveVariable(item));
208
- }
209
-
210
- if (template && typeof template === "object") {
211
- const result = {};
212
- for (const key in template) {
213
- result[key] = resolveVariable(template[key]);
214
- }
215
- return result;
216
- }
217
-
218
- return template;
219
- }
220
-
221
- module.exports = {
222
- getElement,
223
- addElements,
224
- getSelector,
225
- extractVarsFromResponse,
226
- pathToCamelCase,
227
- normalizeCrossplatformPath,
228
- saveVar,
229
- resolveVariable,
230
- };
1
+ const { context } = require("../../hooks/context");
2
+ const path = require("path");
3
+
4
+ let elements = {};
5
+
6
+ function addElements(newElements) {
7
+ elements = { ...elements, ...newElements };
8
+ }
9
+
10
+ // async function locatorExistenceChecker(locator){
11
+ // const locatorCount = await locator.count();
12
+ // console.log(locator, locatorCount)
13
+ // return locatorCount ==0 ? false : true;
14
+ // }
15
+
16
+ function selectorSeparator(element) {
17
+ if (typeof element !== "string") return element;
18
+
19
+ const selector = element?.split("=");
20
+ const validTypes = [
21
+ "xpath",
22
+ "name",
23
+ "placeholder",
24
+ "text",
25
+ "label",
26
+ "role",
27
+ "alt",
28
+ "title",
29
+ "testid",
30
+ ];
31
+
32
+ if (selector && validTypes.includes(selector[0]?.trim())) {
33
+ return [
34
+ selector[0].trim(),
35
+ selector[1] !== undefined ? selector[1].trim() : "",
36
+ ];
37
+ } else {
38
+ return selector.join("=");
39
+ }
40
+ }
41
+
42
+ function getSelector(element) {
43
+ element = resolveVariable(element);
44
+
45
+ const selector =
46
+ elements?.[element]?.selector || elements?.[element] || element;
47
+ return resolveVariable(selectorSeparator(selector));
48
+ }
49
+
50
+ function getElement(element) {
51
+ if (!context.page) {
52
+ throw new Error("Page context is not initialized.");
53
+ }
54
+
55
+ const selector = getSelector(element);
56
+ const waitTime = elements[element]?.waitTime * 1000 || 0;
57
+
58
+ let locator;
59
+ switch (selector[0]) {
60
+ case "xpath":
61
+ locator = context.page.locator(`xpath=${selector[1]}`, { exact: true });
62
+ break;
63
+ case "name":
64
+ locator = context.page.locator(`[name="${selector[1]}"]`, {
65
+ exact: true,
66
+ });
67
+ break;
68
+ case "placeholder":
69
+ locator = context.page.getByPlaceholder(selector[1], { exact: true });
70
+ break;
71
+ case "text":
72
+ locator = context.page.getByText(selector[1], { exact: true });
73
+ break;
74
+ case "label":
75
+ locator = context.page.getByLabel(selector[1], { exact: true });
76
+ break;
77
+ case "role":
78
+ locator = context.page.getByRole(selector[1], { exact: true });
79
+ break;
80
+ case "alt":
81
+ locator = context.page.getByAltText(selector[1], { exact: true });
82
+ break;
83
+ case "title":
84
+ locator = context.page.getByTitle(selector[1], { exact: true });
85
+ break;
86
+ case "testid":
87
+ locator = context.page.getByTestId(selector[1], { exact: true });
88
+ break;
89
+ default:
90
+ locator = context.page.locator(selector, { exact: true });
91
+ break;
92
+ }
93
+
94
+ return locator;
95
+ }
96
+
97
+ function normalizeCrossplatformPath(inputPath) {
98
+ return path.normalize(inputPath.replace(/\\/g, "/"));
99
+ }
100
+
101
+ function pathToCamelCase(path) {
102
+ const cleaned = path.replace(/\[(\d+)\]/g, "_$1");
103
+ const parts = cleaned.split(".");
104
+ return parts
105
+ .map((part, index) => {
106
+ if (index === 0) return part;
107
+ return part.charAt(0).toUpperCase() + part.slice(1);
108
+ })
109
+ .join("");
110
+ }
111
+
112
+ function extractVarsFromResponse(responseBody, vars, customVarNames) {
113
+ function getValueByPath(obj, path) {
114
+ if (typeof obj === "string") return obj;
115
+
116
+ const keys = path.split(".").flatMap((key) => {
117
+ const arrayMatch = key.match(/^([^\[]+)\[(\d+)\]$/);
118
+ if (arrayMatch) {
119
+ return [arrayMatch[1], parseInt(arrayMatch[2])];
120
+ }
121
+ return [key];
122
+ });
123
+
124
+ let current = obj;
125
+ for (const key of keys) {
126
+ if (current == null) return undefined;
127
+
128
+ if (typeof key === "number") {
129
+ if (!Array.isArray(current)) return undefined;
130
+ current = current[key];
131
+ } else if (typeof current === "object" && key in current) {
132
+ current = current[key];
133
+ } else {
134
+ return undefined;
135
+ }
136
+ }
137
+
138
+ return current;
139
+ }
140
+
141
+
142
+ const varPaths = vars.split(",").map((v) => v.trim());
143
+ let customNames = [];
144
+
145
+ if (!customVarNames) {
146
+ customNames = varPaths.map(pathToCamelCase);
147
+ } else if (typeof customVarNames === "string") {
148
+ customNames = customVarNames.split(",").map((n) => n.trim());
149
+ } else if (Array.isArray(customVarNames)) {
150
+ customNames = customVarNames;
151
+ } else {
152
+ throw new Error("customVarNames must be a string or an array");
153
+ }
154
+
155
+ if (customNames.length !== varPaths.length) {
156
+ customNames = varPaths.map(pathToCamelCase);
157
+ }
158
+
159
+ varPaths.forEach((path, index) => {
160
+ const value = getValueByPath(responseBody, path);
161
+ if (value !== undefined) {
162
+ saveVar(value, customNames[index], path);
163
+ }
164
+ });
165
+ }
166
+
167
+ function saveVar(value, customName, path) {
168
+ if (!customName) {
169
+ const flatKey = path
170
+ .split(".")
171
+ .map((part, i) =>
172
+ i === 0 ? part : part[0].toUpperCase() + part.slice(1),
173
+ )
174
+ .join("");
175
+
176
+ context.vars[flatKey] = value;
177
+ } else {
178
+ context.vars[customName] = value;
179
+ }
180
+ }
181
+
182
+ function resolveVariable(template) {
183
+ if (typeof template === "string") {
184
+ return template.replace(/{{\s*(\w+)\s*}}/g, (_, varName) => {
185
+ let value = context.vars[varName];
186
+
187
+ if (value !== undefined) {
188
+ if (typeof value !== "string") {
189
+ try {
190
+ value = JSON.stringify(value);
191
+ } catch {
192
+ value = String(value);
193
+ }
194
+ }
195
+
196
+ return value
197
+ .replace(/\n/g, "\\n")
198
+ .replace(/\r/g, "\\r")
199
+ .replace(/\t/g, "\\t");
200
+ }
201
+
202
+ return `{{${varName}}}`;
203
+ });
204
+ }
205
+
206
+ if (Array.isArray(template)) {
207
+ return template.map((item) => resolveVariable(item));
208
+ }
209
+
210
+ if (template && typeof template === "object") {
211
+ const result = {};
212
+ for (const key in template) {
213
+ result[key] = resolveVariable(template[key]);
214
+ }
215
+ return result;
216
+ }
217
+
218
+ return template;
219
+ }
220
+
221
+ module.exports = {
222
+ getElement,
223
+ addElements,
224
+ getSelector,
225
+ extractVarsFromResponse,
226
+ pathToCamelCase,
227
+ normalizeCrossplatformPath,
228
+ saveVar,
229
+ resolveVariable,
230
+ };
@@ -1,69 +1,69 @@
1
- const fs = require("fs");
2
- const path = require("path");
3
-
4
- function findDuplicateTestNames() {
5
- const testStatusFile = path.join(
6
- process.cwd(),
7
- "node_modules",
8
- "artes",
9
- "test-status",
10
- "test-status.txt",
11
- );
12
-
13
- if (!fs.existsSync(testStatusFile)) {
14
- console.error("test-status.txt not found");
15
- return;
16
- }
17
-
18
- const content = fs.readFileSync(testStatusFile, "utf8");
19
- const lines = content.split("\n").filter((line) => line.trim());
20
-
21
- const testNameToEntries = {};
22
-
23
- lines.forEach((line) => {
24
- const parts = line.split(" | ");
25
- if (parts.length < 5) return;
26
-
27
- const testName = parts[2].trim();
28
- const filePath = parts[4].trim();
29
- const uuid = parts[3].trim();
30
-
31
- if (!testNameToEntries[testName]) {
32
- testNameToEntries[testName] = [];
33
- }
34
-
35
- const alreadyExists = testNameToEntries[testName].some(
36
- (e) => e.uuid === uuid,
37
- );
38
- if (!alreadyExists) {
39
- testNameToEntries[testName].push({ filePath, uuid });
40
- }
41
- });
42
-
43
- const duplicates = {};
44
-
45
- Object.entries(testNameToEntries).forEach(([testName, entries]) => {
46
- if (entries.length > 1) {
47
- duplicates[testName] = entries.map((e) => e.filePath);
48
- }
49
- });
50
-
51
- if (Object.keys(duplicates).length > 0) {
52
- console.warn(
53
- "\n\x1b[33m[WARNING] Duplicate scenario names found: This will affect your reporting",
54
- );
55
- Object.entries(duplicates).forEach(([testName, files]) => {
56
- console.log(`\x1b[33m"${testName}" exists in:`);
57
- files.forEach((file) => {
58
- console.log(` - ${file}`);
59
- });
60
- console.log("");
61
- });
62
- console.log("\x1b[0m");
63
- console.log("");
64
- }
65
-
66
- return duplicates;
67
- }
68
-
69
- module.exports = { findDuplicateTestNames };
1
+ const fs = require("fs");
2
+ const path = require("path");
3
+
4
+ function findDuplicateTestNames() {
5
+ const testStatusFile = path.join(
6
+ process.cwd(),
7
+ "node_modules",
8
+ "artes",
9
+ "test-status",
10
+ "test-status.txt",
11
+ );
12
+
13
+ if (!fs.existsSync(testStatusFile)) {
14
+ console.error("test-status.txt not found");
15
+ return;
16
+ }
17
+
18
+ const content = fs.readFileSync(testStatusFile, "utf8");
19
+ const lines = content.split("\n").filter((line) => line.trim());
20
+
21
+ const testNameToEntries = {};
22
+
23
+ lines.forEach((line) => {
24
+ const parts = line.split(" | ");
25
+ if (parts.length < 5) return;
26
+
27
+ const testName = parts[2].trim();
28
+ const filePath = parts[4].trim();
29
+ const uuid = parts[3].trim();
30
+
31
+ if (!testNameToEntries[testName]) {
32
+ testNameToEntries[testName] = [];
33
+ }
34
+
35
+ const alreadyExists = testNameToEntries[testName].some(
36
+ (e) => e.uuid === uuid,
37
+ );
38
+ if (!alreadyExists) {
39
+ testNameToEntries[testName].push({ filePath, uuid });
40
+ }
41
+ });
42
+
43
+ const duplicates = {};
44
+
45
+ Object.entries(testNameToEntries).forEach(([testName, entries]) => {
46
+ if (entries.length > 1) {
47
+ duplicates[testName] = entries.map((e) => e.filePath);
48
+ }
49
+ });
50
+
51
+ if (Object.keys(duplicates).length > 0) {
52
+ console.warn(
53
+ "\n\x1b[33m[WARNING] Duplicate scenario names found: This will affect your reporting",
54
+ );
55
+ Object.entries(duplicates).forEach(([testName, files]) => {
56
+ console.log(`\x1b[33m"${testName}" exists in:`);
57
+ files.forEach((file) => {
58
+ console.log(` - ${file}`);
59
+ });
60
+ console.log("");
61
+ });
62
+ console.log("\x1b[0m");
63
+ console.log("");
64
+ }
65
+
66
+ return duplicates;
67
+ }
68
+
69
+ module.exports = { findDuplicateTestNames };