@dev-blinq/cucumber_client 1.0.1454-dev → 1.0.1455-dev
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.
|
@@ -32,7 +32,7 @@ class PromisifiedSocketServer {
|
|
|
32
32
|
}
|
|
33
33
|
this.socket.emit("response", { id, value: response, roomId, socketId });
|
|
34
34
|
} catch (error) {
|
|
35
|
-
socketLogger.error("Error handling request", { event, input, id, roomId, socketId, error });
|
|
35
|
+
socketLogger.error("Error handling request", { event, input, id, roomId, socketId, error: error instanceof Error ? `${error.message}\n${error.stack}` : error });
|
|
36
36
|
this.socket.emit("response", {
|
|
37
37
|
id,
|
|
38
38
|
error: {
|
|
@@ -257,7 +257,7 @@ export class BVTStepRunner {
|
|
|
257
257
|
|
|
258
258
|
try {
|
|
259
259
|
this.#lastAttemptedCmdId = null;
|
|
260
|
-
let cmdIDs = (step.commands || []).map((cmd) => cmd.cmdId);
|
|
260
|
+
let cmdIDs = (step.commands || []).map((cmd) => cmd.cmdId ?? cmd.id);
|
|
261
261
|
bvtContext.web.pausedCmd = null;
|
|
262
262
|
|
|
263
263
|
// Clear the liveExecutionMap and set up new entries for this step
|
|
@@ -273,7 +273,7 @@ export class BVTStepRunner {
|
|
|
273
273
|
if (bvtContext.web) {
|
|
274
274
|
bvtContext.web.getCmdId = () => {
|
|
275
275
|
if (cmdIDs.length === 0) {
|
|
276
|
-
cmdIDs = (step.commands || []).map((cmd) => cmd.cmdId);
|
|
276
|
+
cmdIDs = (step.commands || []).map((cmd) => cmd.cmdId ?? cmd.id);
|
|
277
277
|
}
|
|
278
278
|
const cId = cmdIDs.shift();
|
|
279
279
|
this.sendExecutionStatus({
|
|
@@ -320,6 +320,7 @@ export class BVTStepRunner {
|
|
|
320
320
|
codePage,
|
|
321
321
|
projectDir: this.projectDir,
|
|
322
322
|
stepsDefinitions,
|
|
323
|
+
parametersMap
|
|
323
324
|
});
|
|
324
325
|
if (codePage) {
|
|
325
326
|
await codePage.save(stepDefsFilePath);
|
|
@@ -14,6 +14,423 @@ 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 = [
|
|
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
|
+
|
|
384
|
+
if (!isValueVariable && !isTextVariable) {
|
|
385
|
+
return step;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
if (isValueVariable) {
|
|
389
|
+
step.dataSource = "parameters";
|
|
390
|
+
step.dataKey = convertToIdentifier(cmd.value.slice(1, -1))
|
|
391
|
+
}
|
|
392
|
+
const allStrategyLocators = JSON.parse(JSON.stringify(cmd?.allStrategyLocators ?? null));
|
|
393
|
+
|
|
394
|
+
if (!allStrategyLocators) {
|
|
395
|
+
let locs = locatorsObject.locators;
|
|
396
|
+
locs = parameterizeLocators({
|
|
397
|
+
cmd,
|
|
398
|
+
locs,
|
|
399
|
+
isValueVariable,
|
|
400
|
+
isTextVariable,
|
|
401
|
+
parametersMap
|
|
402
|
+
});
|
|
403
|
+
locatorsObject.locators = locs;
|
|
404
|
+
return {
|
|
405
|
+
...step,
|
|
406
|
+
locators: locatorsObject
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
for (const key in allStrategyLocators) {
|
|
411
|
+
if (key === "strategy") continue;
|
|
412
|
+
if (key === "no_text" || key === "custom") continue;
|
|
413
|
+
const locators = allStrategyLocators[key];
|
|
414
|
+
if (locators.length === 0) continue;
|
|
415
|
+
parameterizeLocators({
|
|
416
|
+
cmd,
|
|
417
|
+
locs: locators,
|
|
418
|
+
isValueVariable,
|
|
419
|
+
isTextVariable,
|
|
420
|
+
parametersMap
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
locatorsObject.locators = allStrategyLocators[allStrategyLocators.strategy] ?? locatorsObject.locators;
|
|
425
|
+
|
|
426
|
+
return {
|
|
427
|
+
...step,
|
|
428
|
+
locators: locatorsObject,
|
|
429
|
+
allStrategyLocators,
|
|
430
|
+
isLocatorsAssigned: true
|
|
431
|
+
};
|
|
432
|
+
}
|
|
433
|
+
|
|
17
434
|
export const toMethodName = (str) => {
|
|
18
435
|
// Remove any non-word characters (excluding underscore) and trim spaces
|
|
19
436
|
let cleanStr = str.trim().replace(/[^\w\s]/gi, "");
|
|
@@ -70,7 +487,7 @@ function makeStepTextUnique(step, stepsDefinitions) {
|
|
|
70
487
|
step.text = stepText;
|
|
71
488
|
}
|
|
72
489
|
|
|
73
|
-
export async function saveRecording({ step, cucumberStep, codePage, projectDir, stepsDefinitions }) {
|
|
490
|
+
export async function saveRecording({ step, cucumberStep, codePage, projectDir, stepsDefinitions, parametersMap }) {
|
|
74
491
|
let routesPath = path.join(tmpdir(), "blinq_temp_routes");
|
|
75
492
|
|
|
76
493
|
if (process.env.TEMP_RUN === "true") {
|
|
@@ -142,6 +559,7 @@ export async function saveRecording({ step, cucumberStep, codePage, projectDir,
|
|
|
142
559
|
|
|
143
560
|
cucumberStep.text = step.text;
|
|
144
561
|
const recording = new Recording();
|
|
562
|
+
step.commands = step.commands.map((cmd) => toRecordingStep(cmd, parametersMap));
|
|
145
563
|
const steps = step.commands;
|
|
146
564
|
|
|
147
565
|
recording.loadFromObject({ steps, step: cucumberStep });
|
|
@@ -436,7 +854,7 @@ export async function updateStepDefinitions({ scenario, featureName, projectDir
|
|
|
436
854
|
const stepDefsFilePath = locateDefinitionPath(featureFolder, pageName);
|
|
437
855
|
// path.join(stepDefinitionFolderPath, pageName + "_page.mjs");
|
|
438
856
|
let codePage = getCodePage(stepDefsFilePath);
|
|
439
|
-
codePage = await saveRecording({ step, cucumberStep, codePage, projectDir, stepsDefinitions });
|
|
857
|
+
codePage = await saveRecording({ step, cucumberStep, codePage, projectDir, stepsDefinitions, parametersMap: scenario.parametersMap });
|
|
440
858
|
if (!codePage) {
|
|
441
859
|
continue;
|
|
442
860
|
}
|