@dev-blinq/cucumber_client 1.0.1194-dev → 1.0.1196-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.
- package/bin/assets/preload/locators.js +18 -0
- package/bin/assets/preload/recorderv3.js +2 -1
- package/bin/client/code_gen/code_inversion.js +3 -3
- package/bin/client/operations/dump_tree.js +157 -2
- package/bin/client/recorderv3/bvt_recorder.js +1 -4
- package/bin/client/recorderv3/cli.js +1 -0
- package/bin/client/recorderv3/step_utils.js +8 -6
- package/bin/client/recording.js +1 -0
- package/package.json +1 -1
|
@@ -697,6 +697,24 @@ function querySelector_shadow_aware(element, selector) {
|
|
|
697
697
|
}
|
|
698
698
|
window.querySelector_shadow_aware = querySelector_shadow_aware;
|
|
699
699
|
|
|
700
|
+
function findElement(css, scope = document) {
|
|
701
|
+
// return null if no css provided
|
|
702
|
+
if (!css) return null;
|
|
703
|
+
const selector = window.__injectedScript.parseSelector(css);
|
|
704
|
+
try {
|
|
705
|
+
const elements = window.__injectedScript.querySelectorAll(selector, scope, true);
|
|
706
|
+
if (!elements) return null;
|
|
707
|
+
if (elements.length === 1) {
|
|
708
|
+
return elements[0];
|
|
709
|
+
} else {
|
|
710
|
+
return elements;
|
|
711
|
+
}
|
|
712
|
+
} catch (error) {
|
|
713
|
+
return null;
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
window.findElement = findElement;
|
|
717
|
+
|
|
700
718
|
// export {
|
|
701
719
|
// getUniqueLocators,
|
|
702
720
|
// getBasicInfo,
|
|
@@ -1355,7 +1355,8 @@ function countAccurances(css, scope = document) {
|
|
|
1355
1355
|
}
|
|
1356
1356
|
window.countAccurances = countAccurances;
|
|
1357
1357
|
function findElement(css, scope = document) {
|
|
1358
|
-
//
|
|
1358
|
+
// Note: If you change anything iin this function
|
|
1359
|
+
// please change it in locators.js
|
|
1359
1360
|
if (!css) return null;
|
|
1360
1361
|
const selector = window.__injectedScript.parseSelector(css);
|
|
1361
1362
|
try {
|
|
@@ -521,9 +521,9 @@ const invertCodeToCommand = (codeString, elements = {}, stepParams, stepsDefinit
|
|
|
521
521
|
if (propName === "web" || propName === "stable") {
|
|
522
522
|
const step = invertStableCommand(call, elements, stepParams);
|
|
523
523
|
if (step) steps.push(step);
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
524
|
+
} else if (propName === "api") {
|
|
525
|
+
const step = invertApiCommand(stepsDefinitions, codePage, stepName);
|
|
526
|
+
if (step) steps.push(step);
|
|
527
527
|
} else {
|
|
528
528
|
return;
|
|
529
529
|
}
|
|
@@ -378,6 +378,81 @@ const findLocatorByText = async (context, texts, backendNodeId) => {
|
|
|
378
378
|
await _closeCDP();
|
|
379
379
|
}
|
|
380
380
|
};
|
|
381
|
+
function classifyLocatorsByStrategy(locators) {
|
|
382
|
+
const locs = [];
|
|
383
|
+
|
|
384
|
+
const allStrategyLocators = {
|
|
385
|
+
basic: [],
|
|
386
|
+
no_text: [],
|
|
387
|
+
ignore_digit: [],
|
|
388
|
+
context: [],
|
|
389
|
+
strategy: "basic",
|
|
390
|
+
};
|
|
391
|
+
|
|
392
|
+
const regexRegex = /\/.*\\[d][+].*\//;
|
|
393
|
+
for (const locator of locators) {
|
|
394
|
+
if (locator.mode) {
|
|
395
|
+
const { mode, ...rest } = locator;
|
|
396
|
+
locs.push(rest);
|
|
397
|
+
allStrategyLocators[locator.mode.toLowerCase()].push(rest);
|
|
398
|
+
} else if (locator.text && locator.text.length > 0) {
|
|
399
|
+
locs.push({
|
|
400
|
+
...locator,
|
|
401
|
+
mode: "CONTEXT",
|
|
402
|
+
});
|
|
403
|
+
allStrategyLocators["context"].push(locator);
|
|
404
|
+
} else if (regexRegex.test(locator.css)) {
|
|
405
|
+
locs.push({
|
|
406
|
+
...locator,
|
|
407
|
+
mode: "IGNORE_DIGIT",
|
|
408
|
+
});
|
|
409
|
+
allStrategyLocators["ignore_digit"].push(locator);
|
|
410
|
+
} else if (locator.css.includes("text=") || locator.css.includes("[name=") || locator.css.includes("label=")) {
|
|
411
|
+
locs.push(locator);
|
|
412
|
+
allStrategyLocators["basic"].push(locator);
|
|
413
|
+
} else {
|
|
414
|
+
locs.push({
|
|
415
|
+
...locator,
|
|
416
|
+
mode: "NO_TEXT",
|
|
417
|
+
});
|
|
418
|
+
allStrategyLocators["no_text"].push(locator);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
if (allStrategyLocators["context"].length > 0) {
|
|
422
|
+
allStrategyLocators["strategy"] = "context";
|
|
423
|
+
} else if (allStrategyLocators["basic"].length === 0 && allStrategyLocators["no_text"].length > 0) {
|
|
424
|
+
allStrategyLocators["strategy"] = "no_text";
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
return {
|
|
428
|
+
locators: locs,
|
|
429
|
+
allStrategyLocators,
|
|
430
|
+
};
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
async function filterLocators(cssLocators, elObjectId) {
|
|
434
|
+
const kept = [];
|
|
435
|
+
for (const selector of cssLocators) {
|
|
436
|
+
// call window.findElement(selector) === el
|
|
437
|
+
const { result } = await cdp.send("Runtime.callFunctionOn", {
|
|
438
|
+
functionDeclaration: `
|
|
439
|
+
function(element,selector) {
|
|
440
|
+
console.log("filterLocators in progress");
|
|
441
|
+
console.log(element,selector);
|
|
442
|
+
return window.findElement(selector) === element;
|
|
443
|
+
}
|
|
444
|
+
`,
|
|
445
|
+
objectId: elObjectId,
|
|
446
|
+
arguments: [{ objectId: elObjectId }, { value: selector }],
|
|
447
|
+
returnByValue: true,
|
|
448
|
+
});
|
|
449
|
+
|
|
450
|
+
if (result.value) {
|
|
451
|
+
kept.push(selector);
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
return kept;
|
|
455
|
+
}
|
|
381
456
|
|
|
382
457
|
async function getRecorderLocators(context, backendNodeId) {
|
|
383
458
|
if (!cdp) {
|
|
@@ -388,7 +463,8 @@ async function getRecorderLocators(context, backendNodeId) {
|
|
|
388
463
|
backendNodeId: backendNodeId,
|
|
389
464
|
});
|
|
390
465
|
const objectId = domNode.object.objectId;
|
|
391
|
-
let
|
|
466
|
+
let locators = [];
|
|
467
|
+
locators = await cdp.send("Runtime.callFunctionOn", {
|
|
392
468
|
functionDeclaration:
|
|
393
469
|
"function(element,options) { console.log(element,options); return window.getPWLocators(element,options); }",
|
|
394
470
|
objectId: objectId,
|
|
@@ -405,8 +481,87 @@ async function getRecorderLocators(context, backendNodeId) {
|
|
|
405
481
|
],
|
|
406
482
|
returnByValue: true,
|
|
407
483
|
});
|
|
484
|
+
if (!locators || !locators.result || !locators.result.value) {
|
|
485
|
+
locators = [];
|
|
486
|
+
} else {
|
|
487
|
+
locators = locators.result?.value;
|
|
488
|
+
}
|
|
489
|
+
let cssLocators = [];
|
|
490
|
+
try {
|
|
491
|
+
let origenCss = await cdp.send("Runtime.callFunctionOn", {
|
|
492
|
+
functionDeclaration:
|
|
493
|
+
"function(element) { console.log(element); return window.generateUniqueCSSSelector(element); }",
|
|
494
|
+
objectId: objectId,
|
|
495
|
+
arguments: [
|
|
496
|
+
{
|
|
497
|
+
objectId: objectId,
|
|
498
|
+
},
|
|
499
|
+
],
|
|
500
|
+
returnByValue: true,
|
|
501
|
+
});
|
|
502
|
+
origenCss = origenCss.result?.value;
|
|
503
|
+
if (origenCss) {
|
|
504
|
+
cssLocators.push(origenCss);
|
|
505
|
+
}
|
|
506
|
+
let noClasses = await cdp.send("Runtime.callFunctionOn", {
|
|
507
|
+
functionDeclaration:
|
|
508
|
+
"function(element,options) { console.log(element,options); return window.CssSelectorGenerator.getCssSelector(element,options); }",
|
|
509
|
+
objectId: objectId,
|
|
510
|
+
arguments: [
|
|
511
|
+
{
|
|
512
|
+
objectId: objectId,
|
|
513
|
+
},
|
|
514
|
+
{
|
|
515
|
+
value: {
|
|
516
|
+
blacklist: [/^(?!.*h\d).*?\d.*/, /\[style/, /\[data-input-id/, /\[blinq-container/],
|
|
517
|
+
combineWithinSelector: true,
|
|
518
|
+
combineBetweenSelectors: true,
|
|
519
|
+
selectors: ["id", "attribute", "tag", "nthchild", "nthoftype"],
|
|
520
|
+
maxCombinations: 100,
|
|
521
|
+
},
|
|
522
|
+
},
|
|
523
|
+
],
|
|
524
|
+
returnByValue: true,
|
|
525
|
+
});
|
|
526
|
+
noClasses = noClasses.result?.value;
|
|
527
|
+
if (!cssLocators.includes(noClasses)) {
|
|
528
|
+
cssLocators.push(noClasses);
|
|
529
|
+
}
|
|
530
|
+
let withClasses = await cdp.send("Runtime.callFunctionOn", {
|
|
531
|
+
functionDeclaration:
|
|
532
|
+
"function(element,options) { console.log(element,options); return window.CssSelectorGenerator.getCssSelector(element,options); }",
|
|
533
|
+
objectId: objectId,
|
|
534
|
+
arguments: [
|
|
535
|
+
{
|
|
536
|
+
objectId: objectId,
|
|
537
|
+
},
|
|
538
|
+
{
|
|
539
|
+
value: {
|
|
540
|
+
blacklist: [/^(?!.*h\d).*?\d.*/, /\[style/, /\[data-input-id/, /\[blinq-container/],
|
|
541
|
+
combineWithinSelector: true,
|
|
542
|
+
combineBetweenSelectors: true,
|
|
543
|
+
selectors: ["id", "attribute", "tag", "nthchild", "nthoftype", "class"],
|
|
544
|
+
maxCombinations: 100,
|
|
545
|
+
},
|
|
546
|
+
},
|
|
547
|
+
],
|
|
548
|
+
returnByValue: true,
|
|
549
|
+
});
|
|
550
|
+
withClasses = withClasses.result?.value;
|
|
551
|
+
if (!cssLocators.includes(withClasses)) {
|
|
552
|
+
cssLocators.push(withClasses);
|
|
553
|
+
}
|
|
554
|
+
cssLocators.sort((a, b) => a.length - b.length);
|
|
555
|
+
|
|
556
|
+
cssLocators = await filterLocators(cssLocators, objectId);
|
|
557
|
+
} catch (err) {
|
|
558
|
+
console.error("Error in generateUniqueCSSSelector", error);
|
|
559
|
+
}
|
|
560
|
+
locators?.push(...cssLocators.map((css) => ({ mode: "NO_TEXT", css })));
|
|
561
|
+
|
|
562
|
+
const result = classifyLocatorsByStrategy(locators);
|
|
408
563
|
|
|
409
|
-
return
|
|
564
|
+
return { ...result, element_name: "" };
|
|
410
565
|
} finally {
|
|
411
566
|
await _closeCDP();
|
|
412
567
|
}
|
|
@@ -214,7 +214,6 @@ export class BVTRecorder {
|
|
|
214
214
|
this.world = { attach: () => {} };
|
|
215
215
|
this.shouldTakeScreenshot = true;
|
|
216
216
|
this.watcher = null;
|
|
217
|
-
this.sendEvent("BVTRecorder.getTestData", {});
|
|
218
217
|
}
|
|
219
218
|
events = {
|
|
220
219
|
onFrameNavigate: "BVTRecorder.onFrameNavigate",
|
|
@@ -619,9 +618,7 @@ export class BVTRecorder {
|
|
|
619
618
|
}
|
|
620
619
|
async closeBrowser() {
|
|
621
620
|
delete process.env.TEMP_RUN;
|
|
622
|
-
await this.watcher.close().then(() => {
|
|
623
|
-
this.logger.info(`Closed current testData file`);
|
|
624
|
-
});
|
|
621
|
+
await this.watcher.close().then(() => {});
|
|
625
622
|
this.watcher = null;
|
|
626
623
|
await closeContext();
|
|
627
624
|
this.pageSet.clear();
|
|
@@ -34,6 +34,7 @@ let recorder = null;
|
|
|
34
34
|
const init = async ({ envName, projectDir, roomId }) => {
|
|
35
35
|
console.log("connecting to " + WS_URL);
|
|
36
36
|
const socket = io(WS_URL);
|
|
37
|
+
// Disconnect from the server when the process exits
|
|
37
38
|
socket.on("connect", () => {
|
|
38
39
|
// console.log('connected to server')
|
|
39
40
|
});
|
|
@@ -132,11 +132,13 @@ export async function saveRecording({ step, cucumberStep, codePage, projectDir,
|
|
|
132
132
|
step.keyword,
|
|
133
133
|
stepsDefinitions
|
|
134
134
|
);
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
135
|
+
if (!step.isImplemented) {
|
|
136
|
+
stepsDefinitions.addStep({
|
|
137
|
+
name: step.text,
|
|
138
|
+
file: result.codePage.sourceFileName,
|
|
139
|
+
source: "recorder",
|
|
140
|
+
});
|
|
141
|
+
}
|
|
140
142
|
cucumberStep.methodName = result.methodName;
|
|
141
143
|
return result.codePage;
|
|
142
144
|
} else {
|
|
@@ -227,7 +229,7 @@ export const getCommandsForImplementedStep = (stepName, stepsDefinitions, stepPa
|
|
|
227
229
|
|
|
228
230
|
isUtilStep = codePage.sourceFileName.endsWith("utils.mjs");
|
|
229
231
|
for (const { code } of codeCommands) {
|
|
230
|
-
const command = invertCodeToCommand(code, elements, stepParams)[0];
|
|
232
|
+
const command = invertCodeToCommand(code, elements, stepParams, stepsDefinitions, codePage, stepName)[0];
|
|
231
233
|
if (command === undefined || command.type === null) continue;
|
|
232
234
|
if (command.element) {
|
|
233
235
|
const key = command.element.key;
|
package/bin/client/recording.js
CHANGED