@dev-blinq/cucumber_client 1.0.1472-dev → 1.0.1472-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 (45) hide show
  1. package/bin/assets/bundled_scripts/recorder.js +73 -73
  2. package/bin/assets/scripts/recorder.js +87 -49
  3. package/bin/assets/scripts/snapshot_capturer.js +10 -17
  4. package/bin/assets/scripts/unique_locators.js +168 -40
  5. package/bin/assets/templates/_hooks_template.txt +6 -2
  6. package/bin/assets/templates/utils_template.txt +16 -16
  7. package/bin/client/code_cleanup/utils.js +16 -7
  8. package/bin/client/code_gen/code_inversion.js +125 -1
  9. package/bin/client/code_gen/duplication_analysis.js +2 -1
  10. package/bin/client/code_gen/function_signature.js +8 -0
  11. package/bin/client/code_gen/index.js +4 -0
  12. package/bin/client/code_gen/page_reflection.js +90 -9
  13. package/bin/client/code_gen/playwright_codeget.js +173 -77
  14. package/bin/client/codemod/find_harcoded_locators.js +173 -0
  15. package/bin/client/codemod/fix_hardcoded_locators.js +247 -0
  16. package/bin/client/codemod/index.js +8 -0
  17. package/bin/client/codemod/locators_array/find_misstructured_elements.js +148 -0
  18. package/bin/client/codemod/locators_array/fix_misstructured_elements.js +144 -0
  19. package/bin/client/codemod/locators_array/index.js +114 -0
  20. package/bin/client/codemod/types.js +1 -0
  21. package/bin/client/cucumber/feature.js +4 -17
  22. package/bin/client/cucumber/steps_definitions.js +17 -12
  23. package/bin/client/recorderv3/bvt_init.js +310 -0
  24. package/bin/client/recorderv3/bvt_recorder.js +1560 -1183
  25. package/bin/client/recorderv3/constants.js +45 -0
  26. package/bin/client/recorderv3/implemented_steps.js +2 -0
  27. package/bin/client/recorderv3/index.js +3 -293
  28. package/bin/client/recorderv3/mixpanel.js +41 -0
  29. package/bin/client/recorderv3/services.js +839 -142
  30. package/bin/client/recorderv3/step_runner.js +36 -7
  31. package/bin/client/recorderv3/step_utils.js +300 -98
  32. package/bin/client/recorderv3/update_feature.js +87 -39
  33. package/bin/client/recorderv3/utils.js +74 -0
  34. package/bin/client/recorderv3/wbr_entry.js +61 -0
  35. package/bin/client/recording.js +1 -0
  36. package/bin/client/types/locators.js +2 -0
  37. package/bin/client/upload-service.js +2 -0
  38. package/bin/client/utils/app_dir.js +21 -0
  39. package/bin/client/utils/socket_logger.js +100 -125
  40. package/bin/index.js +5 -0
  41. package/package.json +21 -6
  42. package/bin/client/recorderv3/app_dir.js +0 -23
  43. package/bin/client/recorderv3/network.js +0 -299
  44. package/bin/client/recorderv3/scriptTest.js +0 -5
  45. package/bin/client/recorderv3/ws_server.js +0 -72
@@ -144,7 +144,7 @@ class BVTRecorder {
144
144
  getAction: (e) => {
145
145
  this.eventUtils.consumeEvent(e);
146
146
  },
147
- getInterestedElement: () => {},
147
+ getInterestedElement: () => { },
148
148
  hoverOutlineStyle: "",
149
149
  });
150
150
 
@@ -159,7 +159,7 @@ class BVTRecorder {
159
159
  };
160
160
  },
161
161
  getAction: () => null,
162
- getInterestedElement: () => {},
162
+ getInterestedElement: () => { },
163
163
  hoverOutlineStyle: "",
164
164
  });
165
165
 
@@ -174,7 +174,7 @@ class BVTRecorder {
174
174
  };
175
175
  },
176
176
  getAction: () => null,
177
- getInterestedElement: () => {},
177
+ getInterestedElement: () => { },
178
178
  hoverOutlineStyle: "",
179
179
  });
180
180
 
@@ -390,6 +390,7 @@ class BVTRecorder {
390
390
  }
