@dev-blinq/cucumber_client 1.0.1430-dev → 1.0.1430-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.
Files changed (43) hide show
  1. package/bin/assets/bundled_scripts/recorder.js +73 -73
  2. package/bin/assets/preload/css_gen.js +10 -10
  3. package/bin/assets/preload/toolbar.js +27 -29
  4. package/bin/assets/preload/unique_locators.js +1 -1
  5. package/bin/assets/preload/yaml.js +288 -275
  6. package/bin/assets/scripts/aria_snapshot.js +223 -220
  7. package/bin/assets/scripts/dom_attr.js +329 -329
  8. package/bin/assets/scripts/dom_parent.js +169 -174
  9. package/bin/assets/scripts/event_utils.js +94 -94
  10. package/bin/assets/scripts/pw.js +2050 -1949
  11. package/bin/assets/scripts/recorder.js +70 -45
  12. package/bin/assets/scripts/snapshot_capturer.js +147 -147
  13. package/bin/assets/scripts/unique_locators.js +170 -49
  14. package/bin/assets/scripts/yaml.js +796 -783
  15. package/bin/assets/templates/_hooks_template.txt +6 -2
  16. package/bin/assets/templates/utils_template.txt +16 -16
  17. package/bin/client/code_cleanup/find_step_definition_references.js +0 -1
  18. package/bin/client/code_gen/api_codegen.js +2 -2
  19. package/bin/client/code_gen/code_inversion.js +63 -2
  20. package/bin/client/code_gen/function_signature.js +4 -0
  21. package/bin/client/code_gen/page_reflection.js +52 -11
  22. package/bin/client/code_gen/playwright_codeget.js +28 -22
  23. package/bin/client/cucumber/feature_data.js +2 -2
  24. package/bin/client/cucumber/project_to_document.js +8 -2
  25. package/bin/client/cucumber/steps_definitions.js +19 -3
  26. package/bin/client/local_agent.js +3 -2
  27. package/bin/client/parse_feature_file.js +23 -26
  28. package/bin/client/playground/projects/env.json +2 -2
  29. package/bin/client/recorderv3/bvt_init.js +363 -0
  30. package/bin/client/recorderv3/bvt_recorder.js +1009 -47
  31. package/bin/client/recorderv3/implemented_steps.js +2 -0
  32. package/bin/client/recorderv3/index.js +3 -283
  33. package/bin/client/recorderv3/scriptTest.js +1 -1
  34. package/bin/client/recorderv3/services.js +818 -142
  35. package/bin/client/recorderv3/step_runner.js +28 -8
  36. package/bin/client/recorderv3/step_utils.js +514 -39
  37. package/bin/client/recorderv3/update_feature.js +32 -13
  38. package/bin/client/recorderv3/wbr_entry.js +61 -0
  39. package/bin/client/recording.js +1 -0
  40. package/bin/client/upload-service.js +4 -2
  41. package/bin/client/utils/socket_logger.js +1 -1
  42. package/bin/index.js +4 -1
  43. package/package.json +6 -4
@@ -14,6 +14,431 @@ import { createHash } from "crypto";
14
14
 
15
15
  const __dirname = path.dirname(url.fileURLToPath(import.meta.url));
