@dev-blinq/cucumber_client 1.0.1328-dev → 1.0.1328-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 (52) hide show
  1. package/bin/assets/bundled_scripts/recorder.js +110 -110
  2. package/bin/assets/preload/css_gen.js +10 -10
  3. package/bin/assets/preload/recorderv3.js +3 -1
  4. package/bin/assets/preload/toolbar.js +27 -29
  5. package/bin/assets/preload/unique_locators.js +1 -1
  6. package/bin/assets/preload/yaml.js +288 -275
  7. package/bin/assets/scripts/aria_snapshot.js +223 -220
  8. package/bin/assets/scripts/dom_attr.js +329 -329
  9. package/bin/assets/scripts/dom_parent.js +169 -174
  10. package/bin/assets/scripts/event_utils.js +94 -94
  11. package/bin/assets/scripts/pw.js +2050 -1949
  12. package/bin/assets/scripts/recorder.js +5 -17
  13. package/bin/assets/scripts/snapshot_capturer.js +153 -146
  14. package/bin/assets/scripts/unique_locators.js +173 -48
  15. package/bin/assets/scripts/yaml.js +796 -783
  16. package/bin/assets/templates/_hooks_template.txt +41 -0
  17. package/bin/assets/templates/utils_template.txt +1 -44
  18. package/bin/client/apiTest/apiTest.js +6 -0
  19. package/bin/client/cli_helpers.js +11 -13
  20. package/bin/client/code_cleanup/utils.js +5 -1
  21. package/bin/client/code_gen/api_codegen.js +2 -2
  22. package/bin/client/code_gen/code_inversion.js +53 -4
  23. package/bin/client/code_gen/page_reflection.js +839 -906
  24. package/bin/client/code_gen/playwright_codeget.js +26 -18
  25. package/bin/client/cucumber/feature.js +89 -27
  26. package/bin/client/cucumber/feature_data.js +2 -2
  27. package/bin/client/cucumber/project_to_document.js +9 -3
  28. package/bin/client/cucumber/steps_definitions.js +6 -3
  29. package/bin/client/cucumber_selector.js +17 -1
  30. package/bin/client/local_agent.js +6 -5
  31. package/bin/client/parse_feature_file.js +23 -26
  32. package/bin/client/playground/projects/env.json +2 -2
  33. package/bin/client/project.js +186 -196
  34. package/bin/client/recorderv3/bvt_recorder.js +182 -79
  35. package/bin/client/recorderv3/implemented_steps.js +24 -14
  36. package/bin/client/recorderv3/index.js +68 -54
  37. package/bin/client/recorderv3/network.js +22 -5
  38. package/bin/client/recorderv3/scriptTest.js +1 -1
  39. package/bin/client/recorderv3/services.js +4 -16
  40. package/bin/client/recorderv3/step_runner.js +303 -228
  41. package/bin/client/recorderv3/step_utils.js +484 -7
  42. package/bin/client/recorderv3/update_feature.js +32 -30
  43. package/bin/client/run_cucumber.js +5 -1
  44. package/bin/client/scenario_report.js +0 -5
  45. package/bin/client/test_scenario.js +0 -1
  46. package/bin/client/upload-service.js +3 -2
  47. package/bin/client/utils/socket_logger.js +132 -0
  48. package/bin/index.js +1 -0
  49. package/bin/logger.js +3 -2
  50. package/bin/min/consoleApi.min.cjs +2 -3
  51. package/bin/min/injectedScript.min.cjs +16 -16
  52. package/package.json +21 -12
@@ -150,6 +150,7 @@ class LocatorGenerator {
150
150
  }