391
391
  case "input": {
392
392
  const target = this.eventUtils.getNearestInteractiveElement(this.eventUtils.deepEventTarget(event));
393
+
393
394
  if (target.nodeName === "INPUT" && target.type.toLowerCase() === "file") {
394
395
  return {
395
396
  details: {
@@ -434,6 +435,36 @@ class BVTRecorder {
434
435
  return;
435
436
  }
436
437
  case "keydown": {
438
+ // override event.preventDefault to capture the value
439
+
440
+ const oldPreventDefault = event.preventDefault.bind(event);
441
+ event.preventDefault = () => {
442
+ if (event.key.length >= 1 && !event.ctrlKey && !event.metaKey && !event.altKey) {
443
+ const target = this.eventUtils.getNearestInteractiveElement(this.eventUtils.deepEventTarget(event));
444
+ setTimeout(() => {
445
+ if (event.__bvt_recorded !== undefined) return;
446
+ const valueBefore = target.value;
447
+ let newValue = valueBefore;
448
+
449
+ this.recordEvent(
450
+ {
451
+ details: {
452
+ name: "fill",
453
+ text: newValue,
454
+ },
455
+ element: target,
456
+ },
457
+ target,
458
+ "input",
459
+ event
460
+ );
461
+
462
+ event.__bvt_recorded = true;
463
+ }, 20);
464
+ }
465
+ oldPreventDefault();
466
+ };
467
+
437
468
  if (!this.eventUtils.shouldGenerateKeyPressFor(event)) return;
438
469
  // if (this._actionInProgress(event)) {
439
470
  // this._expectProgrammaticKeyUp = true;
@@ -676,7 +707,8 @@ class BVTRecorder {
676
707
 
677
708
  lastInputId = el.dataset.inputId;
678
709
 
679
- el.__locators = this.getLocatorsObject(el);
710
+ el.__locators = this.getLocatorsObject(el, { maxLocators: 1 });
711
+
680
712
  }
681
713
  const role = this.PW.roleUtils.getAriaRole(el);
682
714
  const label =
@@ -684,13 +716,15 @@ class BVTRecorder {
684
716
  this.PW.roleUtils.getElementAccessibleName(el, true) ||
685
717
  "";
686
718
  const result = this.getElementProperties(el);
719
+ const elText = this.PW.selectorUtils.elementText(new Map(), el);
687
720
  return {
688
721
  role,
689
722
  label,
690
723
  inputID: el.dataset.inputId,
691
724
  tagName: el.tagName,
692
725
  type: el.type,
693
- text: this.PW.selectorUtils.elementText(new Map(), el).full.trim(),
726
+ text: elText.full.trim(),
727
+ textNormalized: elText.normalized.trim(),
694
728
  parent: `tagname: ${el.parentElement?.tagName}\ninnerText: ${el.parentElement?.innerText}`,
695
729
  attrs: {
696
730
  placeholder: el.getAttribute("placeholder"),
@@ -787,30 +821,31 @@ class BVTRecorder {
787
821
  return el.matches(closeBtnSelector);
788
822
  });
789
823
  }
790
-
791
- getLocatorsObject(el) {
824
+ docHasShadowDOM() {
825
+ for (const el of document.all) {
826
+ if (el.tagName.includes("-")) {
827
+ if (["x-bvt-toolbar", "x-bvt-tool"].includes(el.tagName.toLowerCase())) continue;
828
+ if (el.shadowRoot) {
829
+ return true;
830
+ }
831
+ }
832
+ }
833
+ return false;
834
+ }
835
+ getLocatorsObject(el, options = {}) {
836
+ if (!this.docHasShadowDOM()) {
837
+ console.log("No custom elements detected, skipping locator generation");
838
+ return;
839
+ }
840
+ console.log("Custom elements detected locator generation");
792
841
  if (this.contextElement) {
793
- const text = this.contextElement.innerText; // TODO: handle case where contextElement is not in dom/ children removed
794
- const contextEl = this.contextElement;
795
- // const { climb, commonParent } = window.getCommonParent(contextEl, el);
796
- const commonParent = this.locatorGenerator.dom_Parent.findLowestCommonAncestor([contextEl, el]);
797
- const climb = this.locatorGenerator.dom_Parent.getClimbCountToParent(contextEl, commonParent);
798
- const result = this.locatorGenerator.getElementLocators(el, {
799
- excludeText: true,
800
- root: commonParent,
801
- });
802
- result.locators.forEach((locator) => {
803
- locator.text = text;
804
- locator.climb = climb;
805
- });
806
- result.allStrategyLocators.context = result.locators;
807
- result.allStrategyLocators.strategy = "context";
808
- result.allStrategyLocators.no_text = [];
842
+ const result = this.locatorGenerator.toContextLocators(el, this.contextElement, options);
809
843
  return result;
810
844
  }
811
845
  const isRecordingText = this.#mode === "recordingText";
812
846
  return this.locatorGenerator.getElementLocators(el, {
813
847
  excludeText: isRecordingText,
848
+ ...options,
814
849
  });
815
850
  }
816
851
  addListeners() {
@@ -847,31 +882,7 @@ class BVTRecorder {
847
882
  }
848
883
 
849
884
  performance.mark("command-send");
850
- const cmd = {
851
- mode: this.#mode,
852
- action: action.details,
853
- element: this.getElementDetails(actionElement, eventName),
854
- isPopupCloseClick: this.isPopupCloseEvent(e),
855
- // ...this.getLocatorsObject(actionElement),
856
- ...(actionElement.__locators ?? this.getLocatorsObject(actionElement)),
857
- frame: this.getFrameDetails(),
858
- statistics: {
859
- time: `${performance.measure("command-received", "command-send").duration.toFixed(2)} ms`,
860
- },
861
- };
862
- const snapshotDetails = {
863
- id: actionElement.getAttribute("data-blinq-id"),
864
- contextId: this.contextElement?.getAttribute("data-blinq-context-id"),
865
- doc: this.snapshotCapturer.createSnapshot({
866
- excludeSelectors: ["x-bvt-toolbar", "script", "style", "link[rel=stylesheet]"],
867
- }),
868
- };
869
- cmd.snapshotDetails = snapshotDetails;
870
- // eventQueue.enqueue(async () => {
871
- // await bvtRecorderBindings.validateLocators(snapshotDetails);
872
- // });
873
- // console.log(cmd);
874
- await bvtRecorderBindings.recordCommand(cmd);
885
+ this.recordEvent(action, actionElement, eventName, e);
875
886
  this.handleStateTransition(action.element);
876
887
  },
877
888
  { capture: true }
@@ -879,6 +890,33 @@ class BVTRecorder {
879
890
  });
880
891
  }
881
892
 
893
+ recordEvent(action, actionElement, eventName, e) {
894
+ const cmd = {
895
+ mode: this.#mode,
896
+ action: action.details,
897
+ element: this.getElementDetails(actionElement, eventName),
898
+ isPopupCloseClick: this.isPopupCloseEvent(e),
899
+ ...(actionElement.__locators ?? this.getLocatorsObject(actionElement, { maxLocators: 1 })),
900
+ frame: this.getFrameDetails(),
901
+ statistics: {
902
+ time: `${performance.measure("command-received", "command-send").duration.toFixed(2)} ms`,
903
+ },
904
+ };
905
+ const snapshotDetails = {
906
+ id: actionElement.getAttribute("data-blinq-id"),
907
+ contextId: this.contextElement?.getAttribute("data-blinq-context-id"),
908
+ doc: this.snapshotCapturer.createSnapshot({
909
+ excludeSelectors: ["x-bvt-toolbar", "script", "style", "link[rel=stylesheet]"],
910
+ }),
911
+ };
912
+ cmd.snapshotDetails = snapshotDetails;
913
+ // eventQueue.enqueue(async () => {
914
+ // await bvtRecorderBindings.validateLocators(snapshotDetails);
915
+ // });
916
+ // console.log(cmd);
917
+ bvtRecorderBindings.recordCommand(cmd);
918
+ }
919
+
882
920
  // TODO: implement the corresponding logic for the below methods
883
921
  setPopupHandlers(_popopHandlers) {
884
922
  this.popupHandlers = _popopHandlers;
@@ -897,7 +935,7 @@ class BVTRecorder {
897
935
  this.interestedElements.clear();
898
936
  }
899
937
  processAriaSnapshot(snapshot) {
900
- const matchedElements = this.findMatchingElements(snapshot, this.snapshotElements);
938
+ const matchedElements = this.snapshotUtils.findMatchingElements(snapshot, this.snapshotElements);
901
939
  for (const el of matchedElements.values()) {
902
940
  const element = el;
903
941
  if (element) {
@@ -29,25 +29,18 @@ class SnapshotCapturer {
29
29
  processStyles(document) {
30
30
  if (!this.inlineStyles) return;
31
31
 
32
- const stylesheets = Array.from(document.styleSheets);
32
+ const stylesheets = Array.from(window.document.styleSheets);
33
33
  for (const sheet of stylesheets) {
34
34
  try {
35
- if (!sheet.href) continue; // Skip inline styles
36
- const styleEl = document.createElement("style");
37
- let text = "";
38
- const cssRules = Array.from(sheet.cssRules || []);
39
- for (const rule of cssRules) {
40
- if (rule.cssText) {
41
- text += rule.cssText + "\n";
42
- }
43
- }
44
- styleEl.textContent = text;
45
-
46
- // Replace the link with our new style element
47
- if (sheet.ownerNode && sheet.ownerNode.parentNode) {
48
- sheet.ownerNode.parentNode.replaceChild(styleEl, sheet.ownerNode);
49
- } else if (sheet.ownerNode) {
50
- // If the owner node is not in the document, just append it
35
+ const el = sheet.ownerNode.cloneNode(true);
36
+ if (!el.href) {
37
+ document.head.appendChild(el);
38
+ } else {
39
+ const rules = Array.from(sheet.cssRules)
40
+ .map((rule) => rule.cssText)
41
+ .join("\n");
42
+ const styleEl = document.createElement("style");
43
+ styleEl.textContent = rules;
51
44
  document.head.appendChild(styleEl);
52
45
  }
53
46
  } catch (error) {
@@ -217,6 +217,59 @@ class LocatorGenerator {
217
217
  }
218
218
  return result;
219
219
  }
220
+ getMixedLocators(element, options) {
221
+ const noTextLocators = this.getNoTextLocators(element, options);
222
+ const textLocators = this.getTextLocators(element, options);
223
+ const customLocators = this.getCustomLocators(element, options);
224
+ return [...customLocators, ...textLocators, ...noTextLocators];
225
+ }
226
+ toContextLocators(element, contextElement, options = {}) {
227
+ const commonParent = this.dom_Parent.findLowestCommonAncestor([contextElement, element]);
228
+ const climb = this.dom_Parent.getClimbCountToParent(contextElement, commonParent);
229
+ const text = contextElement.innerText.trim();
230
+
231
+ const prefix = `internal:text="${text}" >> ${this.getXPathSelector(climb)}`;
232
+ const result = this.getElementLocators(element, {
233
+ root: commonParent,
234
+ strategies: {
235
+ [this.locatorStrategies.custom]: true,
236
+ [this.locatorStrategies.text]: true,
237
+ [this.locatorStrategies.no_text]: true,
238
+ },
239
+ prefix,
240
+ ...options,
241
+ });
242
+
243
+ const attachContextToLocators = (locs) => {
244
+ locs.forEach((loc) => {
245
+ loc.climb = climb;
246
+ loc.text = text;
247
+ });
248
+ };
249
+
250
+ const allStrategyLocators = result.allStrategyLocators;
251
+ const locators = result.locators;
252
+ if (allStrategyLocators) {
253
+ const allLocators = [];
254
+ for (const strategy in allStrategyLocators) {
255
+ if (strategy === "strategy") continue;
256
+ const locators = allStrategyLocators[strategy];
257
+ if (locators.length === 0) continue;
258
+ allLocators.push(...locators);
259
+ allStrategyLocators[strategy] = [];
260
+ }
261
+ attachContextToLocators(allLocators);
262
+ allStrategyLocators[this.locatorStrategies.context] = allLocators;
263
+ allStrategyLocators.strategy = this.locatorStrategies.context;
264
+ result.locators = allLocators;
265
+ return result;
266
+ }
267
+ if (locators) {
268
+ attachContextToLocators(locators);
269
+ return result;
270
+ }
271
+ return result;
272
+ }
220
273
  getContextLocators(element, locators) {
221
274
  if (!locators || !Array.isArray(locators)) {
222
275
  console.error("Locators must be an array");
@@ -441,12 +494,16 @@ class LocatorGenerator {
441
494
  categorizeLocators(element, locators, options) {
442
495
  const unique = [];
443
496
  const nonUnique = [];
497
+ const visible = options?.visible ?? true;
444
498
  try {
445
499
  for (const locator of locators) {
446
500
  if (!locator || !locator.css || typeof locator.css !== "string") {
447
501
  console.error("Locator must have a valid css selector found: ", locator);
448
502
  continue;
449
503
  }
504
+ if (visible === false) {
505
+ locator.visible = false;
506
+ }
450
507
  const elements = this.getMatchingElements(locator.css, options);
451
508
  if (elements.length === 0) {
452
509
  console.warn(`No elements found for locator: ${locator.css}`);
@@ -571,7 +628,7 @@ class LocatorGenerator {
571
628
  result.push(_locator);
572
629
  } else {
573
630
  const index = _elements.indexOf(element);
574
- if (index !== -1 && index < 5) {
631
+ if (index !== -1 && index < 10) {
575
632
  // _locator.selector = fullSelector;
576
633
  _locator.css = fullSelector;
577
634
  _locator.index = index;
@@ -583,7 +640,7 @@ class LocatorGenerator {
583
640
  }
584
641
  } else {
585
642
  const index = elements.indexOf(element);
586
- if (index !== -1 && index < 5) {
643
+ if (index !== -1 && index < 10) {
587
644
  locator.index = index;
588
645
  locator.priority = 2; // non-unique locators have lower priority
589
646
  result.push(locator);
@@ -591,7 +648,7 @@ class LocatorGenerator {
591
648
  }
592
649
  } else {
593
650
  const index = elements.indexOf(element);
594
- if (index !== -1 && index < 5) {
651
+ if (index !== -1 && index < 10) {
595
652
  locator.index = index;
596
653
  locator.priority = 2; // non-unique locators have lower priority
597
654
  result.push(locator);
@@ -625,7 +682,7 @@ class LocatorGenerator {
625
682
 
626
683
  getUniqueLocators2(element, locatorGenerator = this.getNoTextLocators, options = {}) {
627
684
  try {
628
- const { maxLocators = 5, root = window.document.body } = options;
685
+ const { maxLocators = 5, root = window.document.body, prefix } = options;
629
686
 
630
687
  if (!element) {
631
688
  return [];
@@ -672,12 +729,13 @@ class LocatorGenerator {
672
729
 
673
730
  const elementsCache = new Map();
674
731
 
675
- const allAncestors = this.dom_Parent.getFullAncestorChainToRoot(element, root);
732
+ const allAncestors = prefix ? [element] : this.dom_Parent.getFullAncestorChainToRoot(element, root);
676
733
  allAncestors.shift(); // remove the element itself from the ancestors
677
734
 
678
735
  const cache = new Map();
679
736
  const textToIgnore = this.PW.selectorUtils.elementText(cache, element).full.trim();
680
737
  const ancestorLocators = [];
738
+ let uniqueAncestor = null;
681
739
  for (const ancestor of allAncestors) {
682
740
  const _locators = locatorGenerator(ancestor, { ...options, textToIgnore });
683
741
  if (!_locators || !Array.isArray(_locators) || _locators.length === 0) {
@@ -690,11 +748,15 @@ class LocatorGenerator {
690
748
  });
691
749
  elementsCache.set(ancestor, _categorized);
692
750
  if (_categorized.unique.length > 0) {
751
+ uniqueAncestor = {
752
+ element: ancestor,
753
+ locators: _categorized,
754
+ };
693
755
  break;
694
756
  }
695
757
  }
696
758
 
697
- const uniqueAncestor = ancestorLocators[ancestorLocators.length - 1];
759
+ // const uniqueAncestor = ancestorLocators[ancestorLocators.length - 1];
698
760
 
699
761
  for (const locator of nonUnique) {
700
762
  const selector = locator.css ?? locator.selector;
@@ -703,6 +765,27 @@ class LocatorGenerator {
703
765
  console.warn(`No elements found for locator: ${selector}`);
704
766
  continue;
705
767
  }
768
+ if (!uniqueAncestor) {
769
+ const elements = this.getMatchingElements(selector, options);
770
+ if (elements.length === 1 && elements[0] === element) {
771
+ result.push({
772
+ css: selector,
773
+ score: locator.score,
774
+ priority: 1,
775
+ });
776
+ } else {
777
+ const index = elements.indexOf(element);
778
+ if (index !== -1) {
779
+ result.push({
780
+ css: selector,
781
+ index,
782
+ score: locator.score + 200,
783
+ priority: 2,
784
+ });
785
+ }
786
+ }
787
+ continue;
788
+ }
706
789
 
707
790
  for (const unique_locator of uniqueAncestor.locators.unique) {
708
791
  const fullSelector = `${unique_locator.css} >> ${selector}`;
@@ -718,7 +801,7 @@ class LocatorGenerator {
718
801
  result.push(newLocator);
719
802
  } else {
720
803
  const index = elements.indexOf(element);
721
- if (index !== -1 && index < 5) {
804
+ if (index !== -1 && index < 10) {
722
805
  const effectiveScore = (unique_locator.score + locator.score) / 2;
723
806
  const newLocator = {
724
807
  ...unique_locator,
@@ -741,9 +824,32 @@ class LocatorGenerator {
741
824
  return [];
742
825
  }
743
826
  }
827
+ isElementVisible(element) {
828
+ if (!(element instanceof Element)) return false;
829
+ const style = window.getComputedStyle(element);
830
+ if (style.display === "none" || style.visibility === "hidden" || style.opacity === "0") return false;
831
+ const rect = element.getBoundingClientRect();
832
+ if (rect.width === 0 || rect.height === 0) return false;
833
+ return true;
834
+ }
744
835
  getElementLocators(element, options = {}) {
836
+ const isVisible = this.PW.domUtils.isElementVisible(element);
837
+ if (isVisible === false) {
838
+ console.warn("Element is not visible: ", element);
839
+ options.visible = isVisible;
840
+ }
745
841
  try {
746
- const { excludeText = false } = options;
842
+ const {
843
+ excludeText = false,
844
+ strategies = {
845
+ [this.locatorStrategies.custom]: true,
846
+ [this.locatorStrategies.context]: true,
847
+ [this.locatorStrategies.text]: true,
848
+ [this.locatorStrategies.text_with_index]: true,
849
+ [this.locatorStrategies.digitIgnore]: true,
850
+ [this.locatorStrategies.no_text]: true,
851
+ },
852
+ } = options;
747
853
 
748
854
  const allStrategyLocators = {
749
855
  [this.locatorStrategies.custom]: [],
@@ -753,7 +859,12 @@ class LocatorGenerator {
753
859
  [this.locatorStrategies.digitIgnore]: [],
754
860
  [this.locatorStrategies.no_text]: [],
755
861
  };
756
- if (this.options?.customAttributes) {
862
+ if (
863
+ strategies[this.locatorStrategies.custom] &&
864
+ this.options?.customAttributes &&
865
+ Array.isArray(this.options.customAttributes) &&
866
+ this.options.customAttributes.length > 0
867
+ ) {
757
868
  console.groupCollapsed("Generating Custom locators for element:", element);
758
869
  const customLocators = this.getUniqueLocators(element, this.getCustomLocators.bind(this), options);
759
870
  if (customLocators.length > 0) {
@@ -762,43 +873,60 @@ class LocatorGenerator {
762
873
  }
763
874
  console.groupEnd();
764
875
  if (!excludeText) {
765
- console.groupCollapsed("Generating Text locators for element:", element);
766
- const basicLocators = this.getUniqueLocators(element, this.getTextLocators.bind(this), options);
767
- console.groupEnd();
768
- if (basicLocators.length > 0) {
769
- allStrategyLocators[this.locatorStrategies.text] = basicLocators;
770
- }
876
+ if (strategies[this.locatorStrategies.text]) {
877
+ console.groupCollapsed("Generating Text locators for element:", element);
771
878
 
772
- const textWithIndexLocators = this.getTextwithIndexLocators(basicLocators);
773
- if (textWithIndexLocators.length > 0) {
774
- allStrategyLocators[this.locatorStrategies.text_with_index] = textWithIndexLocators;
775
- }
776
- const digitIgnoreLocators = this.getDigitIgnoreLocators(element, basicLocators);
777
- if (digitIgnoreLocators.length > 0) {
778
- allStrategyLocators[this.locatorStrategies.digitIgnore] = digitIgnoreLocators;
779
- }
780
- const contextLocators = this.getContextLocators(element, basicLocators);
781
- if (contextLocators.length > 0) {
782
- allStrategyLocators[this.locatorStrategies.context] = contextLocators;
879
+ const basicLocators = this.getUniqueLocators(element, this.getTextLocators.bind(this), options);
880
+ console.groupEnd();
881
+ if (basicLocators.length > 0) {
882
+ allStrategyLocators[this.locatorStrategies.text] = basicLocators;
883
+ }
884
+ if (strategies[this.locatorStrategies.text_with_index]) {
885
+ const textWithIndexLocators = this.getTextwithIndexLocators(basicLocators);
886
+ if (textWithIndexLocators.length > 0) {
887
+ allStrategyLocators[this.locatorStrategies.text_with_index] = textWithIndexLocators;
888
+ }
889
+ }
890
+ if (strategies[this.locatorStrategies.digitIgnore]) {
891
+ const digitIgnoreLocators = this.getDigitIgnoreLocators(element, basicLocators);
892
+ if (digitIgnoreLocators.length > 0) {
893
+ allStrategyLocators[this.locatorStrategies.digitIgnore] = digitIgnoreLocators;
894
+ }
895
+ }
896
+ if (strategies[this.locatorStrategies.context]) {
897
+ const contextLocators = this.getContextLocators(element, basicLocators);
898
+ if (contextLocators.length > 0) {
899
+ allStrategyLocators[this.locatorStrategies.context] = contextLocators;
900
+ }
901
+ }
783
902
  }
784
903
  }
785
- console.groupCollapsed("Generating No Text locators for element:", element);
786
- const noTextLocators = this.getUniqueLocators(element, this.getNoTextLocators.bind(this), options);
904
+ if (strategies[this.locatorStrategies.no_text]) {
905
+ console.groupCollapsed("Generating No Text locators for element:", element);
906
+ const noTextLocators = this.getUniqueLocators(element, this.getNoTextLocators.bind(this), options);
787
907
 
788
- if (noTextLocators.length > 0) {
789
- allStrategyLocators[this.locatorStrategies.no_text] = noTextLocators;
790
- } else {
791
- const _locators = [];
792
- _locators.push({
793
- css: this.generateUniqueCSSSelector(element, options),
794
- score: 500,
795
- priority: 3,
796
- });
797
- if (_locators.length > 0) {
798
- allStrategyLocators[this.locatorStrategies.no_text] = _locators;
908
+ if (noTextLocators.length > 0) {
909
+ allStrategyLocators[this.locatorStrategies.no_text] = noTextLocators;
910
+ } else {
911
+
912
+ // try mixed locator strategy as last resort
913
+ const mixedLocators = this.getUniqueLocators(element, this.getMixedLocators.bind(this), options);
914
+ if (mixedLocators.length > 0) {
915
+ allStrategyLocators[this.locatorStrategies.no_text] = mixedLocators;
916
+ } else {
917
+ const _locators = [];
918
+ _locators.push({
919
+ css: this.generateUniqueCSSSelector(element, options),
920
+ score: 500,
921
+ priority: 3,
922
+ });
923
+ if (_locators.length > 0) {
924
+ allStrategyLocators[this.locatorStrategies.no_text] = _locators;
925
+ }
926
+ }
799
927
  }
928
+ console.groupEnd();
800
929
  }
801
- console.groupEnd();
802
930
 
803
931
  let bestStrategy = this.getBestStrategy(allStrategyLocators);
804
932
  if (!bestStrategy) {
@@ -1,3 +1,7 @@
1
+ import dotenv from "dotenv";
2
+ // Load .env into process.env
3
+ dotenv.config();
4
+
1
5
  import {
2
6
  After,
3
7
  setDefaultTimeout,
@@ -30,8 +34,8 @@ BeforeStep(async function (step) {
30
34
  }
31
35
  });
32
36
 
33
- AfterStep(async function (step) {
37
+ AfterStep(async function ({ result, pickleStep }) {
34
38
  if (context) {
35
- await context.web.afterStep(this, step);
39
+ await context.web.afterStep(this, pickleStep, result);
36
40
  }
37
41
  });