@dev-blinq/cucumber_client 1.0.1353-dev → 1.0.1353-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 +107 -107
- 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 +10 -20
- package/bin/assets/scripts/snapshot_capturer.js +153 -146
- package/bin/assets/scripts/unique_locators.js +941 -815
- package/bin/assets/scripts/yaml.js +796 -783
- package/bin/assets/templates/_hooks_template.txt +41 -0
- package/bin/assets/templates/utils_template.txt +2 -45
- 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 +107 -2
- package/bin/client/code_gen/page_reflection.js +839 -906
- package/bin/client/code_gen/playwright_codeget.js +25 -11
- 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 +6 -3
- 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 +202 -89
- package/bin/client/recorderv3/implemented_steps.js +17 -12
- package/bin/client/recorderv3/index.js +59 -54
- package/bin/client/recorderv3/network.js +22 -5
- package/bin/client/recorderv3/scriptTest.js +1 -1
- package/bin/client/recorderv3/services.js +4 -16
- package/bin/client/recorderv3/step_runner.js +318 -209
- package/bin/client/recorderv3/step_utils.js +475 -16
- package/bin/client/recorderv3/update_feature.js +28 -29
- package/bin/client/recording.js +1 -0
- package/bin/client/run_cucumber.js +1 -1
- package/bin/client/scenario_report.js +0 -5
- package/bin/client/test_scenario.js +0 -1
- package/bin/client/upload-service.js +3 -2
- package/bin/client/utils/socket_logger.js +132 -0
- package/bin/index.js +2 -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 +21 -12
|
@@ -14,6 +14,427 @@ 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) => {
|
|
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, isTargetValueVariable, parametersMap }) => {
|
|
336
|
+
if (isValueVariable) {
|
|
337
|
+
const variable = cmd.value.slice(1, -1);
|
|
338
|
+
// const val = parametersMap[variable];
|
|
339
|
+
if (typeof cmd.text === "string") {
|
|
340
|
+
const replacementFromValue = cmd.text.trim().replace(/\s+/g, " ") ?? ""; // val.trim();
|
|
341
|
+
if (replacementFromValue.length > 0) {
|
|
342
|
+
const replacementToValue = `{${variable}}`;
|
|
343
|
+
locs = _parameterizeLocators(locs, replacementFromValue, replacementToValue);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
if (isTargetValueVariable) {
|
|
348
|
+
const variable = cmd.targetValue.slice(1, -1);
|
|
349
|
+
// const val = parametersMap[variable];
|
|
350
|
+
if (typeof cmd.targetText === "string") {
|
|
351
|
+
const replacementFromValue = cmd.targetText.trim().replace(/\s+/g, " ") ?? ""; // val.trim();
|
|
352
|
+
if (replacementFromValue.length > 0) {
|
|
353
|
+
const replacementToValue = `{${variable}}`;
|
|
354
|
+
locs = _parameterizeLocators(locs, replacementFromValue, replacementToValue);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
return locs;
|
|
359
|
+
};
|
|
360
|
+
|
|
361
|
+
//TODO: IMPORTAN
|
|
362
|
+
export const toRecordingStep = (cmd, parametersMap) => {
|
|
363
|
+
if (cmd.type === "api") {
|
|
364
|
+
return {
|
|
365
|
+
type: "api",
|
|
366
|
+
value: cmd.value,
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
const step = _toRecordingStep(cmd);
|
|
370
|
+
const cmdID = {
|
|
371
|
+
cmdId: cmd.id,
|
|
372
|
+
};
|
|
373
|
+
Object.assign(step, cmdID);
|
|
374
|
+
|
|
375
|
+
const locatorsObject = JSON.parse(JSON.stringify(cmd.locators ?? null));
|
|
376
|
+
|
|
377
|
+
if (!locatorsObject) return step;
|
|
378
|
+
|
|
379
|
+
const element_name = cmd?.locators?.element_name ?? `${cmd.label} ${cmd.role ?? "Text"}`;
|
|
380
|
+
locatorsObject.element_name = element_name;
|
|
381
|
+
|
|
382
|
+
const isValueVariable = isVariable(cmd.value);
|
|
383
|
+
const isTargetValueVariable = isVariable(cmd.targetValue);
|
|
384
|
+
const allStrategyLocators = JSON.parse(JSON.stringify(cmd?.allStrategyLocators ?? null));
|
|
385
|
+
step.locators = locatorsObject;
|
|
386
|
+
step.allStrategyLocators = allStrategyLocators;
|
|
387
|
+
step.isLocatorsAssigned = true;
|
|
388
|
+
|
|
389
|
+
if (!isValueVariable && !isTargetValueVariable) {
|
|
390
|
+
return step;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
if (isValueVariable) {
|
|
394
|
+
step.dataSource = "parameters";
|
|
395
|
+
step.dataKey = convertToIdentifier(cmd.value.slice(1, -1));
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
if (!allStrategyLocators) {
|
|
399
|
+
let locs = locatorsObject.locators;
|
|
400
|
+
locs = parameterizeLocators({
|
|
401
|
+
cmd,
|
|
402
|
+
locs,
|
|
403
|
+
isValueVariable,
|
|
404
|
+
isTargetValueVariable,
|
|
405
|
+
parametersMap,
|
|
406
|
+
});
|
|
407
|
+
locatorsObject.locators = locs;
|
|
408
|
+
return {
|
|
409
|
+
...step,
|
|
410
|
+
locators: locatorsObject,
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
for (const key in allStrategyLocators) {
|
|
415
|
+
if (key === "strategy") continue;
|
|
416
|
+
if (key === "no_text" || key === "custom") continue;
|
|
417
|
+
const locators = allStrategyLocators[key];
|
|
418
|
+
if (locators.length === 0) continue;
|
|
419
|
+
parameterizeLocators({
|
|
420
|
+
cmd,
|
|
421
|
+
locs: locators,
|
|
422
|
+
isValueVariable,
|
|
423
|
+
isTargetValueVariable,
|
|
424
|
+
parametersMap,
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
locatorsObject.locators = allStrategyLocators[allStrategyLocators.strategy] ?? locatorsObject.locators;
|
|
429
|
+
|
|
430
|
+
return {
|
|
431
|
+
...step,
|
|
432
|
+
locators: locatorsObject,
|
|
433
|
+
allStrategyLocators,
|
|
434
|
+
isLocatorsAssigned: true,
|
|
435
|
+
};
|
|
436
|
+
};
|
|
437
|
+
|
|
17
438
|
export const toMethodName = (str) => {
|
|
18
439
|
// Remove any non-word characters (excluding underscore) and trim spaces
|
|
19
440
|
let cleanStr = str.trim().replace(/[^\w\s]/gi, "");
|
|
@@ -70,10 +491,13 @@ function makeStepTextUnique(step, stepsDefinitions) {
|
|
|
70
491
|
step.text = stepText;
|
|
71
492
|
}
|
|
72
493
|
|
|
73
|
-
export async function saveRecording({ step, cucumberStep, codePage, projectDir, stepsDefinitions }) {
|
|
494
|
+
export async function saveRecording({ step, cucumberStep, codePage, projectDir, stepsDefinitions, parametersMap }) {
|
|
495
|
+
if (step.commands && Array.isArray(step.commands)) {
|
|
496
|
+
step.commands = step.commands.map((cmd) => toRecordingStep(cmd, parametersMap));
|
|
497
|
+
}
|
|
74
498
|
let routesPath = path.join(tmpdir(), "blinq_temp_routes");
|
|
75
499
|
|
|
76
|
-
if (process.env.TEMP_RUN) {
|
|
500
|
+
if (process.env.TEMP_RUN === "true") {
|
|
77
501
|
if (existsSync(routesPath)) {
|
|
78
502
|
rmSync(routesPath, { recursive: true });
|
|
79
503
|
}
|
|
@@ -111,6 +535,7 @@ export async function saveRecording({ step, cucumberStep, codePage, projectDir,
|
|
|
111
535
|
}
|
|
112
536
|
}
|
|
113
537
|
|
|
538
|
+
routesPath = path.join(tmpdir(), "blinq_temp_routes");
|
|
114
539
|
if (process.env.TEMP_RUN === "true") {
|
|
115
540
|
console.log("Save routes in temp folder for running:", routesPath);
|
|
116
541
|
if (existsSync(routesPath)) {
|
|
@@ -141,6 +566,7 @@ export async function saveRecording({ step, cucumberStep, codePage, projectDir,
|
|
|
141
566
|
|
|
142
567
|
cucumberStep.text = step.text;
|
|
143
568
|
const recording = new Recording();
|
|
569
|
+
|
|
144
570
|
const steps = step.commands;
|
|
145
571
|
|
|
146
572
|
recording.loadFromObject({ steps, step: cucumberStep });
|
|
@@ -216,12 +642,18 @@ export async function saveRecording({ step, cucumberStep, codePage, projectDir,
|
|
|
216
642
|
if (step.commands && step.commands.length > 0 && step.commands[0]) {
|
|
217
643
|
path = step.commands[0].lastKnownUrlPath;
|
|
218
644
|
}
|
|
645
|
+
let protect = false;
|
|
646
|
+
if (step.commands && step.commands.length > 0 && step.commands[0].type) {
|
|
647
|
+
if (step.commands[0].type === "verify_element_property" || step.commands[0].type === "conditional_wait") {
|
|
648
|
+
protect = true;
|
|
649
|
+
}
|
|
650
|
+
}
|
|
219
651
|
const infraResult = codePage.addInfraCommand(
|
|
220
652
|
methodName,
|
|
221
653
|
description,
|
|
222
654
|
cucumberStep.getVariablesList(),
|
|
223
655
|
generateCodeResult.codeLines,
|
|
224
|
-
|
|
656
|
+
protect,
|
|
225
657
|
"recorder",
|
|
226
658
|
path
|
|
227
659
|
);
|
|
@@ -243,6 +675,7 @@ export async function saveRecording({ step, cucumberStep, codePage, projectDir,
|
|
|
243
675
|
}
|
|
244
676
|
|
|
245
677
|
codePage.removeUnusedElements();
|
|
678
|
+
codePage.mergeSimilarElements();
|
|
246
679
|
cucumberStep.methodName = methodName;
|
|
247
680
|
if (generateCodeResult.locatorsMetadata) {
|
|
248
681
|
codePage.addLocatorsMetadata(generateCodeResult.locatorsMetadata);
|
|
@@ -294,26 +727,35 @@ export const getCommandsForImplementedStep = (stepName, stepsDefinitions, stepPa
|
|
|
294
727
|
if (error) {
|
|
295
728
|
throw new Error(error);
|
|
296
729
|
}
|
|
730
|
+
isUtilStep = codePage.sourceFileName.endsWith("utils.mjs");
|
|
297
731
|
|
|
298
732
|
if (parametersNames.length !== stepParams.length) {
|
|
299
733
|
// console.log("Parameters mismatch", parametersNames, stepParams);
|
|
300
734
|
throw new Error("Parameters mismatch");
|
|
301
735
|
}
|
|
302
|
-
for (let i = 0; i < parametersNames.length; i++) {
|
|
303
|
-
stepParams[i].argumentName = parametersNames[i];
|
|
304
|
-
}
|
|
305
736
|
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
737
|
+
const pattern = step.name;
|
|
738
|
+
if (isUtilStep && pattern === "Verify the file {string} exists") {
|
|
739
|
+
commands.push({
|
|
740
|
+
type: "verify_file_exists",
|
|
741
|
+
parameters: [stepParams[0].text],
|
|
742
|
+
});
|
|
743
|
+
} else {
|
|
744
|
+
for (let i = 0; i < parametersNames.length; i++) {
|
|
745
|
+
stepParams[i].argumentName = parametersNames[i];
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
for (const { code } of codeCommands) {
|
|
749
|
+
const command = invertCodeToCommand(code, elements, stepParams, stepsDefinitions, codePage, stepName)[0];
|
|
750
|
+
if (command === undefined || command.type === null) continue;
|
|
751
|
+
if (command.element) {
|
|
752
|
+
const key = command.element.key;
|
|
753
|
+
if (key && locatorsJson[key]) {
|
|
754
|
+
command.allStrategyLocators = locatorsJson[key];
|
|
755
|
+
}
|
|
314
756
|
}
|
|
757
|
+
commands.push(command);
|
|
315
758
|
}
|
|
316
|
-
commands.push(command);
|
|
317
759
|
}
|
|
318
760
|
} catch (error) {
|
|
319
761
|
console.error(error);
|
|
@@ -372,6 +814,12 @@ export async function updateStepDefinitions({ scenario, featureName, projectDir
|
|
|
372
814
|
const utilsTemplateFilePath = path.join(__dirname, "../../assets", "templates", "utils_template.txt");
|
|
373
815
|
const utilsContent = readFileSync(utilsTemplateFilePath, "utf8");
|
|
374
816
|
writeFileSync(utilsFilePath, utilsContent, "utf8");
|
|
817
|
+
const hooksTemplateFilePath = path.join(__dirname, "../../assets", "templates", "_hooks_template.txt");
|
|
818
|
+
if (existsSync(hooksTemplateFilePath)) {
|
|
819
|
+
const hooksFilePath = path.join(stepDefinitionFolderPath, "_hooks.mjs");
|
|
820
|
+
const hooksContent = readFileSync(hooksTemplateFilePath, "utf8");
|
|
821
|
+
writeFileSync(hooksFilePath, hooksContent, "utf8");
|
|
822
|
+
}
|
|
375
823
|
const steps = scenario.steps;
|
|
376
824
|
|
|
377
825
|
const stepsDefinitions = new StepsDefinitions(projectDir);
|
|
@@ -392,6 +840,7 @@ export async function updateStepDefinitions({ scenario, featureName, projectDir
|
|
|
392
840
|
console.log("Save routes in temp folder for running:", routesPath);
|
|
393
841
|
if (existsSync(routesPath)) {
|
|
394
842
|
console.log("Removing existing temp_routes_folder:", routesPath);
|
|
843
|
+
routesPath = path.join(tmpdir(), `blinq_temp_routes`);
|
|
395
844
|
rmSync(routesPath, { recursive: true });
|
|
396
845
|
}
|
|
397
846
|
mkdirSync(routesPath, { recursive: true });
|
|
@@ -415,6 +864,9 @@ export async function updateStepDefinitions({ scenario, featureName, projectDir
|
|
|
415
864
|
}
|
|
416
865
|
saveRoutes({ step, folderPath: routesPath });
|
|
417
866
|
}
|
|
867
|
+
if (step.commands && Array.isArray(step.commands)) {
|
|
868
|
+
step.commands = step.commands.map((cmd) => toRecordingStep(cmd, scenario.parametersMap));
|
|
869
|
+
}
|
|
418
870
|
continue;
|
|
419
871
|
}
|
|
420
872
|
const cucumberStep = getCucumberStep({ step });
|
|
@@ -422,7 +874,14 @@ export async function updateStepDefinitions({ scenario, featureName, projectDir
|
|
|
422
874
|
const stepDefsFilePath = locateDefinitionPath(featureFolder, pageName);
|
|
423
875
|
// path.join(stepDefinitionFolderPath, pageName + "_page.mjs");
|
|
424
876
|
let codePage = getCodePage(stepDefsFilePath);
|
|
425
|
-
codePage = await saveRecording({
|
|
877
|
+
codePage = await saveRecording({
|
|
878
|
+
step,
|
|
879
|
+
cucumberStep,
|
|
880
|
+
codePage,
|
|
881
|
+
projectDir,
|
|
882
|
+
stepsDefinitions,
|
|
883
|
+
parametersMap: scenario.parametersMap,
|
|
884
|
+
});
|
|
426
885
|
if (!codePage) {
|
|
427
886
|
continue;
|
|
428
887
|
}
|
|
@@ -129,10 +129,14 @@ export function getExamplesContent(parametersMap) {
|
|
|
129
129
|
function getTagsContent(scenario, featureFileObject) {
|
|
130
130
|
let oldTags = featureFileObject?.scenarios?.find((s) => s.name === scenario.name)?.tags ?? [];
|
|
131
131
|
for (const tag of scenario.tags) {
|
|
132
|
-
if (
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
132
|
+
if (tag === "global_test_data") {
|
|
133
|
+
if (!oldTags.includes("global_test_data")) {
|
|
134
|
+
oldTags.push("global_test_data");
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (tag === "remove_global_test_data") {
|
|
139
|
+
oldTags = oldTags.filter((t) => t !== "global_test_data");
|
|
136
140
|
}
|
|
137
141
|
}
|
|
138
142
|
|
|
@@ -213,14 +217,12 @@ const GherkinToObject = (gherkin) => {
|
|
|
213
217
|
steps: [],
|
|
214
218
|
};
|
|
215
219
|
while (idx < lines.length && lines[idx].startsWith("@")) {
|
|
216
|
-
skipEmptyLines();
|
|
217
220
|
const tags = [...lines[idx].matchAll(/@([^@]+)/g)].map((match) => match[1].trim());
|
|
218
221
|
scenario.tags.push(...(tags ?? []));
|
|
219
222
|
idx++;
|
|
223
|
+
skipEmptyLines();
|
|
220
224
|
}
|
|
221
225
|
|
|
222
|
-
skipEmptyLines();
|
|
223
|
-
|
|
224
226
|
if (idx < lines.length && (lines[idx].startsWith("Scenario:") || lines[idx].startsWith("Scenario Outline:"))) {
|
|
225
227
|
scenario.name = lines[idx].substring(lines[idx].indexOf(":") + 1).trim();
|
|
226
228
|
idx++;
|
|
@@ -233,7 +235,7 @@ const GherkinToObject = (gherkin) => {
|
|
|
233
235
|
skipEmptyLines();
|
|
234
236
|
|
|
235
237
|
if (idx >= lines.length) {
|
|
236
|
-
return
|
|
238
|
+
return scenario;
|
|
237
239
|
}
|
|
238
240
|
|
|
239
241
|
while (
|
|
@@ -243,32 +245,32 @@ const GherkinToObject = (gherkin) => {
|
|
|
243
245
|
!lines[idx].startsWith("@")
|
|
244
246
|
) {
|
|
245
247
|
const line = lines[idx++];
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
type: "comment",
|
|
251
|
-
text: comment,
|
|
252
|
-
};
|
|
253
|
-
scenario.steps.push(command);
|
|
254
|
-
}
|
|
255
|
-
} else if (line.startsWith("Examples:")) {
|
|
256
|
-
obj.hasParams = true;
|
|
257
|
-
const command = {
|
|
248
|
+
let command;
|
|
249
|
+
if (line.startsWith("Examples:")) {
|
|
250
|
+
scenario.hasParams = true;
|
|
251
|
+
command = {
|
|
258
252
|
type: "examples",
|
|
259
253
|
lines: [],
|
|
260
254
|
};
|
|
261
|
-
|
|
262
255
|
while (idx < lines.length && lines[idx].startsWith("|")) {
|
|
263
256
|
const line = lines[idx++];
|
|
264
257
|
command.lines.push(line);
|
|
265
258
|
}
|
|
266
259
|
} else {
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
260
|
+
if (line.startsWith("#")) {
|
|
261
|
+
command = {
|
|
262
|
+
type: "comment",
|
|
263
|
+
text: line,
|
|
264
|
+
};
|
|
265
|
+
} else {
|
|
266
|
+
command = {
|
|
267
|
+
type: "step",
|
|
268
|
+
text: line,
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
271
|
}
|
|
272
|
+
scenario.steps.push(command);
|
|
273
|
+
skipEmptyLines();
|
|
272
274
|
}
|
|
273
275
|
|
|
274
276
|
return scenario;
|
|
@@ -277,7 +279,6 @@ const GherkinToObject = (gherkin) => {
|
|
|
277
279
|
while (idx < lines.length) {
|
|
278
280
|
const scenario = getScenario();
|
|
279
281
|
if (scenario === -1) break;
|
|
280
|
-
|
|
281
282
|
if (scenario.error) {
|
|
282
283
|
return {
|
|
283
284
|
error: scenario.error,
|
|
@@ -303,8 +304,7 @@ function updateExistingScenario({ featureFileContent, scenarioName, scenarioCont
|
|
|
303
304
|
skipScenarioIndex = i;
|
|
304
305
|
continue;
|
|
305
306
|
}
|
|
306
|
-
let scenarioContent = `${
|
|
307
|
-
|
|
307
|
+
let scenarioContent = `${scenario.hasParams ? "Scenario Outline" : "Scenario"}: ${scenario.name}`;
|
|
308
308
|
let tagsLine;
|
|
309
309
|
if (scenario.tags?.length > 0) {
|
|
310
310
|
tagsLine = `${scenario.tags.map((t) => `@${t}`).join(" ")}`;
|
|
@@ -327,7 +327,6 @@ function updateExistingScenario({ featureFileContent, scenarioName, scenarioCont
|
|
|
327
327
|
if (skipScenarioIndex !== -1) {
|
|
328
328
|
finalContent = results.join("\n") + "\n" + scenarioContent;
|
|
329
329
|
}
|
|
330
|
-
|
|
331
330
|
return finalContent;
|
|
332
331
|
}
|
|
333
332
|
export async function updateFeatureFile({ featureName, scenario, override, projectDir }) {
|