16
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, stepText) => {
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
+ valueInStepText: stepText && typeof stepText === "string" ? stepText.includes(`"${cmd.value}"`) : false,
254
+ };
255
+ }
256
+ case "conditional_wait": {
257
+ return {
258
+ type: "conditional_wait",
259
+ element: {
260
+ role: cmd.role,
261
+ name: cmd.label,
262
+ },
263
+ parameters: [cmd.timeout, cmd.selectedField, cmd.value],
264
+ lastKnownUrlPath: cmd.lastKnownUrlPath,
265
+ valueInStepText: stepText && typeof stepText === "string" ? stepText.includes(`"${cmd.value}"`) : false,
266
+ };
267
+ }
268
+ case "navigate": {
269
+ return {
270
+ type: "navigate",
271
+ parameters: [cmd.value],
272
+ lastKnownUrlPath: cmd.lastKnownUrlPath,
273
+ };
274
+ }
275
+ case "browser_go_back": {
276
+ return {
277
+ type: "browser_go_back",
278
+ };
279
+ }
280
+ case "browser_go_forward": {
281
+ return {
282
+ type: "browser_go_forward",
283
+ };
284
+ }
285
+ case "set_input_files": {
286
+ return {
287
+ type: "set_input_files",
288
+ element: {
289
+ role: cmd.role,
290
+ name: cmd.label,
291
+ },
292
+ parameters: [cmd.files],
293
+ lastKnownUrlPath: cmd.lastKnownUrlPath,
294
+ };
295
+ }
296
+ case "verify_page_snapshot": {
297
+ return {
298
+ type: "verify_page_snapshot",
299
+ parameters: [cmd.value],
300
+ selectors: cmd.selectors,
301
+ data: cmd.data,
302
+ valueInStepText: stepText && typeof stepText === "string" ? stepText.includes(`"${cmd.value}"`) : false,
303
+ };
304
+ }
305
+ default: {
306
+ return {
307
+ type: cmd.type,
308
+ parameters: [cmd.value],
309
+ lastKnownUrlPath: cmd.lastKnownUrlPath,
310
+ };
311
+ }
312
+ }
313
+ };
314
+
315
+ function getBestStrategy(allStrategyLocators) {
316
+ const orderedPriorities = ["custom", "context", "basic", "text_with_index", "ignore_digit", "no_text"];
317
+ for (const strategy of orderedPriorities) {
318
+ if (allStrategyLocators[strategy] && allStrategyLocators[strategy].length > 0) {
319
+ return strategy;
320
+ }
321
+ }
322
+ return null;
323
+ }
324
+
325
+ const _parameterizeLocators = (locators, replacementFromValue, replacementToValue) => {
326
+ for (const loc of locators) {
327
+ if (loc?.css?.includes(replacementFromValue)) {
328
+ loc.css = loc.css.replaceAll(replacementFromValue, replacementToValue);
329
+ }
330
+ if (loc?.text?.includes(replacementFromValue)) {
331
+ loc.text = loc.text.replaceAll(replacementFromValue, replacementToValue);
332
+ }
333
+ if (loc?.climb && typeof loc.climb === "string" && loc.climb?.includes(replacementFromValue)) {
334
+ loc.climb = loc.climb.replaceAll(replacementFromValue, replacementToValue);
335
+ }
336
+ }
337
+ return locators;
338
+ };
339
+ const parameterizeLocators = ({ cmd, locs, isValueVariable, isTargetValueVariable, parametersMap }) => {
340
+ if (isValueVariable) {
341
+ const variable = cmd.value.slice(1, -1);
342
+ // const val = parametersMap[variable];
343
+ if (typeof cmd.text === "string") {
344
+ const replacementFromValue = cmd.text.trim().replace(/\s+/g, " ") ?? ""; // val.trim();
345
+ if (replacementFromValue.length > 0) {
346
+ const replacementToValue = `{${variable}}`;
347
+ locs = _parameterizeLocators(locs, replacementFromValue, replacementToValue);
348
+ }
349
+ }
350
+ }
351
+ if (isTargetValueVariable) {
352
+ const variable = cmd.targetValue.slice(1, -1);
353
+ // const val = parametersMap[variable];
354
+ if (typeof cmd.targetText === "string") {
355
+ const replacementFromValue = cmd.targetText.trim().replace(/\s+/g, " ") ?? ""; // val.trim();
356
+ if (replacementFromValue.length > 0) {
357
+ const replacementToValue = `{${variable}}`;
358
+ locs = _parameterizeLocators(locs, replacementFromValue, replacementToValue);
359
+ }
360
+ }
361
+ }
362
+ return locs;
363
+ };
364
+
365
+ //TODO: IMPORTAN
366
+ export const toRecordingStep = (cmd, parametersMap, stepText) => {
367
+ if (cmd.type === "api") {
368
+ return {
369
+ type: "api",
370
+ value: cmd.value,
371
+ };
372
+ }
373
+ const step = _toRecordingStep(cmd, stepText);
374
+ const cmdID = {
375
+ cmdId: cmd.id,
376
+ };
377
+ Object.assign(step, cmdID);
378
+
379
+ const locatorsObject = JSON.parse(JSON.stringify(cmd.locators ?? null));
380
+
381
+ if (!locatorsObject) return step;
382
+
383
+ const element_name = cmd?.locators?.element_name ?? `${cmd.label} ${cmd.role ?? "Text"}`;
384
+ locatorsObject.element_name = element_name;
385
+
386
+ const isValueVariable = isVariable(cmd.value);
387
+ const isTargetValueVariable = isVariable(cmd.targetValue);
388
+ const allStrategyLocators = JSON.parse(JSON.stringify(cmd?.allStrategyLocators ?? null));
389
+ step.locators = locatorsObject;
390
+ step.allStrategyLocators = allStrategyLocators;
391
+ step.isLocatorsAssigned = true;
392
+
393
+ if (!isValueVariable && !isTargetValueVariable) {
394
+ return step;
395
+ }
396
+
397
+ if (isValueVariable) {
398
+ step.dataSource = "parameters";
399
+ step.dataKey = convertToIdentifier(cmd.value.slice(1, -1));
400
+ }
401
+
402
+ if (!allStrategyLocators) {
403
+ let locs = locatorsObject.locators;
404
+ locs = parameterizeLocators({
405
+ cmd,
406
+ locs,
407
+ isValueVariable,
408
+ isTargetValueVariable,
409
+ parametersMap,
410
+ });
411
+ locatorsObject.locators = locs;
412
+ return {
413
+ ...step,
414
+ locators: locatorsObject,
415
+ };
416
+ }
417
+
418
+ for (const key in allStrategyLocators) {
419
+ if (key === "strategy") continue;
420
+ if (key === "no_text" || key === "custom") continue;
421
+ const locators = allStrategyLocators[key];
422
+ if (locators.length === 0) continue;
423
+ parameterizeLocators({
424
+ cmd,
425
+ locs: locators,
426
+ isValueVariable,
427
+ isTargetValueVariable,
428
+ parametersMap,
429
+ });
430
+ }
431
+
432
+ locatorsObject.locators = allStrategyLocators[allStrategyLocators.strategy] ?? locatorsObject.locators;
433
+
434
+ return {
435
+ ...step,
436
+ locators: locatorsObject,
437
+ allStrategyLocators,
438
+ isLocatorsAssigned: true,
439
+ };
440
+ };
441
+
17
442
  export const toMethodName = (str) => {
18
443
  // Remove any non-word characters (excluding underscore) and trim spaces
19
444
  let cleanStr = str.trim().replace(/[^\w\s]/gi, "");
@@ -36,7 +461,7 @@ export function getCodePage(stepDefsFilePath) {
36
461
  export function getCucumberStep({ step }) {
37
462
  const cucumberStep = new Step();
38
463
  cucumberStep.loadFromJson({
39
- text: step.text,
464
+ text: step.renamedText ? step.renamedText : step.text,
40
465
  keyword: step.keyword,
41
466
  keywordType: step.keywordType,
42
467
  parameters: [],
@@ -54,7 +479,7 @@ export function getCucumberStep({ step }) {
54
479
 
55
480
  function makeStepTextUnique(step, stepsDefinitions) {
56
481
  // const utilsFilePath = path.join("features", "step_definitions", "utils.mjs");
57
- let stepText = step.text;
482
+ let stepText = step.renamedText ? step.renamedText : step.text;
58
483
  let stepIndex = 1;
59
484
  // console.log("makeStepTextUnique", step.text);
60
485
  let stepDef = stepsDefinitions.findMatchingStep(stepText);
@@ -70,10 +495,13 @@ function makeStepTextUnique(step, stepsDefinitions) {
70
495
  step.text = stepText;
71
496
  }
72
497
 
73
- export async function saveRecording({ step, cucumberStep, codePage, projectDir, stepsDefinitions }) {
498
+ export async function saveRecording({ step, cucumberStep, codePage, projectDir, stepsDefinitions, parametersMap }) {
499
+ if (step.commands && Array.isArray(step.commands)) {
500
+ step.commands = step.commands.map((cmd) => toRecordingStep(cmd, parametersMap, step.text));
501
+ }
74
502
  let routesPath = path.join(tmpdir(), "blinq_temp_routes");
75
503
 
76
- if (process.env.TEMP_RUN) {
504
+ if (process.env.TEMP_RUN === "true") {
77
505
  if (existsSync(routesPath)) {
78
506
  rmSync(routesPath, { recursive: true });
79
507
  }
@@ -84,9 +512,9 @@ export async function saveRecording({ step, cucumberStep, codePage, projectDir,
84
512
  // remove the folder
85
513
  try {
86
514
  rmSync(routesPath, { recursive: true });
87
- console.log("Removed temp_routes_folder:", routesPath);
515
+ //
88
516
  } catch (error) {
89
- console.error("Error removing temp_routes folder", error);
517
+ //
90
518
  }
91
519
  routesPath = path.join(projectDir, "data", "routes");
92
520
  if (!existsSync(routesPath)) {
@@ -107,32 +535,37 @@ export async function saveRecording({ step, cucumberStep, codePage, projectDir,
107
535
  const isUtilStep = makeStepTextUnique(step, stepsDefinitions);
108
536
 
109
537
  if (isUtilStep) {
110
- return;
538
+ if (!step.renamedText) {
539
+ return;
540
+ }
541
+ step.text = step.text.trim();
542
+ const { functionName } = stepsDefinitions.findMatchingStep(step.renamedText);
543
+ step.renamedText = functionName;
544
+ const newImportLine = `import { ${functionName} } from "./utils.mjs";\n`;
545
+
546
+ if (!codePage.fileContent.includes(newImportLine)) {
547
+ codePage.fileContent = newImportLine + codePage.fileContent;
548
+ }
111
549
  }
112
550
  }
113
551
 
552
+ routesPath = path.join(tmpdir(), "blinq_temp_routes");
114
553
  if (process.env.TEMP_RUN === "true") {
115
- console.log("Save routes in temp folder for running:", routesPath);
116
554
  if (existsSync(routesPath)) {
117
- console.log("Removing existing temp_routes_folder:", routesPath);
118
555
  rmSync(routesPath, { recursive: true });
119
556
  }
120
557
  mkdirSync(routesPath, { recursive: true });
121
- console.log("Created temp_routes_folder:", routesPath);
122
558
  saveRoutes({ step, folderPath: routesPath });
123
559
  } else {
124
- console.log("Saving routes in project directory:", projectDir);
125
560
  if (existsSync(routesPath)) {
126
561
  // remove the folder
127
562
  try {
128
563
  rmSync(routesPath, { recursive: true });
129
- console.log("Removed temp_routes_folder:", routesPath);
130
564
  } catch (error) {
131
- console.error("Error removing temp_routes folder", error);
565
+ //
132
566
  }
133
567
  }
134
568
  routesPath = path.join(projectDir, "data", "routes");
135
- console.log("Saving routes to:", routesPath);
136
569
  if (!existsSync(routesPath)) {
137
570
  mkdirSync(routesPath, { recursive: true });
138
571
  }
@@ -141,6 +574,7 @@ export async function saveRecording({ step, cucumberStep, codePage, projectDir,
141
574
 
142
575
  cucumberStep.text = step.text;
143
576
  const recording = new Recording();
577
+
144
578
  const steps = step.commands;
145
579
 
146
580
  recording.loadFromObject({ steps, step: cucumberStep });
@@ -191,7 +625,7 @@ export async function saveRecording({ step, cucumberStep, codePage, projectDir,
191
625
  stepsDefinitions
192
626
  );
193
627
 
194
- if (!step.isImplemented) {
628
+ if (!step.renamedText && !(step.isImplemented && step.shouldOverride)) {
195
629
  stepsDefinitions.addStep({
196
630
  name: step.text,
197
631
  file: result.codePage.sourceFileName,
@@ -209,7 +643,10 @@ export async function saveRecording({ step, cucumberStep, codePage, projectDir,
209
643
  }
210
644
  codePage = generateCodeResult.page;
211
645
  methodName = generateCodeResult.methodName;
212
- codePage.insertElements(generateCodeResult.elements);
646
+
647
+ if (!step.renamedText) {
648
+ codePage.insertElements(generateCodeResult.elements);
649
+ }
213
650
 
214
651
  const description = cucumberStep.text;
215
652
  let path = null;
@@ -222,15 +659,32 @@ export async function saveRecording({ step, cucumberStep, codePage, projectDir,
222
659
  protect = true;
223
660
  }
224
661
  }
225
- const infraResult = codePage.addInfraCommand(
226
- methodName,
227
- description,
228
- cucumberStep.getVariablesList(),
229
- generateCodeResult.codeLines,
230
- protect,
231
- "recorder",
232
- path
233
- );
662
+
663
+ if (step.renamedText) {
664
+ codePage.addInfraCommandUtil(
665
+ methodName,
666
+ description,
667
+ cucumberStep.parameters,
668
+ generateCodeResult.codeLines,
669
+ step.renamedText,
670
+ step.text,
671
+ parametersMap,
672
+ protect,
673
+ "recorder",
674
+ path
675
+ );
676
+ } else {
677
+ codePage.addInfraCommand(
678
+ methodName,
679
+ description,
680
+ cucumberStep.getVariablesList(),
681
+ generateCodeResult.codeLines,
682
+ protect,
683
+ "recorder",
684
+ path
685
+ );
686
+ }
687
+
234
688
  const keyword = (cucumberStep.keywordAlias ?? cucumberStep.keyword).trim();
235
689
  const stepResult = codePage.addCucumberStep(
236
690
  keyword,
@@ -240,7 +694,7 @@ export async function saveRecording({ step, cucumberStep, codePage, projectDir,
240
694
  step.finalTimeout
241
695
  );
242
696
 
243
- if (!step.isImplemented) {
697
+ if (!step.renamedText && !(step.isImplemented && step.shouldOverride)) {
244
698
  stepsDefinitions.addStep({
245
699
  name: step.text,
246
700
  file: codePage.sourceFileName,
@@ -249,6 +703,7 @@ export async function saveRecording({ step, cucumberStep, codePage, projectDir,
249
703
  }
250
704
 
251
705
  codePage.removeUnusedElements();
706
+ codePage.mergeSimilarElements();
252
707
  cucumberStep.methodName = methodName;
253
708
  if (generateCodeResult.locatorsMetadata) {
254
709
  codePage.addLocatorsMetadata(generateCodeResult.locatorsMetadata);
@@ -300,26 +755,35 @@ export const getCommandsForImplementedStep = (stepName, stepsDefinitions, stepPa
300
755
  if (error) {
301
756
  throw new Error(error);
302
757
  }
758
+ isUtilStep = codePage.sourceFileName.endsWith("utils.mjs");
303
759
 
304
760
  if (parametersNames.length !== stepParams.length) {
305
761
  // console.log("Parameters mismatch", parametersNames, stepParams);
306
762
  throw new Error("Parameters mismatch");
307
763
  }
308
- for (let i = 0; i < parametersNames.length; i++) {
309
- stepParams[i].argumentName = parametersNames[i];
310
- }
311
764
 
312
- isUtilStep = codePage.sourceFileName.endsWith("utils.mjs");
313
- for (const { code } of codeCommands) {
314
- const command = invertCodeToCommand(code, elements, stepParams, stepsDefinitions, codePage, stepName)[0];
315
- if (command === undefined || command.type === null) continue;
316
- if (command.element) {
317
- const key = command.element.key;
318
- if (key && locatorsJson[key]) {
319
- command.allStrategyLocators = locatorsJson[key];
765
+ const pattern = step.name;
766
+ if (isUtilStep && pattern === "Verify the file {string} exists") {
767
+ commands.push({
768
+ type: "verify_file_exists",
769
+ parameters: [stepParams[0].text],
770
+ });
771
+ } else {
772
+ for (let i = 0; i < parametersNames.length; i++) {
773
+ stepParams[i].argumentName = parametersNames[i];
774
+ }
775
+
776
+ for (const { code } of codeCommands) {
777
+ const command = invertCodeToCommand(code, elements, stepParams, stepsDefinitions, codePage, stepName)[0];
778
+ if (command === undefined || command.type === null) continue;
779
+ if (command.element) {
780
+ const key = command.element.key;
781
+ if (key && locatorsJson[key]) {
782
+ command.allStrategyLocators = locatorsJson[key];
783
+ }
320
784
  }
785
+ commands.push(command);
321
786
  }
322
- commands.push(command);
323
787
  }
324
788
  } catch (error) {
325
789
  console.error(error);
@@ -404,6 +868,7 @@ export async function updateStepDefinitions({ scenario, featureName, projectDir
404
868
  console.log("Save routes in temp folder for running:", routesPath);
405
869
  if (existsSync(routesPath)) {
406
870
  console.log("Removing existing temp_routes_folder:", routesPath);
871
+ routesPath = path.join(tmpdir(), `blinq_temp_routes`);
407
872
  rmSync(routesPath, { recursive: true });
408
873
  }
409
874
  mkdirSync(routesPath, { recursive: true });
@@ -427,6 +892,9 @@ export async function updateStepDefinitions({ scenario, featureName, projectDir
427
892
  }
428
893
  saveRoutes({ step, folderPath: routesPath });
429
894
  }
895
+ if (step.commands && Array.isArray(step.commands)) {
896
+ step.commands = step.commands.map((cmd) => toRecordingStep(cmd, scenario.parametersMap));
897
+ }
430
898
  continue;
431
899
  }
432
900
  const cucumberStep = getCucumberStep({ step });
@@ -434,7 +902,14 @@ export async function updateStepDefinitions({ scenario, featureName, projectDir
434
902
  const stepDefsFilePath = locateDefinitionPath(featureFolder, pageName);
435
903
  // path.join(stepDefinitionFolderPath, pageName + "_page.mjs");
436
904
  let codePage = getCodePage(stepDefsFilePath);
437
- codePage = await saveRecording({ step, cucumberStep, codePage, projectDir, stepsDefinitions });
905
+ codePage = await saveRecording({
906
+ step,
907
+ cucumberStep,
908
+ codePage,
909
+ projectDir,
910
+ stepsDefinitions,
911
+ parametersMap: scenario.parametersMap,
912
+ });
438
913
  if (!codePage) {
439
914
  continue;
440
915
  }