151
151
  getTextLocators(element, options) {
152
152
  const injectedScript = this.injectedScript;
153
+ const { textToIgnore = null } = options;
153
154
  const selectorPartLists = this.PW.selectorGenerator.buildTextCandidates(injectedScript, element, options);
154
155
  const result = [];
155
156
  for (const selectorPartList of selectorPartLists) {
@@ -157,6 +158,9 @@ class LocatorGenerator {
157
158
  const tSelectorList = [];
158
159
  for (const selectorPart of selectorPartList) {
159
160
  const { engine, selector } = selectorPart;
161
+ if (textToIgnore && selector.includes(textToIgnore)) {
162
+ continue;
163
+ }
160
164
  if (engine === "css") {
161
165
  tSelectorList.push(selector);
162
166
  } else {
@@ -213,6 +217,52 @@ class LocatorGenerator {
213
217
  }
214
218
  return result;
215
219
  }
220
+ toContextLocators(element, contextElement) {
221
+ const commonParent = this.dom_Parent.findLowestCommonAncestor([contextElement, element]);
222
+ const climb = this.dom_Parent.getClimbCountToParent(contextElement, commonParent);
223
+ const text = contextElement.innerText.trim();
224
+
225
+ const prefix = `internal:text="${text}" >> ${this.getXPathSelector(climb)}`;
226
+ const result = this.getElementLocators(element, {
227
+ root: commonParent,
228
+ strategies: {
229
+ [this.locatorStrategies.custom]: true,
230
+ [this.locatorStrategies.text]: true,
231
+ [this.locatorStrategies.no_text]: true,
232
+ },
233
+ prefix,
234
+ });
235
+
236
+ const attachContextToLocators = (locs) => {
237
+ locs.forEach((loc) => {
238
+ loc.climb = climb;
239
+ loc.text = text;
240
+ });
241
+ };
242
+
243
+ const allStrategyLocators = result.allStrategyLocators;
244
+ const locators = result.locators;
245
+ if (allStrategyLocators) {
246
+ const allLocators = [];
247
+ for (const strategy in allStrategyLocators) {
248
+ if (strategy === "strategy") continue;
249
+ const locators = allStrategyLocators[strategy];
250
+ if (locators.length === 0) continue;
251
+ allLocators.push(...locators);
252
+ allStrategyLocators[strategy] = [];
253
+ }
254
+ attachContextToLocators(allLocators);
255
+ allStrategyLocators[this.locatorStrategies.context] = allLocators;
256
+ allStrategyLocators.strategy = this.locatorStrategies.context;
257
+ result.locators = allLocators;
258
+ return result;
259
+ }
260
+ if (locators) {
261
+ attachContextToLocators(locators);
262
+ return result;
263
+ }
264
+ return result;
265
+ }
216
266
  getContextLocators(element, locators) {
217
267
  if (!locators || !Array.isArray(locators)) {
218
268
  console.error("Locators must be an array");
@@ -283,7 +333,7 @@ class LocatorGenerator {
283
333
  }
284
334
  const textElement = elements[0];
285
335
  // const text = this.PW.selectorUtils.elementText(textElement);
286
- const text = this.injectedScript.utils.elementText(new Map(), textElement).full;
336
+ const text = this.injectedScript.utils.elementText(new Map(), textElement).full.trim();
287
337
 
288
338
  const fullSelector = `${textLocator} >> xpath=${xpath} >> ${restOfSelector}`;
289
339
  const fullElements = this.getMatchingElements(fullSelector, {});
@@ -361,7 +411,7 @@ class LocatorGenerator {
361
411
  hasDigitsInText = digitsRegex.test(text);
362
412
 
363
413
  let pattern = this.PW.stringUtils.escapeRegExp(text.substring(1, text.length - 2));
364
- const re = new RegExp("^" + pattern + "$");
414
+ const re = new RegExp(pattern);
365
415
 
366
416
  finalSelector += `internal:text=${escapeRegexForSelector(re).replace(digitsRegex, "\\d+")} >> `;
367
417
  }
@@ -437,8 +487,16 @@ class LocatorGenerator {
437
487
  categorizeLocators(element, locators, options) {
438
488
  const unique = [];
439
489
  const nonUnique = [];
490
+ const visible = options?.visible ?? true;
440
491
  try {
441
492
  for (const locator of locators) {
493
+ if (!locator || !locator.css || typeof locator.css !== "string") {
494
+ console.error("Locator must have a valid css selector found: ", locator);
495
+ continue;
496
+ }
497
+ if (visible === false) {
498
+ locator.visible = false;
499
+ }
442
500
  const elements = this.getMatchingElements(locator.css, options);
443
501
  if (elements.length === 0) {
444
502
  console.warn(`No elements found for locator: ${locator.css}`);
@@ -617,7 +675,7 @@ class LocatorGenerator {
617
675
 
618
676
  getUniqueLocators2(element, locatorGenerator = this.getNoTextLocators, options = {}) {
619
677
  try {
620
- const { maxLocators = 5, root = window.document.body } = options;
678
+ const { maxLocators = 5, root = window.document.body, prefix } = options;
621
679
 
622
680
  if (!element) {
623
681
  return [];
@@ -637,13 +695,7 @@ class LocatorGenerator {
637
695
  },
638
696
  ];
639
697
  } else {
640
- return [
641
- {
642
- css: ":root",
643
- score: 1,
644
- priority: 1,
645
- },
646
- ];
698
+ return [];
647
699
  }
648
700
  }
649
701
 
@@ -670,12 +722,15 @@ class LocatorGenerator {
670
722
 
671
723
  const elementsCache = new Map();
672
724
 
673
- const allAncestors = this.dom_Parent.getFullAncestorChainToRoot(element, root);
725
+ const allAncestors = prefix ? [element] : this.dom_Parent.getFullAncestorChainToRoot(element, root);
674
726
  allAncestors.shift(); // remove the element itself from the ancestors
675
727
 
728
+ const cache = new Map();
729
+ const textToIgnore = this.PW.selectorUtils.elementText(cache, element).full.trim();
676
730
  const ancestorLocators = [];
731
+ let uniqueAncestor = null;
677
732
  for (const ancestor of allAncestors) {
678
- const _locators = locatorGenerator(ancestor, options);
733
+ const _locators = locatorGenerator(ancestor, { ...options, textToIgnore });
679
734
  if (!_locators || !Array.isArray(_locators) || _locators.length === 0) {
680
735
  continue;
681
736
  }
@@ -686,11 +741,15 @@ class LocatorGenerator {
686
741
  });
687
742
  elementsCache.set(ancestor, _categorized);
688
743
  if (_categorized.unique.length > 0) {
744
+ uniqueAncestor = {
745
+ element: ancestor,
746
+ locators: _categorized,
747
+ };
689
748
  break;
690
749
  }
691
750
  }
692
751
 
693
- const uniqueAncestor = ancestorLocators[ancestorLocators.length - 1];
752
+ // const uniqueAncestor = ancestorLocators[ancestorLocators.length - 1];
694
753
 
695
754
  for (const locator of nonUnique) {
696
755
  const selector = locator.css ?? locator.selector;
@@ -699,6 +758,27 @@ class LocatorGenerator {
699
758
  console.warn(`No elements found for locator: ${selector}`);
700
759
  continue;
701
760
  }
761
+ if (!uniqueAncestor) {
762
+ const elements = this.getMatchingElements(selector, options);
763
+ if (elements.length === 1 && elements[0] === element) {
764
+ result.push({
765
+ css: selector,
766
+ score: locator.score,
767
+ priority: 1,
768
+ });
769
+ } else {
770
+ const index = elements.indexOf(element);
771
+ if (index !== -1) {
772
+ result.push({
773
+ css: selector,
774
+ index,
775
+ score: locator.score + 200,
776
+ priority: 2,
777
+ });
778
+ }
779
+ }
780
+ continue;
781
+ }
702
782
 
703
783
  for (const unique_locator of uniqueAncestor.locators.unique) {
704
784
  const fullSelector = `${unique_locator.css} >> ${selector}`;
@@ -737,12 +817,47 @@ class LocatorGenerator {
737
817
  return [];
738
818
  }
739
819
  }
820
+ isElementVisible(element) {
821
+ if (!(element instanceof Element)) return false;
822
+ const style = window.getComputedStyle(element);
823
+ if (style.display === "none" || style.visibility === "hidden" || style.opacity === "0") return false;
824
+ const rect = element.getBoundingClientRect();
825
+ if (rect.width === 0 || rect.height === 0) return false;
826
+ return true;
827
+ }
740
828
  getElementLocators(element, options = {}) {
829
+ const isVisible = this.isElementVisible(element);
830
+ if (isVisible === false) {
831
+ console.warn("Element is not visible: ", element);
832
+ options.visible = isVisible;
833
+ }
741
834
  try {
742
- const { excludeText = false } = options;
743
-
744
- const allStrategyLocators = {};
745
- if (this.options?.customAttributes) {
835
+ const {
836
+ excludeText = false,
837
+ strategies = {
838
+ [this.locatorStrategies.custom]: true,
839
+ [this.locatorStrategies.context]: true,
840
+ [this.locatorStrategies.text]: true,
841
+ [this.locatorStrategies.text_with_index]: true,
842
+ [this.locatorStrategies.digitIgnore]: true,
843
+ [this.locatorStrategies.no_text]: true,
844
+ },
845
+ } = options;
846
+
847
+ const allStrategyLocators = {
848
+ [this.locatorStrategies.custom]: [],
849
+ [this.locatorStrategies.context]: [],
850
+ [this.locatorStrategies.text]: [],
851
+ [this.locatorStrategies.text_with_index]: [],
852
+ [this.locatorStrategies.digitIgnore]: [],
853
+ [this.locatorStrategies.no_text]: [],
854
+ };
855
+ if (
856
+ strategies[this.locatorStrategies.custom] &&
857
+ this.options?.customAttributes &&
858
+ Array.isArray(this.options.customAttributes) &&
859
+ this.options.customAttributes.length > 0
860
+ ) {
746
861
  console.groupCollapsed("Generating Custom locators for element:", element);
747
862
  const customLocators = this.getUniqueLocators(element, this.getCustomLocators.bind(this), options);
748
863
  if (customLocators.length > 0) {
@@ -751,43 +866,53 @@ class LocatorGenerator {
751
866
  }
752
867
  console.groupEnd();
753
868
  if (!excludeText) {
754
- console.groupCollapsed("Generating Text locators for element:", element);
755
- const basicLocators = this.getUniqueLocators(element, this.getTextLocators.bind(this), options);
756
- console.groupEnd();
757
- if (basicLocators.length > 0) {
758
- allStrategyLocators[this.locatorStrategies.text] = basicLocators;
759
- }
869
+ if (strategies[this.locatorStrategies.text]) {
870
+ console.groupCollapsed("Generating Text locators for element:", element);
760
871
 
761
- const textWithIndexLocators = this.getTextwithIndexLocators(basicLocators);
762
- if (textWithIndexLocators.length > 0) {
763
- allStrategyLocators[this.locatorStrategies.text_with_index] = textWithIndexLocators;
764
- }
765
- const digitIgnoreLocators = this.getDigitIgnoreLocators(element, basicLocators);
766
- if (digitIgnoreLocators.length > 0) {
767
- allStrategyLocators[this.locatorStrategies.digitIgnore] = digitIgnoreLocators;
768
- }
769
- const contextLocators = this.getContextLocators(element, basicLocators);
770
- if (contextLocators.length > 0) {
771
- allStrategyLocators[this.locatorStrategies.context] = contextLocators;
872
+ const basicLocators = this.getUniqueLocators(element, this.getTextLocators.bind(this), options);
873
+ console.groupEnd();
874
+ if (basicLocators.length > 0) {
875
+ allStrategyLocators[this.locatorStrategies.text] = basicLocators;
876
+ }
877
+ if (strategies[this.locatorStrategies.text_with_index]) {
878
+ const textWithIndexLocators = this.getTextwithIndexLocators(basicLocators);
879
+ if (textWithIndexLocators.length > 0) {
880
+ allStrategyLocators[this.locatorStrategies.text_with_index] = textWithIndexLocators;
881
+ }
882
+ }
883
+ if (strategies[this.locatorStrategies.digitIgnore]) {
884
+ const digitIgnoreLocators = this.getDigitIgnoreLocators(element, basicLocators);
885
+ if (digitIgnoreLocators.length > 0) {
886
+ allStrategyLocators[this.locatorStrategies.digitIgnore] = digitIgnoreLocators;
887
+ }
888
+ }
889
+ if (strategies[this.locatorStrategies.context]) {
890
+ const contextLocators = this.getContextLocators(element, basicLocators);
891
+ if (contextLocators.length > 0) {
892
+ allStrategyLocators[this.locatorStrategies.context] = contextLocators;
893
+ }
894
+ }
772
895
  }
773
896
  }
774
- console.groupCollapsed("Generating No Text locators for element:", element);
775
- const noTextLocators = this.getUniqueLocators(element, this.getNoTextLocators.bind(this), options);
897
+ if (strategies[this.locatorStrategies.no_text]) {
898
+ console.groupCollapsed("Generating No Text locators for element:", element);
899
+ const noTextLocators = this.getUniqueLocators(element, this.getNoTextLocators.bind(this), options);
776
900
 
777
- if (noTextLocators.length > 0) {
778
- allStrategyLocators[this.locatorStrategies.no_text] = noTextLocators;
779
- } else {
780
- const _locators = [];
781
- _locators.push({
782
- css: this.generateUniqueCSSSelector(element, options),
783
- score: 500,
784
- priority: 3,
785
- });
786
- if (_locators.length > 0) {
787
- allStrategyLocators[this.locatorStrategies.no_text] = _locators;
901
+ if (noTextLocators.length > 0) {
902
+ allStrategyLocators[this.locatorStrategies.no_text] = noTextLocators;
903
+ } else {
904
+ const _locators = [];
905
+ _locators.push({
906
+ css: this.generateUniqueCSSSelector(element, options),
907
+ score: 500,
908
+ priority: 3,
909
+ });
910
+ if (_locators.length > 0) {
911
+ allStrategyLocators[this.locatorStrategies.no_text] = _locators;
912
+ }
788
913
  }
914
+ console.groupEnd();
789
915
  }
790
- console.groupEnd();
791
916
 
792
917
  let bestStrategy = this.getBestStrategy(allStrategyLocators);
793
918
  if (!bestStrategy) {