@dev-blinq/cucumber_client 1.0.1476-dev → 1.0.1476-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 (47) hide show
  1. package/bin/assets/bundled_scripts/recorder.js +49 -49
  2. package/bin/assets/scripts/recorder.js +87 -34
  3. package/bin/assets/scripts/snapshot_capturer.js +10 -17
  4. package/bin/assets/scripts/unique_locators.js +78 -28
  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/codemod/find_harcoded_locators.js +173 -0
  8. package/bin/client/code_cleanup/codemod/fix_hardcoded_locators.js +247 -0
  9. package/bin/client/code_cleanup/utils.js +16 -7
  10. package/bin/client/code_gen/code_inversion.js +125 -1
  11. package/bin/client/code_gen/duplication_analysis.js +2 -1
  12. package/bin/client/code_gen/function_signature.js +8 -0
  13. package/bin/client/code_gen/index.js +4 -0
  14. package/bin/client/code_gen/page_reflection.js +90 -9
  15. package/bin/client/code_gen/playwright_codeget.js +173 -77
  16. package/bin/client/codemod/find_harcoded_locators.js +173 -0
  17. package/bin/client/codemod/fix_hardcoded_locators.js +247 -0
  18. package/bin/client/codemod/index.js +8 -0
  19. package/bin/client/codemod/locators_array/find_misstructured_elements.js +148 -0
  20. package/bin/client/codemod/locators_array/fix_misstructured_elements.js +144 -0
  21. package/bin/client/codemod/locators_array/index.js +114 -0
  22. package/bin/client/codemod/types.js +1 -0
  23. package/bin/client/cucumber/feature.js +4 -17
  24. package/bin/client/cucumber/steps_definitions.js +17 -12
  25. package/bin/client/recorderv3/bvt_init.js +310 -0
  26. package/bin/client/recorderv3/bvt_recorder.js +1559 -1182
  27. package/bin/client/recorderv3/constants.js +45 -0
  28. package/bin/client/recorderv3/implemented_steps.js +2 -0
  29. package/bin/client/recorderv3/index.js +3 -305
  30. package/bin/client/recorderv3/mixpanel.js +39 -0
  31. package/bin/client/recorderv3/services.js +839 -142
  32. package/bin/client/recorderv3/step_runner.js +36 -7
  33. package/bin/client/recorderv3/step_utils.js +316 -98
  34. package/bin/client/recorderv3/update_feature.js +85 -37
  35. package/bin/client/recorderv3/utils.js +80 -0
  36. package/bin/client/recorderv3/wbr_entry.js +61 -0
  37. package/bin/client/recording.js +1 -0
  38. package/bin/client/types/locators.js +2 -0
  39. package/bin/client/upload-service.js +2 -0
  40. package/bin/client/utils/app_dir.js +21 -0
  41. package/bin/client/utils/socket_logger.js +100 -125
  42. package/bin/index.js +5 -0
  43. package/package.json +21 -6
  44. package/bin/client/recorderv3/app_dir.js +0 -23
  45. package/bin/client/recorderv3/network.js +0 -299
  46. package/bin/client/recorderv3/scriptTest.js +0 -5
  47. 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,15 +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 result = this.locatorGenerator.toContextLocators(el, this.contextElement);
842
+ const result = this.locatorGenerator.toContextLocators(el, this.contextElement, options);
794
843
  return result;
795
844
  }
796
845
  const isRecordingText = this.#mode === "recordingText";
797
846
  return this.locatorGenerator.getElementLocators(el, {
798
847
  excludeText: isRecordingText,
848
+ ...options,
799
849
  });
800
850
  }
