@dev-blinq/cucumber_client 1.0.1301-dev → 1.0.1301-stage
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/bin/assets/bundled_scripts/recorder.js +106 -106
- package/bin/assets/preload/css_gen.js +10 -10
- package/bin/assets/preload/recorderv3.js +3 -1
- package/bin/assets/preload/toolbar.js +27 -29
- package/bin/assets/preload/unique_locators.js +1 -1
- package/bin/assets/preload/yaml.js +288 -275
- package/bin/assets/scripts/aria_snapshot.js +223 -220
- package/bin/assets/scripts/dom_attr.js +329 -329
- package/bin/assets/scripts/dom_parent.js +169 -174
- package/bin/assets/scripts/event_utils.js +94 -94
- package/bin/assets/scripts/pw.js +2050 -1949
- package/bin/assets/scripts/recorder.js +4 -16
- package/bin/assets/scripts/snapshot_capturer.js +153 -146
- package/bin/assets/scripts/unique_locators.js +925 -793
- package/bin/assets/scripts/yaml.js +796 -783
- package/bin/assets/templates/_hooks_template.txt +37 -0
- package/bin/assets/templates/utils_template.txt +1 -46
- package/bin/client/apiTest/apiTest.js +6 -0
- package/bin/client/cli_helpers.js +11 -13
- package/bin/client/code_cleanup/utils.js +5 -1
- package/bin/client/code_gen/api_codegen.js +2 -2
- package/bin/client/code_gen/code_inversion.js +53 -4
- package/bin/client/code_gen/page_reflection.js +839 -906
- package/bin/client/code_gen/playwright_codeget.js +48 -14
- package/bin/client/cucumber/feature.js +89 -27
- package/bin/client/cucumber/feature_data.js +2 -2
- package/bin/client/cucumber/project_to_document.js +9 -3
- package/bin/client/cucumber/steps_definitions.js +90 -87
- package/bin/client/cucumber_selector.js +17 -1
- package/bin/client/local_agent.js +6 -5
- package/bin/client/parse_feature_file.js +23 -26
- package/bin/client/playground/projects/env.json +2 -2
- package/bin/client/project.js +186 -196
- package/bin/client/recorderv3/bvt_recorder.js +168 -55
- package/bin/client/recorderv3/implemented_steps.js +74 -16
- package/bin/client/recorderv3/index.js +69 -22
- package/bin/client/recorderv3/network.js +299 -0
- package/bin/client/recorderv3/scriptTest.js +1 -1
- package/bin/client/recorderv3/services.js +4 -16
- package/bin/client/recorderv3/step_runner.js +329 -72
- package/bin/client/recorderv3/step_utils.js +575 -5
- package/bin/client/recorderv3/update_feature.js +32 -30
- package/bin/client/run_cucumber.js +5 -1
- package/bin/client/scenario_report.js +0 -5
- package/bin/client/test_scenario.js +0 -1
- package/bin/client/upload-service.js +2 -2
- package/bin/client/utils/socket_logger.js +132 -0
- package/bin/index.js +1 -0
- package/bin/logger.js +3 -2
- package/bin/min/consoleApi.min.cjs +2 -3
- package/bin/min/injectedScript.min.cjs +16 -16
- package/package.json +20 -11
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "fs";
|
|
2
2
|
import path from "path";
|
|
3
3
|
import url from "url";
|
|
4
4
|
import logger from "../../logger.js";
|
|
@@ -9,9 +9,425 @@ import { Step } from "../cucumber/feature.js";
|
|
|
9
9
|
import { locateDefinitionPath, StepsDefinitions } from "../cucumber/steps_definitions.js";
|
|
10
10
|
import { Recording } from "../recording.js";
|
|
11
11
|
import { generateApiCode } from "../code_gen/api_codegen.js";
|
|
12
|
+
import { tmpdir } from "os";
|
|
13
|
+
import { createHash } from "crypto";
|
|
12
14
|
|
|
13
15
|
const __dirname = path.dirname(url.fileURLToPath(import.meta.url));
|
|
14
16
|
|
|
17
|
+
const convertToIdentifier = (text) => {
|
|
18
|
+
// replace all invalid characters with _
|
|
19
|
+
return text.replace(/[^a-zA-Z0-9_]/g, "_");
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export const isVariable = (text) => {
|
|
23
|
+
if (typeof text !== "string") return false;
|
|
24
|
+
const isParametric = text.startsWith("<") && text.endsWith(">");
|
|
25
|
+
if (!isParametric) return false;
|
|
26
|
+
const l = text.length;
|
|
27
|
+
if (l < 2) return false;
|
|
28
|
+
const leftindex = text.indexOf("<");
|
|
29
|
+
const rightindex = text.indexOf(">");
|
|
30
|
+
return leftindex === 0 && rightindex === l - 1;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export const extractQuotes = (text) => {
|
|
34
|
+
const stringRegex = /"([^"]*)"/g;
|
|
35
|
+
const matches = text.match(stringRegex);
|
|
36
|
+
if (!matches) return [];
|
|
37
|
+
const quotes = [];
|
|
38
|
+
for (const match of matches) {
|
|
39
|
+
const value = match.slice(1, -1);
|
|
40
|
+
quotes.push(value);
|
|
41
|
+
}
|
|
42
|
+
return quotes;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const replaceLastOccurence = (str, search, replacement) => {
|
|
46
|
+
const lastIndex = str.lastIndexOf(search);
|
|
47
|
+
if (lastIndex === -1) return str;
|
|
48
|
+
return str.substring(0, lastIndex) + replacement + str.substring(lastIndex + search.length);
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const _toRecordingStep = (cmd) => {
|
|
52
|
+
switch (cmd.type) {
|
|
53
|
+
case "hover_element": {
|
|
54
|
+
return {
|
|
55
|
+
type: "hover_element",
|
|
56
|
+
element: {
|
|
57
|
+
role: cmd.role,
|
|
58
|
+
name: cmd.label,
|
|
59
|
+
},
|
|
60
|
+
lastKnownUrlPath: cmd.lastKnownUrlPath,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
case "click_element": {
|
|
64
|
+
return {
|
|
65
|
+
type: "click_element",
|
|
66
|
+
element: {
|
|
67
|
+
role: cmd.role,
|
|
68
|
+
name: cmd.label,
|
|
69
|
+
},
|
|
70
|
+
lastKnownUrlPath: cmd.lastKnownUrlPath,
|
|
71
|
+
count: cmd.count ?? 1,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
case "context_click": {
|
|
75
|
+
return {
|
|
76
|
+
type: "context_click",
|
|
77
|
+
element: {
|
|
78
|
+
role: cmd.role,
|
|
79
|
+
name: cmd.label,
|
|
80
|
+
},
|
|
81
|
+
label: cmd.label,
|
|
82
|
+
value: cmd.value,
|
|
83
|
+
lastKnownUrlPath: cmd.lastKnownUrlPath,
|
|
84
|
+
text: cmd.text,
|
|
85
|
+
count: cmd.count ?? 1,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
case "parameterized_click": {
|
|
89
|
+
return {
|
|
90
|
+
type: "parameterized_click",
|
|
91
|
+
element: {
|
|
92
|
+
role: cmd.role,
|
|
93
|
+
name: cmd.label,
|
|
94
|
+
},
|
|
95
|
+
label: cmd.label,
|
|
96
|
+
value: cmd.value,
|
|
97
|
+
lastKnownUrlPath: cmd.lastKnownUrlPath,
|
|
98
|
+
count: cmd.count ?? 1,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
case "fill_element": {
|
|
102
|
+
return {
|
|
103
|
+
type: "fill_element",
|
|
104
|
+
element: {
|
|
105
|
+
role: cmd.role,
|
|
106
|
+
name: cmd.label,
|
|
107
|
+
},
|
|
108
|
+
parameters: [cmd.value, cmd.enter ?? false],
|
|
109
|
+
lastKnownUrlPath: cmd.lastKnownUrlPath,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
case "select_combobox": {
|
|
113
|
+
return {
|
|
114
|
+
type: "select_combobox",
|
|
115
|
+
element: {
|
|
116
|
+
role: "combobox",
|
|
117
|
+
name: cmd.label,
|
|
118
|
+
},
|
|
119
|
+
selectMode: "select",
|
|
120
|
+
parameters: [cmd.value],
|
|
121
|
+
lastKnownUrlPath: cmd.lastKnownUrlPath,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
case "verify_page_contains_text": {
|
|
125
|
+
return {
|
|
126
|
+
type: "verify_page_contains_text",
|
|
127
|
+
parameters: [cmd.value, cmd.isRegex],
|
|
128
|
+
lastKnownUrlPath: cmd.lastKnownUrlPath,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
case "verify_element_contains_text": {
|
|
132
|
+
return {
|
|
133
|
+
type: "verify_element_contains_text",
|
|
134
|
+
element: {
|
|
135
|
+
role: cmd.role,
|
|
136
|
+
name: cmd.label,
|
|
137
|
+
},
|
|
138
|
+
parameters: [cmd.value, cmd.climb],
|
|
139
|
+
lastKnownUrlPath: cmd.lastKnownUrlPath,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
case "close_page": {
|
|
143
|
+
return {
|
|
144
|
+
type: "close_page",
|
|
145
|
+
lastKnownUrlPath: cmd.lastKnownUrlPath,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
case "check_element": {
|
|
149
|
+
return {
|
|
150
|
+
type: "check_element",
|
|
151
|
+
element: {
|
|
152
|
+
role: cmd.role,
|
|
153
|
+
name: cmd.label,
|
|
154
|
+
},
|
|
155
|
+
check: cmd.check,
|
|
156
|
+
lastKnownUrlPath: cmd.lastKnownUrlPath,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
case "press_key": {
|
|
160
|
+
return {
|
|
161
|
+
type: "press_key",
|
|
162
|
+
element: {
|
|
163
|
+
role: cmd.role,
|
|
164
|
+
name: cmd.label,
|
|
165
|
+
},
|
|
166
|
+
key: cmd.value,
|
|
167
|
+
lastKnownUrlPath: cmd.lastKnownUrlPath,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
case "load_user": {
|
|
171
|
+
return {
|
|
172
|
+
type: "load_data",
|
|
173
|
+
parameters: ["users", cmd.value],
|
|
174
|
+
lastKnownUrlPath: cmd.lastKnownUrlPath,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
case "load_csv": {
|
|
178
|
+
return {
|
|
179
|
+
type: "load_data",
|
|
180
|
+
parameters: ["csv", `${cmd.label}:${cmd.value}`],
|
|
181
|
+
lastKnownUrlPath: cmd.lastKnownUrlPath,
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
case "set_date_time": {
|
|
185
|
+
return {
|
|
186
|
+
type: "set_date_time",
|
|
187
|
+
element: {
|
|
188
|
+
role: cmd.role,
|
|
189
|
+
name: cmd.label,
|
|
190
|
+
},
|
|
191
|
+
parameters: [cmd.value],
|
|
192
|
+
lastKnownUrlPath: cmd.lastKnownUrlPath,
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
case "set_input": {
|
|
196
|
+
return {
|
|
197
|
+
type: "set_input",
|
|
198
|
+
element: {
|
|
199
|
+
role: cmd.role,
|
|
200
|
+
name: cmd.label,
|
|
201
|
+
},
|
|
202
|
+
value: cmd.value,
|
|
203
|
+
parameters: [cmd.value],
|
|
204
|
+
lastKnownUrlPath: cmd.lastKnownUrlPath,
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
case "extract_attribute": {
|
|
208
|
+
return {
|
|
209
|
+
type: "extract_attribute",
|
|
210
|
+
element: {
|
|
211
|
+
role: cmd.role,
|
|
212
|
+
name: cmd.label,
|
|
213
|
+
},
|
|
214
|
+
parameters: [cmd.selectedField, cmd.variableName],
|
|
215
|
+
lastKnownUrlPath: cmd.lastKnownUrlPath,
|
|
216
|
+
regex: cmd.regex,
|
|
217
|
+
trimSpaces: cmd.trimSpaces,
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
case "extract_property": {
|
|
221
|
+
return {
|
|
222
|
+
type: "extract_property",
|
|
223
|
+
element: {
|
|
224
|
+
role: cmd.role,
|
|
225
|
+
name: cmd.label,
|
|
226
|
+
},
|
|
227
|
+
parameters: [cmd.selectedField, cmd.variableName],
|
|
228
|
+
lastKnownUrlPath: cmd.lastKnownUrlPath,
|
|
229
|
+
regex: cmd.regex,
|
|
230
|
+
trimSpaces: cmd.trimSpaces,
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
case "verify_element_attribute": {
|
|
234
|
+
return {
|
|
235
|
+
type: "verify_element_attribute",
|
|
236
|
+
element: {
|
|
237
|
+
role: cmd.role,
|
|
238
|
+
name: cmd.label,
|
|
239
|
+
},
|
|
240
|
+
parameters: [cmd.selectedField, cmd.value],
|
|
241
|
+
lastKnownUrlPath: cmd.lastKnownUrlPath,
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
case "verify_element_property": {
|
|
245
|
+
return {
|
|
246
|
+
type: "verify_element_property",
|
|
247
|
+
element: {
|
|
248
|
+
role: cmd.role,
|
|
249
|
+
name: cmd.label,
|
|
250
|
+
},
|
|
251
|
+
parameters: [cmd.selectedField, cmd.value],
|
|
252
|
+
lastKnownUrlPath: cmd.lastKnownUrlPath,
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
case "conditional_wait": {
|
|
256
|
+
return {
|
|
257
|
+
type: "conditional_wait",
|
|
258
|
+
element: {
|
|
259
|
+
role: cmd.role,
|
|
260
|
+
name: cmd.label,
|
|
261
|
+
},
|
|
262
|
+
parameters: [cmd.timeout, cmd.selectedField, cmd.value],
|
|
263
|
+
lastKnownUrlPath: cmd.lastKnownUrlPath,
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
case "navigate": {
|
|
267
|
+
return {
|
|
268
|
+
type: "navigate",
|
|
269
|
+
parameters: [cmd.value],
|
|
270
|
+
lastKnownUrlPath: cmd.lastKnownUrlPath,
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
case "browser_go_back": {
|
|
274
|
+
return {
|
|
275
|
+
type: "browser_go_back",
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
case "browser_go_forward": {
|
|
279
|
+
return {
|
|
280
|
+
type: "browser_go_forward",
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
case "set_input_files": {
|
|
284
|
+
return {
|
|
285
|
+
type: "set_input_files",
|
|
286
|
+
element: {
|
|
287
|
+
role: cmd.role,
|
|
288
|
+
name: cmd.label,
|
|
289
|
+
},
|
|
290
|
+
parameters: [cmd.files],
|
|
291
|
+
lastKnownUrlPath: cmd.lastKnownUrlPath,
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
case "verify_page_snapshot": {
|
|
295
|
+
return {
|
|
296
|
+
type: "verify_page_snapshot",
|
|
297
|
+
parameters: [cmd.value],
|
|
298
|
+
selectors: cmd.selectors,
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
default: {
|
|
302
|
+
return {
|
|
303
|
+
type: cmd.type,
|
|
304
|
+
parameters: [cmd.value],
|
|
305
|
+
lastKnownUrlPath: cmd.lastKnownUrlPath,
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
function getBestStrategy(allStrategyLocators) {
|
|
312
|
+
const orderedPriorities = ["custom", "context", "basic", "text_with_index", "ignore_digit", "no_text"];
|
|
313
|
+
for (const strategy of orderedPriorities) {
|
|
314
|
+
if (allStrategyLocators[strategy] && allStrategyLocators[strategy].length > 0) {
|
|
315
|
+
return strategy;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
return null;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
const _parameterizeLocators = (locators, replacementFromValue, replacementToValue) => {
|
|
322
|
+
for (const loc of locators) {
|
|
323
|
+
if (loc?.css?.includes(replacementFromValue)) {
|
|
324
|
+
loc.css = loc.css.replaceAll(replacementFromValue, replacementToValue);
|
|
325
|
+
}
|
|
326
|
+
if (loc?.text?.includes(replacementFromValue)) {
|
|
327
|
+
loc.text = loc.text.replaceAll(replacementFromValue, replacementToValue);
|
|
328
|
+
}
|
|
329
|
+
if (loc?.climb && typeof loc.climb === "string" && loc.climb?.includes(replacementFromValue)) {
|
|
330
|
+
loc.climb = loc.climb.replaceAll(replacementFromValue, replacementToValue);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
return locators;
|
|
334
|
+
};
|
|
335
|
+
const parameterizeLocators = ({ cmd, locs, isValueVariable, isTextVariable, parametersMap }) => {
|
|
336
|
+
if (isValueVariable) {
|
|
337
|
+
const variable = cmd.value.slice(1, -1);
|
|
338
|
+
const val = parametersMap[variable];
|
|
339
|
+
const replacementFromValue = val.trim();
|
|
340
|
+
const replacementToValue = `{${variable}}`;
|
|
341
|
+
locs = _parameterizeLocators(locs, replacementFromValue, replacementToValue);
|
|
342
|
+
}
|
|
343
|
+
if (isTextVariable) {
|
|
344
|
+
const variable = cmd.text.slice(1, -1);
|
|
345
|
+
const val = parametersMap[variable];
|
|
346
|
+
const replacementFromValue = val.trim();
|
|
347
|
+
const replacementToValue = `{${variable}}`;
|
|
348
|
+
locs = _parameterizeLocators(locs, replacementFromValue, replacementToValue);
|
|
349
|
+
}
|
|
350
|
+
return locs;
|
|
351
|
+
};
|
|
352
|
+
|
|
353
|
+
//TODO: IMPORTAN
|
|
354
|
+
export const toRecordingStep = (cmd, parametersMap) => {
|
|
355
|
+
if (cmd.type === "api") {
|
|
356
|
+
return {
|
|
357
|
+
type: "api",
|
|
358
|
+
value: cmd.value,
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
const step = _toRecordingStep(cmd);
|
|
362
|
+
const cmdID = {
|
|
363
|
+
cmdId: cmd.id,
|
|
364
|
+
};
|
|
365
|
+
Object.assign(step, cmdID);
|
|
366
|
+
|
|
367
|
+
const locatorsObject = JSON.parse(JSON.stringify(cmd.locators ?? null));
|
|
368
|
+
|
|
369
|
+
if (!locatorsObject) return step;
|
|
370
|
+
|
|
371
|
+
const element_name = cmd?.locators?.element_name ?? `${cmd.label} ${cmd.role ?? "Text"}`;
|
|
372
|
+
locatorsObject.element_name = element_name;
|
|
373
|
+
|
|
374
|
+
const isValueVariable = isVariable(cmd.value);
|
|
375
|
+
const isTextVariable = isVariable(cmd.text);
|
|
376
|
+
const allStrategyLocators = JSON.parse(JSON.stringify(cmd?.allStrategyLocators ?? null));
|
|
377
|
+
step.locators = locatorsObject;
|
|
378
|
+
step.allStrategyLocators = allStrategyLocators;
|
|
379
|
+
step.isLocatorsAssigned = true;
|
|
380
|
+
|
|
381
|
+
if (!isValueVariable && !isTextVariable) {
|
|
382
|
+
return step;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
if (isValueVariable) {
|
|
386
|
+
step.dataSource = "parameters";
|
|
387
|
+
step.dataKey = convertToIdentifier(cmd.value.slice(1, -1));
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
if (!allStrategyLocators) {
|
|
391
|
+
let locs = locatorsObject.locators;
|
|
392
|
+
locs = parameterizeLocators({
|
|
393
|
+
cmd,
|
|
394
|
+
locs,
|
|
395
|
+
isValueVariable,
|
|
396
|
+
isTextVariable,
|
|
397
|
+
parametersMap,
|
|
398
|
+
});
|
|
399
|
+
locatorsObject.locators = locs;
|
|
400
|
+
return {
|
|
401
|
+
...step,
|
|
402
|
+
locators: locatorsObject,
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
for (const key in allStrategyLocators) {
|
|
407
|
+
if (key === "strategy") continue;
|
|
408
|
+
if (key === "no_text" || key === "custom") continue;
|
|
409
|
+
const locators = allStrategyLocators[key];
|
|
410
|
+
if (locators.length === 0) continue;
|
|
411
|
+
parameterizeLocators({
|
|
412
|
+
cmd,
|
|
413
|
+
locs: locators,
|
|
414
|
+
isValueVariable,
|
|
415
|
+
isTextVariable,
|
|
416
|
+
parametersMap,
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
locatorsObject.locators = allStrategyLocators[allStrategyLocators.strategy] ?? locatorsObject.locators;
|
|
421
|
+
|
|
422
|
+
|
|
423
|
+
return {
|
|
424
|
+
...step,
|
|
425
|
+
locators: locatorsObject,
|
|
426
|
+
allStrategyLocators,
|
|
427
|
+
isLocatorsAssigned: true,
|
|
428
|
+
};
|
|
429
|
+
};
|
|
430
|
+
|
|
15
431
|
export const toMethodName = (str) => {
|
|
16
432
|
// Remove any non-word characters (excluding underscore) and trim spaces
|
|
17
433
|
let cleanStr = str.trim().replace(/[^\w\s]/gi, "");
|
|
@@ -68,22 +484,82 @@ function makeStepTextUnique(step, stepsDefinitions) {
|
|
|
68
484
|
step.text = stepText;
|
|
69
485
|
}
|
|
70
486
|
|
|
71
|
-
export async function saveRecording({ step, cucumberStep, codePage, projectDir, stepsDefinitions }) {
|
|
72
|
-
|
|
487
|
+
export async function saveRecording({ step, cucumberStep, codePage, projectDir, stepsDefinitions, parametersMap }) {
|
|
488
|
+
if (step.commands && Array.isArray(step.commands)) {
|
|
489
|
+
step.commands = step.commands.map((cmd) => toRecordingStep(cmd, parametersMap));
|
|
490
|
+
}
|
|
491
|
+
let routesPath = path.join(tmpdir(), "blinq_temp_routes");
|
|
492
|
+
|
|
493
|
+
if (process.env.TEMP_RUN === "true") {
|
|
494
|
+
if (existsSync(routesPath)) {
|
|
495
|
+
rmSync(routesPath, { recursive: true });
|
|
496
|
+
}
|
|
497
|
+
mkdirSync(routesPath, { recursive: true });
|
|
498
|
+
saveRoutes({ step, folderPath: routesPath });
|
|
499
|
+
} else {
|
|
500
|
+
if (existsSync(routesPath)) {
|
|
501
|
+
// remove the folder
|
|
502
|
+
try {
|
|
503
|
+
rmSync(routesPath, { recursive: true });
|
|
504
|
+
console.log("Removed temp_routes_folder:", routesPath);
|
|
505
|
+
} catch (error) {
|
|
506
|
+
console.error("Error removing temp_routes folder", error);
|
|
507
|
+
}
|
|
508
|
+
routesPath = path.join(projectDir, "data", "routes");
|
|
509
|
+
if (!existsSync(routesPath)) {
|
|
510
|
+
mkdirSync(routesPath, { recursive: true });
|
|
511
|
+
}
|
|
512
|
+
saveRoutes({ step, folderPath: routesPath });
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
|
|
73
516
|
if (step.isImplementedWhileRecording && !process.env.TEMP_RUN) {
|
|
74
517
|
return;
|
|
75
518
|
}
|
|
519
|
+
|
|
76
520
|
if (step.isImplemented && step.shouldOverride) {
|
|
77
521
|
let stepDef = stepsDefinitions.findMatchingStep(step.text);
|
|
78
522
|
codePage = getCodePage(stepDef.file);
|
|
79
523
|
} else {
|
|
80
524
|
const isUtilStep = makeStepTextUnique(step, stepsDefinitions);
|
|
525
|
+
|
|
81
526
|
if (isUtilStep) {
|
|
82
527
|
return;
|
|
83
528
|
}
|
|
84
529
|
}
|
|
530
|
+
|
|
531
|
+
routesPath = path.join(tmpdir(), "blinq_temp_routes");
|
|
532
|
+
if (process.env.TEMP_RUN === "true") {
|
|
533
|
+
console.log("Save routes in temp folder for running:", routesPath);
|
|
534
|
+
if (existsSync(routesPath)) {
|
|
535
|
+
console.log("Removing existing temp_routes_folder:", routesPath);
|
|
536
|
+
rmSync(routesPath, { recursive: true });
|
|
537
|
+
}
|
|
538
|
+
mkdirSync(routesPath, { recursive: true });
|
|
539
|
+
console.log("Created temp_routes_folder:", routesPath);
|
|
540
|
+
saveRoutes({ step, folderPath: routesPath });
|
|
541
|
+
} else {
|
|
542
|
+
console.log("Saving routes in project directory:", projectDir);
|
|
543
|
+
if (existsSync(routesPath)) {
|
|
544
|
+
// remove the folder
|
|
545
|
+
try {
|
|
546
|
+
rmSync(routesPath, { recursive: true });
|
|
547
|
+
console.log("Removed temp_routes_folder:", routesPath);
|
|
548
|
+
} catch (error) {
|
|
549
|
+
console.error("Error removing temp_routes folder", error);
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
routesPath = path.join(projectDir, "data", "routes");
|
|
553
|
+
console.log("Saving routes to:", routesPath);
|
|
554
|
+
if (!existsSync(routesPath)) {
|
|
555
|
+
mkdirSync(routesPath, { recursive: true });
|
|
556
|
+
}
|
|
557
|
+
saveRoutes({ step, folderPath: routesPath });
|
|
558
|
+
}
|
|
559
|
+
|
|
85
560
|
cucumberStep.text = step.text;
|
|
86
561
|
const recording = new Recording();
|
|
562
|
+
|
|
87
563
|
const steps = step.commands;
|
|
88
564
|
|
|
89
565
|
recording.loadFromObject({ steps, step: cucumberStep });
|
|
@@ -108,6 +584,7 @@ export async function saveRecording({ step, cucumberStep, codePage, projectDir,
|
|
|
108
584
|
isStaticToken,
|
|
109
585
|
status,
|
|
110
586
|
} = step.commands[0].value;
|
|
587
|
+
|
|
111
588
|
const result = await generateApiCode(
|
|
112
589
|
{
|
|
113
590
|
url,
|
|
@@ -132,6 +609,7 @@ export async function saveRecording({ step, cucumberStep, codePage, projectDir,
|
|
|
132
609
|
step.keyword,
|
|
133
610
|
stepsDefinitions
|
|
134
611
|
);
|
|
612
|
+
|
|
135
613
|
if (!step.isImplemented) {
|
|
136
614
|
stepsDefinitions.addStep({
|
|
137
615
|
name: step.text,
|
|
@@ -139,6 +617,7 @@ export async function saveRecording({ step, cucumberStep, codePage, projectDir,
|
|
|
139
617
|
source: "recorder",
|
|
140
618
|
});
|
|
141
619
|
}
|
|
620
|
+
|
|
142
621
|
cucumberStep.methodName = result.methodName;
|
|
143
622
|
return result.codePage;
|
|
144
623
|
} else {
|
|
@@ -156,12 +635,18 @@ export async function saveRecording({ step, cucumberStep, codePage, projectDir,
|
|
|
156
635
|
if (step.commands && step.commands.length > 0 && step.commands[0]) {
|
|
157
636
|
path = step.commands[0].lastKnownUrlPath;
|
|
158
637
|
}
|
|
638
|
+
let protect = false;
|
|
639
|
+
if (step.commands && step.commands.length > 0 && step.commands[0].type) {
|
|
640
|
+
if (step.commands[0].type === "verify_element_property" || step.commands[0].type === "conditional_wait") {
|
|
641
|
+
protect = true;
|
|
642
|
+
}
|
|
643
|
+
}
|
|
159
644
|
const infraResult = codePage.addInfraCommand(
|
|
160
645
|
methodName,
|
|
161
646
|
description,
|
|
162
647
|
cucumberStep.getVariablesList(),
|
|
163
648
|
generateCodeResult.codeLines,
|
|
164
|
-
|
|
649
|
+
protect,
|
|
165
650
|
"recorder",
|
|
166
651
|
path
|
|
167
652
|
);
|
|
@@ -183,6 +668,7 @@ export async function saveRecording({ step, cucumberStep, codePage, projectDir,
|
|
|
183
668
|
}
|
|
184
669
|
|
|
185
670
|
codePage.removeUnusedElements();
|
|
671
|
+
codePage.mergeSimilarElements();
|
|
186
672
|
cucumberStep.methodName = methodName;
|
|
187
673
|
if (generateCodeResult.locatorsMetadata) {
|
|
188
674
|
codePage.addLocatorsMetadata(generateCodeResult.locatorsMetadata);
|
|
@@ -312,6 +798,12 @@ export async function updateStepDefinitions({ scenario, featureName, projectDir
|
|
|
312
798
|
const utilsTemplateFilePath = path.join(__dirname, "../../assets", "templates", "utils_template.txt");
|
|
313
799
|
const utilsContent = readFileSync(utilsTemplateFilePath, "utf8");
|
|
314
800
|
writeFileSync(utilsFilePath, utilsContent, "utf8");
|
|
801
|
+
const hooksTemplateFilePath = path.join(__dirname, "../../assets", "templates", "_hooks_template.txt");
|
|
802
|
+
if (existsSync(hooksTemplateFilePath)) {
|
|
803
|
+
const hooksFilePath = path.join(stepDefinitionFolderPath, "_hooks.mjs");
|
|
804
|
+
const hooksContent = readFileSync(hooksTemplateFilePath, "utf8");
|
|
805
|
+
writeFileSync(hooksFilePath, hooksContent, "utf8");
|
|
806
|
+
}
|
|
315
807
|
const steps = scenario.steps;
|
|
316
808
|
|
|
317
809
|
const stepsDefinitions = new StepsDefinitions(projectDir);
|
|
@@ -327,6 +819,35 @@ export async function updateStepDefinitions({ scenario, featureName, projectDir
|
|
|
327
819
|
}
|
|
328
820
|
}
|
|
329
821
|
if ((step.isImplemented && !step.shouldOverride) || step.commands.length === 0) {
|
|
822
|
+
let routesPath = path.join(tmpdir(), `blinq_temp_routes`);
|
|
823
|
+
if (process.env.TEMP_RUN === "true") {
|
|
824
|
+
console.log("Save routes in temp folder for running:", routesPath);
|
|
825
|
+
if (existsSync(routesPath)) {
|
|
826
|
+
console.log("Removing existing temp_routes_folder:", routesPath);
|
|
827
|
+
routesPath = path.join(tmpdir(), `blinq_temp_routes`);
|
|
828
|
+
rmSync(routesPath, { recursive: true });
|
|
829
|
+
}
|
|
830
|
+
mkdirSync(routesPath, { recursive: true });
|
|
831
|
+
console.log("Created temp_routes_folder:", routesPath);
|
|
832
|
+
saveRoutes({ step, folderPath: routesPath });
|
|
833
|
+
} else {
|
|
834
|
+
console.log("Saving routes in project directory:", projectDir);
|
|
835
|
+
if (existsSync(routesPath)) {
|
|
836
|
+
// remove the folder
|
|
837
|
+
try {
|
|
838
|
+
rmSync(routesPath, { recursive: true });
|
|
839
|
+
console.log("Removed temp_routes_folder:", routesPath);
|
|
840
|
+
} catch (error) {
|
|
841
|
+
console.error("Error removing temp_routes folder", error);
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
routesPath = path.join(projectDir, "data", "routes");
|
|
845
|
+
console.log("Saving routes to:", routesPath);
|
|
846
|
+
if (!existsSync(routesPath)) {
|
|
847
|
+
mkdirSync(routesPath, { recursive: true });
|
|
848
|
+
}
|
|
849
|
+
saveRoutes({ step, folderPath: routesPath });
|
|
850
|
+
}
|
|
330
851
|
continue;
|
|
331
852
|
}
|
|
332
853
|
const cucumberStep = getCucumberStep({ step });
|
|
@@ -334,7 +855,14 @@ export async function updateStepDefinitions({ scenario, featureName, projectDir
|
|
|
334
855
|
const stepDefsFilePath = locateDefinitionPath(featureFolder, pageName);
|
|
335
856
|
// path.join(stepDefinitionFolderPath, pageName + "_page.mjs");
|
|
336
857
|
let codePage = getCodePage(stepDefsFilePath);
|
|
337
|
-
codePage = await saveRecording({
|
|
858
|
+
codePage = await saveRecording({
|
|
859
|
+
step,
|
|
860
|
+
cucumberStep,
|
|
861
|
+
codePage,
|
|
862
|
+
projectDir,
|
|
863
|
+
stepsDefinitions,
|
|
864
|
+
parametersMap: scenario.parametersMap,
|
|
865
|
+
});
|
|
338
866
|
if (!codePage) {
|
|
339
867
|
continue;
|
|
340
868
|
}
|
|
@@ -345,3 +873,45 @@ export async function updateStepDefinitions({ scenario, featureName, projectDir
|
|
|
345
873
|
}
|
|
346
874
|
writeFileSync(utilsFilePath, utilsContent, "utf8");
|
|
347
875
|
}
|
|
876
|
+
|
|
877
|
+
export function saveRoutes({ step, folderPath }) {
|
|
878
|
+
const routeItems = step.routeItems;
|
|
879
|
+
if (!routeItems || routeItems.length === 0) {
|
|
880
|
+
return;
|
|
881
|
+
}
|
|
882
|
+
const cucumberStep = getCucumberStep({ step });
|
|
883
|
+
const template = cucumberStep.getTemplate();
|
|
884
|
+
const stepNameHash = createHash("sha256").update(template).digest("hex");
|
|
885
|
+
console.log("Saving routes for step:", step.text, "with hash:", stepNameHash);
|
|
886
|
+
|
|
887
|
+
const routeItemsWithFilters = routeItems.map((routeItem) => {
|
|
888
|
+
const oldFilters = routeItem.filters;
|
|
889
|
+
const queryParamsObject = {};
|
|
890
|
+
oldFilters.queryParams.forEach((queryParam) => {
|
|
891
|
+
queryParamsObject[queryParam.key] = queryParam.value;
|
|
892
|
+
});
|
|
893
|
+
const newFilters = { path: oldFilters.path, method: oldFilters.method, queryParams: queryParamsObject };
|
|
894
|
+
return {
|
|
895
|
+
...routeItem,
|
|
896
|
+
filters: newFilters,
|
|
897
|
+
};
|
|
898
|
+
});
|
|
899
|
+
|
|
900
|
+
const routesFilePath = path.join(folderPath, stepNameHash + ".json");
|
|
901
|
+
console.log("Routes file path:", routesFilePath);
|
|
902
|
+
const routesData = {
|
|
903
|
+
template,
|
|
904
|
+
routes: routeItemsWithFilters,
|
|
905
|
+
};
|
|
906
|
+
console.log("Routes data to save:", routesData);
|
|
907
|
+
|
|
908
|
+
if (!existsSync(folderPath)) {
|
|
909
|
+
mkdirSync(folderPath, { recursive: true });
|
|
910
|
+
}
|
|
911
|
+
try {
|
|
912
|
+
writeFileSync(routesFilePath, JSON.stringify(routesData, null, 2), "utf8");
|
|
913
|
+
console.log("Saved routes to", routesFilePath);
|
|
914
|
+
} catch (error) {
|
|
915
|
+
console.error("Failed to save routes to", routesFilePath, "Error:", error);
|
|
916
|
+
}
|
|
917
|
+
}
|