@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.
@@ -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
- // return null if no css provided
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
- // } else if (propName === "api") {
525
- // const step = invertApiCommand(stepsDefinitions, codePage, stepName);
526
- // if (step) steps.push(step);
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 res = await cdp.send("Runtime.callFunctionOn", {
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 res.result;
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
- stepsDefinitions.addStep({
136
- name: step.text,
137
- file: result.codePage.sourceFileName,
138
- source: "recorder",
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;
@@ -5,6 +5,7 @@ import { Step } from "../client/cucumber/feature.js";
5
5
  This list need to be in sync with the list exist in the commands.js file
6
6
  */
7
7
  const Types = {
8
+ API: "api",
8
9
  CLICK: "click_element",
9
10
  CLICK_SIMPLE: "click_simple",
10
11
  NAVIGATE: "navigate",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dev-blinq/cucumber_client",
3
- "version": "1.0.1194-dev",
3
+ "version": "1.0.1196-dev",
4
4
  "description": "",
5
5
  "main": "bin/index.js",
6
6
  "types": "bin/index.d.ts",