801
851
  addListeners() {
@@ -832,31 +882,7 @@ class BVTRecorder {
832
882
  }
833
883
 
834
884
  performance.mark("command-send");
835
- const cmd = {
836
- mode: this.#mode,
837
- action: action.details,
838
- element: this.getElementDetails(actionElement, eventName),
839
- isPopupCloseClick: this.isPopupCloseEvent(e),
840
- // ...this.getLocatorsObject(actionElement),
841
- ...(actionElement.__locators ?? this.getLocatorsObject(actionElement)),
842
- frame: this.getFrameDetails(),
843
- statistics: {
844
- time: `${performance.measure("command-received", "command-send").duration.toFixed(2)} ms`,
845
- },
846
- };
847
- const snapshotDetails = {
848
- id: actionElement.getAttribute("data-blinq-id"),
849
- contextId: this.contextElement?.getAttribute("data-blinq-context-id"),
850
- doc: this.snapshotCapturer.createSnapshot({
851
- excludeSelectors: ["x-bvt-toolbar", "script", "style", "link[rel=stylesheet]"],
852
- }),
853
- };
854
- cmd.snapshotDetails = snapshotDetails;
855
- // eventQueue.enqueue(async () => {
856
- // await bvtRecorderBindings.validateLocators(snapshotDetails);
857
- // });
858
- // console.log(cmd);
859
- await bvtRecorderBindings.recordCommand(cmd);
885
+ this.recordEvent(action, actionElement, eventName, e);
860
886
  this.handleStateTransition(action.element);
861
887
  },
862
888
  { capture: true }
@@ -864,6 +890,33 @@ class BVTRecorder {
864
890
  });
865
891
  }
866
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
+
867
920
  // TODO: implement the corresponding logic for the below methods
