@dev-blinq/cucumber_client 1.0.1280-dev → 1.0.1280-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/recorderv3.js +3 -1
- package/bin/assets/scripts/dom_parent.js +4 -0
- package/bin/assets/scripts/recorder.js +4 -1
- package/bin/assets/scripts/unique_locators.js +837 -815
- package/bin/assets/templates/_hooks_template.txt +37 -0
- package/bin/assets/templates/page_template.txt +2 -16
- 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/code_inversion.js +53 -4
- package/bin/client/code_gen/page_reflection.js +838 -902
- package/bin/client/code_gen/playwright_codeget.js +43 -12
- package/bin/client/cucumber/feature.js +89 -27
- package/bin/client/cucumber/project_to_document.js +1 -1
- package/bin/client/cucumber/steps_definitions.js +84 -81
- package/bin/client/cucumber_selector.js +17 -1
- package/bin/client/local_agent.js +7 -6
- package/bin/client/project.js +186 -196
- package/bin/client/recorderv3/bvt_recorder.js +170 -60
- package/bin/client/recorderv3/implemented_steps.js +74 -16
- package/bin/client/recorderv3/index.js +50 -25
- package/bin/client/recorderv3/network.js +299 -0
- package/bin/client/recorderv3/services.js +4 -16
- package/bin/client/recorderv3/step_runner.js +332 -69
- package/bin/client/recorderv3/step_utils.js +578 -7
- 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/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 +22 -13
|
@@ -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,431 @@ 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 = [
|
|
313
|
+
"custom",
|
|
314
|
+
"context",
|
|
315
|
+
"basic",
|
|
316
|
+
"text_with_index",
|
|
317
|
+
"ignore_digit",
|
|
318
|
+
"no_text",
|
|
319
|
+
];
|
|
320
|
+
for (const strategy of orderedPriorities) {
|
|
321
|
+
if (allStrategyLocators[strategy] && allStrategyLocators[strategy].length > 0) {
|
|
322
|
+
return strategy;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
return null;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
const _parameterizeLocators = (locators, replacementFromValue, replacementToValue) => {
|
|
330
|
+
for (const loc of locators) {
|
|
331
|
+
if (loc?.css?.includes(replacementFromValue)) {
|
|
332
|
+
loc.css = loc.css.replaceAll(replacementFromValue, replacementToValue);
|
|
333
|
+
}
|
|
334
|
+
if (loc?.text?.includes(replacementFromValue)) {
|
|
335
|
+
loc.text = loc.text.replaceAll(replacementFromValue, replacementToValue);
|
|
336
|
+
}
|
|
337
|
+
if (loc?.climb && typeof loc.climb === "string" && loc.climb?.includes(replacementFromValue)) {
|
|
338
|
+
loc.climb = loc.climb.replaceAll(replacementFromValue, replacementToValue);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
return locators;
|
|
342
|
+
}
|
|
343
|
+
const parameterizeLocators = ({
|
|
344
|
+
cmd, locs, isValueVariable, isTextVariable,
|
|
345
|
+
parametersMap
|
|
346
|
+
}) => {
|
|
347
|
+
if (isValueVariable) {
|
|
348
|
+
const variable = cmd.value.slice(1, -1);
|
|
349
|
+
const val = parametersMap[variable];
|
|
350
|
+
const replacementFromValue = val.trim();
|
|
351
|
+
const replacementToValue = `{${variable}}`
|
|
352
|
+
locs = _parameterizeLocators(locs, replacementFromValue, replacementToValue);
|
|
353
|
+
}
|
|
354
|
+
if (isTextVariable) {
|
|
355
|
+
const variable = cmd.text.slice(1, -1);
|
|
356
|
+
const val = parametersMap[variable];
|
|
357
|
+
const replacementFromValue = val.trim();
|
|
358
|
+
const replacementToValue = `{${variable}}`
|
|
359
|
+
locs = _parameterizeLocators(locs, replacementFromValue, replacementToValue);
|
|
360
|
+
}
|
|
361
|
+
return locs
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
//TODO: IMPORTAN
|
|
365
|
+
export const toRecordingStep = (cmd, parametersMap) => {
|
|
366
|
+
if (cmd.type === "api") {
|
|
367
|
+
return {
|
|
368
|
+
type: "api",
|
|
369
|
+
value: cmd.value,
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
const step = _toRecordingStep(cmd);
|
|
373
|
+
const cmdID = {
|
|
374
|
+
cmdId: cmd.id,
|
|
375
|
+
};
|
|
376
|
+
Object.assign(step, cmdID);
|
|
377
|
+
|
|
378
|
+
const locatorsObject = JSON.parse(JSON.stringify(cmd.locators ?? null));
|
|
379
|
+
|
|
380
|
+
if (!locatorsObject) return step;
|
|
381
|
+
const isValueVariable = isVariable(cmd.value);
|
|
382
|
+
const isTextVariable = isVariable(cmd.text);
|
|
383
|
+
const allStrategyLocators = JSON.parse(JSON.stringify(cmd?.allStrategyLocators ?? null));
|
|
384
|
+
step.locators = locatorsObject;
|
|
385
|
+
step.allStrategyLocators = allStrategyLocators;
|
|
386
|
+
step.isLocatorsAssigned = true;
|
|
387
|
+
|
|
388
|
+
if (!isValueVariable && !isTextVariable) {
|
|
389
|
+
return step;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
if (isValueVariable) {
|
|
393
|
+
step.dataSource = "parameters";
|
|
394
|
+
step.dataKey = convertToIdentifier(cmd.value.slice(1, -1))
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
if (!allStrategyLocators) {
|
|
398
|
+
let locs = locatorsObject.locators;
|
|
399
|
+
locs = parameterizeLocators({
|
|
400
|
+
cmd,
|
|
401
|
+
locs,
|
|
402
|
+
isValueVariable,
|
|
403
|
+
isTextVariable,
|
|
404
|
+
parametersMap
|
|
405
|
+
});
|
|
406
|
+
locatorsObject.locators = locs;
|
|
407
|
+
return {
|
|
408
|
+
...step,
|
|
409
|
+
locators: locatorsObject
|
|
410
|
+
};
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
for (const key in allStrategyLocators) {
|
|
414
|
+
if (key === "strategy") continue;
|
|
415
|
+
if (key === "no_text" || key === "custom") continue;
|
|
416
|
+
const locators = allStrategyLocators[key];
|
|
417
|
+
if (locators.length === 0) continue;
|
|
418
|
+
parameterizeLocators({
|
|
419
|
+
cmd,
|
|
420
|
+
locs: locators,
|
|
421
|
+
isValueVariable,
|
|
422
|
+
isTextVariable,
|
|
423
|
+
parametersMap
|
|
424
|
+
});
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
locatorsObject.locators = allStrategyLocators[allStrategyLocators.strategy] ?? locatorsObject.locators;
|
|
428
|
+
|
|
429
|
+
return {
|
|
430
|
+
...step,
|
|
431
|
+
locators: locatorsObject,
|
|
432
|
+
allStrategyLocators,
|
|
433
|
+
isLocatorsAssigned: true
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
|
|
15
437
|
export const toMethodName = (str) => {
|
|
16
438
|
// Remove any non-word characters (excluding underscore) and trim spaces
|
|
17
439
|
let cleanStr = str.trim().replace(/[^\w\s]/gi, "");
|
|
@@ -68,22 +490,79 @@ function makeStepTextUnique(step, stepsDefinitions) {
|
|
|
68
490
|
step.text = stepText;
|
|
69
491
|
}
|
|
70
492
|
|
|
71
|
-
export async function saveRecording({ step, cucumberStep, codePage, projectDir, stepsDefinitions }) {
|
|
72
|
-
|
|
493
|
+
export async function saveRecording({ step, cucumberStep, codePage, projectDir, stepsDefinitions, parametersMap }) {
|
|
494
|
+
let routesPath = path.join(tmpdir(), "blinq_temp_routes");
|
|
495
|
+
|
|
496
|
+
if (process.env.TEMP_RUN === "true") {
|
|
497
|
+
if (existsSync(routesPath)) {
|
|
498
|
+
rmSync(routesPath, { recursive: true });
|
|
499
|
+
}
|
|
500
|
+
mkdirSync(routesPath, { recursive: true });
|
|
501
|
+
saveRoutes({ step, folderPath: routesPath });
|
|
502
|
+
} else {
|
|
503
|
+
if (existsSync(routesPath)) {
|
|
504
|
+
// remove the folder
|
|
505
|
+
try {
|
|
506
|
+
rmSync(routesPath, { recursive: true });
|
|
507
|
+
console.log("Removed temp_routes_folder:", routesPath);
|
|
508
|
+
} catch (error) {
|
|
509
|
+
console.error("Error removing temp_routes folder", error);
|
|
510
|
+
}
|
|
511
|
+
routesPath = path.join(projectDir, "data", "routes");
|
|
512
|
+
if (!existsSync(routesPath)) {
|
|
513
|
+
mkdirSync(routesPath, { recursive: true });
|
|
514
|
+
}
|
|
515
|
+
saveRoutes({ step, folderPath: routesPath });
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
|
|
73
519
|
if (step.isImplementedWhileRecording && !process.env.TEMP_RUN) {
|
|
74
520
|
return;
|
|
75
521
|
}
|
|
522
|
+
|
|
76
523
|
if (step.isImplemented && step.shouldOverride) {
|
|
77
524
|
let stepDef = stepsDefinitions.findMatchingStep(step.text);
|
|
78
525
|
codePage = getCodePage(stepDef.file);
|
|
79
526
|
} else {
|
|
80
527
|
const isUtilStep = makeStepTextUnique(step, stepsDefinitions);
|
|
528
|
+
|
|
81
529
|
if (isUtilStep) {
|
|
82
530
|
return;
|
|
83
531
|
}
|
|
84
532
|
}
|
|
533
|
+
|
|
534
|
+
routesPath = path.join(tmpdir(), "blinq_temp_routes");
|
|
535
|
+
if (process.env.TEMP_RUN === "true") {
|
|
536
|
+
console.log("Save routes in temp folder for running:", routesPath);
|
|
537
|
+
if (existsSync(routesPath)) {
|
|
538
|
+
console.log("Removing existing temp_routes_folder:", routesPath);
|
|
539
|
+
rmSync(routesPath, { recursive: true });
|
|
540
|
+
}
|
|
541
|
+
mkdirSync(routesPath, { recursive: true });
|
|
542
|
+
console.log("Created temp_routes_folder:", routesPath);
|
|
543
|
+
saveRoutes({ step, folderPath: routesPath });
|
|
544
|
+
} else {
|
|
545
|
+
console.log("Saving routes in project directory:", projectDir);
|
|
546
|
+
if (existsSync(routesPath)) {
|
|
547
|
+
// remove the folder
|
|
548
|
+
try {
|
|
549
|
+
rmSync(routesPath, { recursive: true });
|
|
550
|
+
console.log("Removed temp_routes_folder:", routesPath);
|
|
551
|
+
} catch (error) {
|
|
552
|
+
console.error("Error removing temp_routes folder", error);
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
routesPath = path.join(projectDir, "data", "routes");
|
|
556
|
+
console.log("Saving routes to:", routesPath);
|
|
557
|
+
if (!existsSync(routesPath)) {
|
|
558
|
+
mkdirSync(routesPath, { recursive: true });
|
|
559
|
+
}
|
|
560
|
+
saveRoutes({ step, folderPath: routesPath });
|
|
561
|
+
}
|
|
562
|
+
|
|
85
563
|
cucumberStep.text = step.text;
|
|
86
564
|
const recording = new Recording();
|
|
565
|
+
step.commands = step.commands.map((cmd) => toRecordingStep(cmd, parametersMap));
|
|
87
566
|
const steps = step.commands;
|
|
88
567
|
|
|
89
568
|
recording.loadFromObject({ steps, step: cucumberStep });
|
|
@@ -108,6 +587,7 @@ export async function saveRecording({ step, cucumberStep, codePage, projectDir,
|
|
|
108
587
|
isStaticToken,
|
|
109
588
|
status,
|
|
110
589
|
} = step.commands[0].value;
|
|
590
|
+
|
|
111
591
|
const result = await generateApiCode(
|
|
112
592
|
{
|
|
113
593
|
url,
|
|
@@ -132,6 +612,7 @@ export async function saveRecording({ step, cucumberStep, codePage, projectDir,
|
|
|
132
612
|
step.keyword,
|
|
133
613
|
stepsDefinitions
|
|
134
614
|
);
|
|
615
|
+
|
|
135
616
|
if (!step.isImplemented) {
|
|
136
617
|
stepsDefinitions.addStep({
|
|
137
618
|
name: step.text,
|
|
@@ -139,6 +620,7 @@ export async function saveRecording({ step, cucumberStep, codePage, projectDir,
|
|
|
139
620
|
source: "recorder",
|
|
140
621
|
});
|
|
141
622
|
}
|
|
623
|
+
|
|
142
624
|
cucumberStep.methodName = result.methodName;
|
|
143
625
|
return result.codePage;
|
|
144
626
|
} else {
|
|
@@ -156,17 +638,29 @@ export async function saveRecording({ step, cucumberStep, codePage, projectDir,
|
|
|
156
638
|
if (step.commands && step.commands.length > 0 && step.commands[0]) {
|
|
157
639
|
path = step.commands[0].lastKnownUrlPath;
|
|
158
640
|
}
|
|
641
|
+
let protect = false;
|
|
642
|
+
if (step.commands && step.commands.length > 0 && step.commands[0].type) {
|
|
643
|
+
if (step.commands[0].type === "verify_element_property" || step.commands[0].type === "conditional_wait") {
|
|
644
|
+
protect = true;
|
|
645
|
+
}
|
|
646
|
+
}
|
|
159
647
|
const infraResult = codePage.addInfraCommand(
|
|
160
648
|
methodName,
|
|
161
649
|
description,
|
|
162
650
|
cucumberStep.getVariablesList(),
|
|
163
651
|
generateCodeResult.codeLines,
|
|
164
|
-
|
|
652
|
+
protect,
|
|
165
653
|
"recorder",
|
|
166
654
|
path
|
|
167
655
|
);
|
|
168
656
|
const keyword = (cucumberStep.keywordAlias ?? cucumberStep.keyword).trim();
|
|
169
|
-
const stepResult = codePage.addCucumberStep(
|
|
657
|
+
const stepResult = codePage.addCucumberStep(
|
|
658
|
+
keyword,
|
|
659
|
+
cucumberStep.getTemplate(),
|
|
660
|
+
methodName,
|
|
661
|
+
steps.length,
|
|
662
|
+
step.finalTimeout
|
|
663
|
+
);
|
|
170
664
|
|
|
171
665
|
if (!step.isImplemented) {
|
|
172
666
|
stepsDefinitions.addStep({
|
|
@@ -177,6 +671,7 @@ export async function saveRecording({ step, cucumberStep, codePage, projectDir,
|
|
|
177
671
|
}
|
|
178
672
|
|
|
179
673
|
codePage.removeUnusedElements();
|
|
674
|
+
codePage.mergeSimilarElements();
|
|
180
675
|
cucumberStep.methodName = methodName;
|
|
181
676
|
if (generateCodeResult.locatorsMetadata) {
|
|
182
677
|
codePage.addLocatorsMetadata(generateCodeResult.locatorsMetadata);
|
|
@@ -306,6 +801,12 @@ export async function updateStepDefinitions({ scenario, featureName, projectDir
|
|
|
306
801
|
const utilsTemplateFilePath = path.join(__dirname, "../../assets", "templates", "utils_template.txt");
|
|
307
802
|
const utilsContent = readFileSync(utilsTemplateFilePath, "utf8");
|
|
308
803
|
writeFileSync(utilsFilePath, utilsContent, "utf8");
|
|
804
|
+
const hooksTemplateFilePath = path.join(__dirname, "../../assets", "templates", "_hooks_template.txt");
|
|
805
|
+
if (existsSync(hooksTemplateFilePath)) {
|
|
806
|
+
const hooksFilePath = path.join(stepDefinitionFolderPath, "_hooks.mjs");
|
|
807
|
+
const hooksContent = readFileSync(hooksTemplateFilePath, "utf8");
|
|
808
|
+
writeFileSync(hooksFilePath, hooksContent, "utf8");
|
|
809
|
+
}
|
|
309
810
|
const steps = scenario.steps;
|
|
310
811
|
|
|
311
812
|
const stepsDefinitions = new StepsDefinitions(projectDir);
|
|
@@ -321,6 +822,35 @@ export async function updateStepDefinitions({ scenario, featureName, projectDir
|
|
|
321
822
|
}
|
|
322
823
|
}
|
|
323
824
|
if ((step.isImplemented && !step.shouldOverride) || step.commands.length === 0) {
|
|
825
|
+
let routesPath = path.join(tmpdir(), `blinq_temp_routes`);
|
|
826
|
+
if (process.env.TEMP_RUN === "true") {
|
|
827
|
+
console.log("Save routes in temp folder for running:", routesPath);
|
|
828
|
+
if (existsSync(routesPath)) {
|
|
829
|
+
console.log("Removing existing temp_routes_folder:", routesPath);
|
|
830
|
+
routesPath = path.join(tmpdir(), `blinq_temp_routes`);
|
|
831
|
+
rmSync(routesPath, { recursive: true });
|
|
832
|
+
}
|
|
833
|
+
mkdirSync(routesPath, { recursive: true });
|
|
834
|
+
console.log("Created temp_routes_folder:", routesPath);
|
|
835
|
+
saveRoutes({ step, folderPath: routesPath });
|
|
836
|
+
} else {
|
|
837
|
+
console.log("Saving routes in project directory:", projectDir);
|
|
838
|
+
if (existsSync(routesPath)) {
|
|
839
|
+
// remove the folder
|
|
840
|
+
try {
|
|
841
|
+
rmSync(routesPath, { recursive: true });
|
|
842
|
+
console.log("Removed temp_routes_folder:", routesPath);
|
|
843
|
+
} catch (error) {
|
|
844
|
+
console.error("Error removing temp_routes folder", error);
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
routesPath = path.join(projectDir, "data", "routes");
|
|
848
|
+
console.log("Saving routes to:", routesPath);
|
|
849
|
+
if (!existsSync(routesPath)) {
|
|
850
|
+
mkdirSync(routesPath, { recursive: true });
|
|
851
|
+
}
|
|
852
|
+
saveRoutes({ step, folderPath: routesPath });
|
|
853
|
+
}
|
|
324
854
|
continue;
|
|
325
855
|
}
|
|
326
856
|
const cucumberStep = getCucumberStep({ step });
|
|
@@ -328,8 +858,7 @@ export async function updateStepDefinitions({ scenario, featureName, projectDir
|
|
|
328
858
|
const stepDefsFilePath = locateDefinitionPath(featureFolder, pageName);
|
|
329
859
|
// path.join(stepDefinitionFolderPath, pageName + "_page.mjs");
|
|
330
860
|
let codePage = getCodePage(stepDefsFilePath);
|
|
331
|
-
|
|
332
|
-
codePage = await saveRecording({ step, cucumberStep, codePage, projectDir, stepsDefinitions });
|
|
861
|
+
codePage = await saveRecording({ step, cucumberStep, codePage, projectDir, stepsDefinitions, parametersMap: scenario.parametersMap });
|
|
333
862
|
if (!codePage) {
|
|
334
863
|
continue;
|
|
335
864
|
}
|
|
@@ -340,3 +869,45 @@ export async function updateStepDefinitions({ scenario, featureName, projectDir
|
|
|
340
869
|
}
|
|
341
870
|
writeFileSync(utilsFilePath, utilsContent, "utf8");
|
|
342
871
|
}
|
|
872
|
+
|
|
873
|
+
export function saveRoutes({ step, folderPath }) {
|
|
874
|
+
const routeItems = step.routeItems;
|
|
875
|
+
if (!routeItems || routeItems.length === 0) {
|
|
876
|
+
return;
|
|
877
|
+
}
|
|
878
|
+
const cucumberStep = getCucumberStep({ step });
|
|
879
|
+
const template = cucumberStep.getTemplate();
|
|
880
|
+
const stepNameHash = createHash("sha256").update(template).digest("hex");
|
|
881
|
+
console.log("Saving routes for step:", step.text, "with hash:", stepNameHash);
|
|
882
|
+
|
|
883
|
+
const routeItemsWithFilters = routeItems.map((routeItem) => {
|
|
884
|
+
const oldFilters = routeItem.filters;
|
|
885
|
+
const queryParamsObject = {};
|
|
886
|
+
oldFilters.queryParams.forEach((queryParam) => {
|
|
887
|
+
queryParamsObject[queryParam.key] = queryParam.value;
|
|
888
|
+
});
|
|
889
|
+
const newFilters = { path: oldFilters.path, method: oldFilters.method, queryParams: queryParamsObject };
|
|
890
|
+
return {
|
|
891
|
+
...routeItem,
|
|
892
|
+
filters: newFilters,
|
|
893
|
+
};
|
|
894
|
+
});
|
|
895
|
+
|
|
896
|
+
const routesFilePath = path.join(folderPath, stepNameHash + ".json");
|
|
897
|
+
console.log("Routes file path:", routesFilePath);
|
|
898
|
+
const routesData = {
|
|
899
|
+
template,
|
|
900
|
+
routes: routeItemsWithFilters,
|
|
901
|
+
};
|
|
902
|
+
console.log("Routes data to save:", routesData);
|
|
903
|
+
|
|
904
|
+
if (!existsSync(folderPath)) {
|
|
905
|
+
mkdirSync(folderPath, { recursive: true });
|
|
906
|
+
}
|
|
907
|
+
try {
|
|
908
|
+
writeFileSync(routesFilePath, JSON.stringify(routesData, null, 2), "utf8");
|
|
909
|
+
console.log("Saved routes to", routesFilePath);
|
|
910
|
+
} catch (error) {
|
|
911
|
+
console.error("Failed to save routes to", routesFilePath, "Error:", error);
|
|
912
|
+
}
|
|
913
|
+
}
|