868
921
  setPopupHandlers(_popopHandlers) {
869
922
  this.popupHandlers = _popopHandlers;
@@ -882,7 +935,7 @@ class BVTRecorder {
882
935
  this.interestedElements.clear();
883
936
  }
884
937
  processAriaSnapshot(snapshot) {
885
- const matchedElements = this.findMatchingElements(snapshot, this.snapshotElements);
938
+ const matchedElements = this.snapshotUtils.findMatchingElements(snapshot, this.snapshotElements);
886
939
  for (const el of matchedElements.values()) {
887
940
  const element = el;
888
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,10 +217,18 @@ class LocatorGenerator {
217
217
  }
218
218
  return result;
219
219
  }
220
- toContextLocators(element, contextElement) {
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 = {}) {
221
227
  const commonParent = this.dom_Parent.findLowestCommonAncestor([contextElement, element]);
222
228
  const climb = this.dom_Parent.getClimbCountToParent(contextElement, commonParent);
223
229
  const text = contextElement.innerText.trim();
230
+
231
+ const prefix = `internal:text="${text}" >> ${this.getXPathSelector(climb)}`;
224
232
  const result = this.getElementLocators(element, {
225
233
  root: commonParent,
226
234
  strategies: {
@@ -228,26 +236,17 @@ class LocatorGenerator {
228
236
  [this.locatorStrategies.text]: true,
229
237
  [this.locatorStrategies.no_text]: true,
230
238
  },
239
+ prefix,
240
+ ...options,
231
241
  });
232
242
 
233
- const randomToken = Math.random().toString(36).substring(2, 8);
234
- commonParent.setAttribute("data-blinq--" + randomToken, "true");
235
- // const contextLocators = [];
236
-
237
243
  const attachContextToLocators = (locs) => {
238
244
  locs.forEach((loc) => {
239
245
  loc.climb = climb;
240
246
  loc.text = text;
241
- const _selector = `[data-blinq--${randomToken}]` + " >> " + this.getXPathSelector(climb) + " >> " + loc.css;
242
- const elements = this.getMatchingElements(_selector, { root: window.document });
243
- const index = elements.indexOf(element);
244
- if (index !== -1) {
245
- loc.index = index;
246
- } else {
247
- console.error("Invalid context locator, element not found in context locator", loc, element, contextElement);
248
- }
249
247
  });
250
248
  };
249
+
251
250
  const allStrategyLocators = result.allStrategyLocators;
252
251
  const locators = result.locators;
253
252
  if (allStrategyLocators) {
@@ -262,6 +261,7 @@ class LocatorGenerator {
262
261
  attachContextToLocators(allLocators);
263
262
  allStrategyLocators[this.locatorStrategies.context] = allLocators;
264
263
  allStrategyLocators.strategy = this.locatorStrategies.context;
264
+ result.locators = allLocators;
265
265
  return result;
266
266
  }
267
267
  if (locators) {
@@ -494,12 +494,16 @@ class LocatorGenerator {
494
494
  categorizeLocators(element, locators, options) {
495
495
  const unique = [];
496
496
  const nonUnique = [];
497
+ const visible = options?.visible ?? true;
497
498
  try {
498
499
  for (const locator of locators) {
499
500
  if (!locator || !locator.css || typeof locator.css !== "string") {
500
501
  console.error("Locator must have a valid css selector found: ", locator);
501
502
  continue;
502
503
  }
504
+ if (visible === false) {
505
+ locator.visible = false;
506
+ }
503
507
  const elements = this.getMatchingElements(locator.css, options);
504
508
  if (elements.length === 0) {
505
509
  console.warn(`No elements found for locator: ${locator.css}`);
@@ -624,7 +628,7 @@ class LocatorGenerator {
624
628
  result.push(_locator);
625
629
  } else {
626
630
  const index = _elements.indexOf(element);
627
- if (index !== -1 && index < 5) {
631
+ if (index !== -1 && index < 10) {
628
632
  // _locator.selector = fullSelector;
629
633
  _locator.css = fullSelector;
630
634
  _locator.index = index;
@@ -636,7 +640,7 @@ class LocatorGenerator {
636
640
  }
637
641
  } else {
638
642
  const index = elements.indexOf(element);
639
- if (index !== -1 && index < 5) {
643
+ if (index !== -1 && index < 10) {
640
644
  locator.index = index;
641
645
  locator.priority = 2; // non-unique locators have lower priority
642
646
  result.push(locator);
@@ -644,7 +648,7 @@ class LocatorGenerator {
644
648
  }
645
649
  } else {
646
650
  const index = elements.indexOf(element);
647
- if (index !== -1 && index < 5) {
651
+ if (index !== -1 && index < 10) {
648
652
  locator.index = index;
649
653
  locator.priority = 2; // non-unique locators have lower priority
650
654
  result.push(locator);
@@ -678,7 +682,7 @@ class LocatorGenerator {
678
682
 
679
683
  getUniqueLocators2(element, locatorGenerator = this.getNoTextLocators, options = {}) {
680
684
  try {
681
- const { maxLocators = 5, root = window.document.body } = options;
685
+ const { maxLocators = 5, root = window.document.body, prefix } = options;
682
686
 
683
687
  if (!element) {
684
688
  return [];
@@ -725,12 +729,13 @@ class LocatorGenerator {
725
729
 
726
730
  const elementsCache = new Map();
727
731
 
728
- const allAncestors = this.dom_Parent.getFullAncestorChainToRoot(element, root);
732
+ const allAncestors = prefix ? [element] : this.dom_Parent.getFullAncestorChainToRoot(element, root);
729
733
  allAncestors.shift(); // remove the element itself from the ancestors
730
734
 
731
735
  const cache = new Map();
732
736
  const textToIgnore = this.PW.selectorUtils.elementText(cache, element).full.trim();
733
737
  const ancestorLocators = [];
738
+ let uniqueAncestor = null;
734
739
  for (const ancestor of allAncestors) {
735
740
  const _locators = locatorGenerator(ancestor, { ...options, textToIgnore });
736
741
  if (!_locators || !Array.isArray(_locators) || _locators.length === 0) {
@@ -743,11 +748,15 @@ class LocatorGenerator {
743
748
  });
744
749
  elementsCache.set(ancestor, _categorized);
745
750
  if (_categorized.unique.length > 0) {
751
+ uniqueAncestor = {
752
+ element: ancestor,
753
+ locators: _categorized,
754
+ };
746
755
  break;
747
756
  }
748
757
  }
749
758
 
750
- const uniqueAncestor = ancestorLocators[ancestorLocators.length - 1];
759
+ // const uniqueAncestor = ancestorLocators[ancestorLocators.length - 1];
751
760
 
752
761
  for (const locator of nonUnique) {
753
762
  const selector = locator.css ?? locator.selector;
@@ -756,6 +765,27 @@ class LocatorGenerator {
756
765
  console.warn(`No elements found for locator: ${selector}`);
757
766
  continue;
758
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
+ }
759
789
 
760
790
  for (const unique_locator of uniqueAncestor.locators.unique) {
761
791
  const fullSelector = `${unique_locator.css} >> ${selector}`;
@@ -771,7 +801,7 @@ class LocatorGenerator {
771
801
  result.push(newLocator);
772
802
  } else {
773
803
  const index = elements.indexOf(element);
774
- if (index !== -1 && index < 5) {
804
+ if (index !== -1 && index < 10) {
775
805
  const effectiveScore = (unique_locator.score + locator.score) / 2;
776
806
  const newLocator = {
777
807
  ...unique_locator,
@@ -794,7 +824,20 @@ class LocatorGenerator {
794
824
  return [];
795
825
  }
796
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
+ }
797
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
+ }
798
841
  try {
799
842
  const {
800
843
  excludeText = false,
@@ -865,14 +908,21 @@ class LocatorGenerator {
865
908
  if (noTextLocators.length > 0) {
866
909
  allStrategyLocators[this.locatorStrategies.no_text] = noTextLocators;
867
910
  } else {
868
- const _locators = [];
869
- _locators.push({
870
- css: this.generateUniqueCSSSelector(element, options),
871
- score: 500,
872
- priority: 3,
873
- });
874
- if (_locators.length > 0) {
875
- allStrategyLocators[this.locatorStrategies.no_text] = _locators;
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
+ }
876
926
  }
877
927
  }
878
928
  console.groupEnd();
@@ -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
  });
@@ -12,7 +12,7 @@ import path from "path";
12
12
  * @param {string} text the text to verify exists in page
13
13
  * @protect
14
14
  */
15
- async function verifyTextExistsInPage(text) {
15
+ export async function verifyTextExistsInPage(text) {
16
16
  await context.web.verifyTextExistInPage(text, null, this);
17
17
  }
18
18
  Then("Verify the text {string} can be found in the page", verifyTextExistsInPage);
@@ -22,7 +22,7 @@ Then("Verify the text {string} can be found in the page", verifyTextExistsInPage
22
22
  * @param {string} elementDescription element description
23
23
  * @protect
24
24
  */
25
- async function clickOnElement(elementDescription) {
25
+ export async function clickOnElement(elementDescription) {
26
26
  await context.web.simpleClick(elementDescription, null, null, this);
27
27
  }
28
28
  When("click on {string}", clickOnElement);
@@ -36,7 +36,7 @@ When("Click {string}", clickOnElement);
36
36
  * @param {string} value value to fill the element with
37
37
  * @protect
38
38
  */
39
- async function fillElement(elementDescription, value) {
39
+ export async function fillElement(elementDescription, value) {
40
40
  await context.web.simpleClickType(elementDescription, value, null, null, this);
41
41
  }
42
42
  When("fill {string} with {string}", fillElement);
@@ -47,7 +47,7 @@ When("Fill {string} with {string}", fillElement);
47
47
  * @param {string} text the text to verify does not exist in page
48
48
  * @protect
49
49
  */
50
- async function verifyTextNotExistsInPage(text) {
50
+ export async function verifyTextNotExistsInPage(text) {
51
51
  await context.web.waitForTextToDisappear(text, null, this);
52
52
  }
53
53
  Then("Verify the text {string} cannot be found in the page", verifyTextNotExistsInPage);
@@ -57,7 +57,7 @@ Then("Verify the text {string} cannot be found in the page", verifyTextNotExists
57
57
  * @param {string} url URL to navigate
58
58
  * @protect
59
59
  */
60
- async function navigateTo(url) {
60
+ export async function navigateTo(url) {
61
61
  await context.web.goto(url, this);
62
62
  }
63
63
  When("Navigate to {string}", navigateTo);
@@ -66,7 +66,7 @@ When("Navigate to {string}", navigateTo);
66
66
  * Navigate to the current page
67
67
  * @protect
68
68
  */
69
- async function browserNavigateBack() {
69
+ export async function browserNavigateBack() {
70
70
  await context.web.goBack({}, this);
71
71
  }
72
72
  Then("Browser navigate back", browserNavigateBack);
@@ -75,7 +75,7 @@ Then("Browser navigate back", browserNavigateBack);
75
75
  * Navigate forward in browser history
76
76
  * @protect
77
77
  */
78
- async function browserNavigateForward() {
78
+ export async function browserNavigateForward() {
79
79
  await context.web.goForward({}, this);
80
80
  }
81
81
  Then("Browser navigate forward", browserNavigateForward);
@@ -85,7 +85,7 @@ Then("Browser navigate forward", browserNavigateForward);
85
85
  * @param {string} filePath the file path or empty to store in the test data file
86
86
  * @protect
87
87
  */
88
- async function storeBrowserSession(filePath) {
88
+ export async function storeBrowserSession(filePath) {
89
89
  await context.web.saveStoreState(filePath, this);
90
90
  }
91
91
  When("Store browser session {string}", storeBrowserSession);
@@ -95,7 +95,7 @@ When("Store browser session {string}", storeBrowserSession);
95
95
  * @param {string} filePath the file path or empty
96
96
  * @protect
97
97
  */
98
- async function resetBrowserSession(filePath) {
98
+ export async function resetBrowserSession(filePath) {
99
99
  await context.web.restoreSaveState(filePath, this);
100
100
  }
101
101
  When("Reset browser session {string}", resetBrowserSession);
@@ -107,7 +107,7 @@ When("Reset browser session {string}", resetBrowserSession);
107
107
  * @param {string} textToVerify the target text to verify
108
108
  * @protect
109
109
  */
110
- async function verifyTextRelatedToText(textAnchor, climb, textToVerify) {
110
+ export async function verifyTextRelatedToText(textAnchor, climb, textToVerify) {
111
111
  await context.web.verifyTextRelatedToText(textAnchor, climb, textToVerify, null, this);
112
112
  }
113
113
  Then(
@@ -120,7 +120,7 @@ Then(
120
120
  * @requestName the name of the bruno request file
121
121
  * @protect
122
122
  */
123
- async function runBrunoRequest(requestName) {
123
+ export async function runBrunoRequest(requestName) {
124
124
  await executeBrunoRequest(requestName, {}, context, this);
125
125
  }
126
126
  When("Bruno - {string}", runBrunoRequest);
@@ -131,7 +131,7 @@ When("bruno - {string}", runBrunoRequest);
131
131
  * @param {string} fileName the downloaded file to verify
132
132
  * @protect
133
133
  */
134
- async function verify_the_downloaded_file_exists(fileName) {
134
+ export async function verify_the_downloaded_file_exists(fileName) {
135
135
  const downloadFolder = path.join(context.reportFolder, "downloads");
136
136
  const downloadFile = path.join(downloadFolder, fileName);
137
137
  await verifyFileExists(downloadFile, {}, context, this);
@@ -148,7 +148,7 @@ When("Noop", async function () {});
148
148
  * @param {string} url URL to be verified against current URL
149
149
  * @protect
150
150
  */
151
- async function verify_page_url(url) {
151
+ export async function verify_page_url(url) {
152
152
  await context.web.verifyPagePath(url, {}, this);
153
153
  }
154
154
  Then("Verify the page url is {string}", verify_page_url);
@@ -158,7 +158,7 @@ Then("Verify the page url is {string}", verify_page_url);
158
158
  * @param {string} title Title to be verified against current Title
159
159
  * @protect
160
160
  */
161
- async function verify_page_title(title) {
161
+ export async function verify_page_title(title) {
162
162
  await context.web.verifyPageTitle(title, {}, this);
163
163
  }
164
164
  Then("Verify the page title is {string}", verify_page_title);
@@ -170,7 +170,7 @@ Then("Verify the page title is {string}", verify_page_title);
170
170
  * @param {world} - Optional world context
171
171
  * @returns Promise that resolves after the specified duration
172
172
  */
173
- async function sleep(duration) {
174
- await context.web.sleep(duration, {}, null);
173
+ export async function sleep(duration) {
174
+ await context.web.sleep(duration, {}, this);
175
175
  }
176
176
  Then("Sleep for {string} ms", { timeout: -1 }, sleep);