automation_model 1.0.464-dev → 1.0.464-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/lib/api.d.ts +42 -1
  2. package/lib/api.js +224 -49
  3. package/lib/api.js.map +1 -1
  4. package/lib/auto_page.js +38 -16
  5. package/lib/auto_page.js.map +1 -1
  6. package/lib/axe/axe.mini.js +12 -0
  7. package/lib/browser_manager.d.ts +5 -3
  8. package/lib/browser_manager.js +44 -19
  9. package/lib/browser_manager.js.map +1 -1
  10. package/lib/command_common.d.ts +6 -0
  11. package/lib/command_common.js +138 -0
  12. package/lib/command_common.js.map +1 -0
  13. package/lib/environment.js +5 -3
  14. package/lib/environment.js.map +1 -1
  15. package/lib/error-messages.d.ts +6 -0
  16. package/lib/error-messages.js +188 -0
  17. package/lib/error-messages.js.map +1 -0
  18. package/lib/index.d.ts +1 -0
  19. package/lib/index.js +1 -0
  20. package/lib/index.js.map +1 -1
  21. package/lib/init_browser.d.ts +1 -1
  22. package/lib/init_browser.js +18 -3
  23. package/lib/init_browser.js.map +1 -1
  24. package/lib/locate_element.d.ts +7 -0
  25. package/lib/locate_element.js +213 -0
  26. package/lib/locate_element.js.map +1 -0
  27. package/lib/locator.d.ts +36 -0
  28. package/lib/locator.js +165 -0
  29. package/lib/locator.js.map +1 -1
  30. package/lib/network.d.ts +3 -0
  31. package/lib/network.js +144 -0
  32. package/lib/network.js.map +1 -0
  33. package/lib/stable_browser.d.ts +26 -19
  34. package/lib/stable_browser.js +626 -773
  35. package/lib/stable_browser.js.map +1 -1
  36. package/lib/table.d.ts +13 -0
  37. package/lib/table.js +187 -0
  38. package/lib/table.js.map +1 -0
  39. package/lib/test_context.d.ts +1 -0
  40. package/lib/test_context.js +12 -12
  41. package/lib/test_context.js.map +1 -1
  42. package/lib/utils.d.ts +3 -1
  43. package/lib/utils.js +68 -1
  44. package/lib/utils.js.map +1 -1
  45. package/package.json +4 -5
@@ -10,12 +10,14 @@ import { getDateTimeValue } from "./date_time.js";
10
10
  import drawRectangle from "./drawRect.js";
11
11
  //import { closeUnexpectedPopups } from "./popups.js";
12
12
  import { getTableCells, getTableData } from "./table_analyze.js";
13
- import objectPath from "object-path";
14
- import { decrypt } from "./utils.js";
13
+ import { maskValue, replaceWithLocalTestData } from "./utils.js";
15
14
  import csv from "csv-parser";
16
15
  import { Readable } from "node:stream";
17
16
  import readline from "readline";
18
17
  import { getContext } from "./init_browser.js";
18
+ import { locate_element } from "./locate_element.js";
19
+ import { _commandError, _commandFinally, _preCommand, _validateSelectors, _screenshot, _reportToWorld, } from "./command_common.js";
20
+ import { registerDownloadEvent, registerNetworkEvents } from "./network.js";
19
21
  const Types = {
20
22
  CLICK: "click_element",
21
23
  NAVIGATE: "navigate",
@@ -42,20 +44,27 @@ const Types = {
42
44
  VERIFY_VISUAL: "verify_visual",
43
45
  LOAD_DATA: "load_data",
44
46
  SET_INPUT: "set_input",
47
+ WAIT_FOR_TEXT_TO_DISAPPEAR: "wait_for_text_to_disappear",
45
48
  };
46
49
  export const apps = {};
47
50
  class StableBrowser {
51
+ browser;
52
+ page;
53
+ logger;
54
+ context;
55
+ world;
56
+ project_path = null;
57
+ webLogFile = null;
58
+ networkLogger = null;
59
+ configuration = null;
60
+ appName = "main";
61
+ tags = null;
48
62
  constructor(browser, page, logger = null, context = null, world = null) {
49
63
  this.browser = browser;
50
64
  this.page = page;
51
65
  this.logger = logger;
52
66
  this.context = context;
53
67
  this.world = world;
54
- this.project_path = null;
55
- this.webLogFile = null;
56
- this.networkLogger = null;
57
- this.configuration = null;
58
- this.appName = "main";
59
68
  if (!this.logger) {
60
69
  this.logger = console;
61
70
  }
@@ -80,11 +89,13 @@ class StableBrowser {
80
89
  catch (e) {
81
90
  this.logger.error("unable to read ai_config.json");
82
91
  }
83
- context.pageLoading = { status: false };
84
- context.pages = [this.page];
85
92
  const logFolder = path.join(this.project_path, "logs", "web");
86
93
  this.world = world;
94
+ context.pages = [this.page];
95
+ context.pageLoading = { status: false };
87
96
  this.registerEventListeners(this.context);
97
+ registerNetworkEvents(this.world, this, this.context, this.page);
98
+ registerDownloadEvent(this.page, this.world, this.context);
88
99
  }
89
100
  registerEventListeners(context) {
90
101
  this.registerConsoleLogListener(this.page, context);
@@ -93,10 +104,17 @@ class StableBrowser {
93
104
  context.pageLoading = { status: false };
94
105
  }
95
106
  context.playContext.on("page", async function (page) {
107
+ if (this.configuration && this.configuration.closePopups === true) {
108
+ console.log("close unexpected popups");
109
+ await page.close();
110
+ return;
111
+ }
96
112
  context.pageLoading.status = true;
97
113
  this.page = page;
98
114
  context.page = page;
99
115
  context.pages.push(page);
116
+ registerNetworkEvents(this.world, this, context, this.page);
117
+ registerDownloadEvent(this.page, this.world, context);
100
118
  page.on("close", async () => {
101
119
  if (this.context && this.context.pages && this.context.pages.length > 1) {
102
120
  this.context.pages.pop();
@@ -126,9 +144,9 @@ class StableBrowser {
126
144
  if (this.appName === appName) {
127
145
  return;
128
146
  }
129
- let newContextCreated = false;
147
+ let navigate = false;
130
148
  if (!apps[appName]) {
131
- let newContext = await getContext(null, this.context.headless ? this.context.headless : false, this, this.logger, appName, false, this);
149
+ let newContext = await getContext(null, this.context.headless ? this.context.headless : false, this, this.logger, appName, false, this, -1, this.context.reportFolder);
132
150
  newContextCreated = true;
133
151
  apps[appName] = {
134
152
  context: newContext,
@@ -141,8 +159,7 @@ class StableBrowser {
141
159
  this._copyContext(apps[appName], this);
142
160
  apps[this.appName] = tempContext;
143
161
  this.appName = appName;
144
- if (newContextCreated) {
145
- this.registerEventListeners(this.context);
162
+ if (navigate) {
146
163
  await this.goto(this.context.environment.baseUrl);
147
164
  await this.waitForPageLoad();
148
165
  }
@@ -168,7 +185,6 @@ class StableBrowser {
168
185
  this.context.webLogger = [];
169
186
  }
170
187
  page.on("console", async (msg) => {
171
- var _a;
172
188
  const obj = {
173
189
  type: msg.type(),
174
190
  text: msg.text(),
@@ -176,7 +192,9 @@ class StableBrowser {
176
192
  time: new Date().toISOString(),
177
193
  };
178
194
  this.context.webLogger.push(obj);
179
- (_a = this.world) === null || _a === void 0 ? void 0 : _a.attach(JSON.stringify(obj), { mediaType: "application/json+log" });
195
+ if (msg.type() === "error") {
196
+ this.world?.attach(JSON.stringify(obj), { mediaType: "application/json+log" });
197
+ }
180
198
  });
181
199
  }
182
200
  registerRequestListener(page, context, logFile) {
@@ -184,7 +202,6 @@ class StableBrowser {
184
202
  this.context.networkLogger = [];
185
203
  }
186
204
  page.on("request", async (data) => {
187
- var _a;
188
205
  const startTime = new Date().getTime();
189
206
  try {
190
207
  const pageUrl = new URL(page.url());
@@ -209,10 +226,10 @@ class StableBrowser {
209
226
  startTime,
210
227
  };
211
228
  context.networkLogger.push(obj);
212
- (_a = this.world) === null || _a === void 0 ? void 0 : _a.attach(JSON.stringify(obj), { mediaType: "application/json+network" });
229
+ this.world?.attach(JSON.stringify(obj), { mediaType: "application/json+network" });
213
230
  }
214
231
  catch (error) {
215
- console.error("Error in request listener", error);
232
+ // console.error("Error in request listener", error);
216
233
  context.networkLogger.push({
217
234
  error: "not able to listen",
218
235
  message: error.message,
@@ -234,20 +251,6 @@ class StableBrowser {
234
251
  timeout: 60000,
235
252
  });
236
253
  }
237
- _validateSelectors(selectors) {
238
- if (!selectors) {
239
- throw new Error("selectors is null");
240
- }
241
- if (!selectors.locators) {
242
- throw new Error("selectors.locators is null");
243
- }
244
- if (!Array.isArray(selectors.locators)) {
245
- throw new Error("selectors.locators expected to be array");
246
- }
247
- if (selectors.locators.length === 0) {
248
- throw new Error("selectors.locators expected to be non empty array");
249
- }
250
- }
251
254
  _fixUsingParams(text, _params) {
252
255
  if (!_params || typeof text !== "string") {
253
256
  return text;
@@ -315,7 +318,7 @@ class StableBrowser {
315
318
  locatorReturn = scope.getByRole(role, { name }, { exact: flags === "i" });
316
319
  }
317
320
  }
318
- if (locator === null || locator === void 0 ? void 0 : locator.engine) {
321
+ if (locator?.engine) {
319
322
  if (locator.engine === "css") {
320
323
  locatorReturn = scope.locator(locator.selector);
321
324
  }
@@ -339,7 +342,7 @@ class StableBrowser {
339
342
  if (css && css.locator) {
340
343
  css = css.locator;
341
344
  }
342
- let result = await this._locateElementByText(scope, this._fixUsingParams(text, _params), "*", false, true, _params);
345
+ let result = await this._locateElementByText(scope, this._fixUsingParams(text, _params), "*:not(script, style, head)", false, false, _params);
343
346
  if (result.elementCount === 0) {
344
347
  return;
345
348
  }
@@ -354,7 +357,7 @@ class StableBrowser {
354
357
  }
355
358
  async _locateElementByText(scope, text1, tag1, regex1 = false, partial1, _params) {
356
359
  //const stringifyText = JSON.stringify(text);
357
- return await scope.evaluate(([text, tag, regex, partial]) => {
360
+ return await scope.locator(":root").evaluate((_node, [text, tag, regex, partial]) => {
358
361
  function isParent(parent, child) {
359
362
  let currentNode = child.parentNode;
360
363
  while (currentNode !== null) {
@@ -391,7 +394,7 @@ class StableBrowser {
391
394
  }
392
395
  document.collectAllShadowDomElements = collectAllShadowDomElements;
393
396
  if (!tag) {
394
- tag = "*";
397
+ tag = "*:not(script, style, head)";
395
398
  }
396
399
  let regexpSearch = document.getRegex(text);
397
400
  if (regexpSearch) {
@@ -473,6 +476,15 @@ class StableBrowser {
473
476
  }, [text1, tag1, regex1, partial1]);
474
477
  }
475
478
  async _collectLocatorInformation(selectorHierarchy, index = 0, scope, foundLocators, _params, info, visibleOnly = true) {
479
+ if (!info) {
480
+ info = {};
481
+ }
482
+ if (!info.failCause) {
483
+ info.failCause = {};
484
+ }
485
+ if (!info.log) {
486
+ info.log = "";
487
+ }
476
488
  let locatorSearch = selectorHierarchy[index];
477
489
  try {
478
490
  locatorSearch = JSON.parse(this._fixUsingParams(JSON.stringify(locatorSearch), _params));
@@ -485,13 +497,18 @@ class StableBrowser {
485
497
  if (locatorSearch.climb && locatorSearch.climb >= 0) {
486
498
  let locatorString = await this._locateElmentByTextClimbCss(scope, locatorSearch.text, locatorSearch.climb, locatorSearch.css, _params);
487
499
  if (!locatorString) {
500
+ info.failCause.textNotFound = true;
501
+ info.failCause.lastError = "failed to locate element by text: " + locatorSearch.text;
488
502
  return;
489
503
  }
490
504
  locator = this._getLocator({ css: locatorString }, scope, _params);
491
505
  }
492
506
  else if (locatorSearch.text) {
493
- let result = await this._locateElementByText(scope, this._fixUsingParams(locatorSearch.text, _params), locatorSearch.tag, false, locatorSearch.partial === true, _params);
507
+ let text = this._fixUsingParams(locatorSearch.text, _params);
508
+ let result = await this._locateElementByText(scope, text, locatorSearch.tag, false, locatorSearch.partial === true, _params);
494
509
  if (result.elementCount === 0) {
510
+ info.failCause.textNotFound = true;
511
+ info.failCause.lastError = "failed to locate element by text: " + text;
495
512
  return;
496
513
  }
497
514
  locatorSearch.css = "[data-blinq-id='blinq-id-" + result.randomToken + "']";
@@ -508,6 +525,9 @@ class StableBrowser {
508
525
  // cssHref = true;
509
526
  // }
510
527
  let count = await locator.count();
528
+ if (count > 0 && !info.failCause.count) {
529
+ info.failCause.count = count;
530
+ }
511
531
  //info.log += "total elements found " + count + "\n";
512
532
  //let visibleCount = 0;
513
533
  let visibleLocator = null;
@@ -525,6 +545,8 @@ class StableBrowser {
525
545
  foundLocators.push(locator.nth(j));
526
546
  }
527
547
  else {
548
+ info.failCause.visible = visible;
549
+ info.failCause.enabled = enabled;
528
550
  if (!info.printMessages) {
529
551
  info.printMessages = {};
530
552
  }
@@ -536,6 +558,11 @@ class StableBrowser {
536
558
  }
537
559
  }
538
560
  async closeUnexpectedPopups(info, _params) {
561
+ if (!info) {
562
+ info = {};
563
+ info.failCause = {};
564
+ info.log = "";
565
+ }
539
566
  if (this.configuration.popupHandlers && this.configuration.popupHandlers.length > 0) {
540
567
  if (!info) {
541
568
  info = {};
@@ -576,7 +603,10 @@ class StableBrowser {
576
603
  }
577
604
  return { rerun: false };
578
605
  }
579
- async _locate(selectors, info, _params, timeout = 30000) {
606
+ async _locate(selectors, info, _params, timeout) {
607
+ if (!timeout) {
608
+ timeout = 30000;
609
+ }
580
610
  for (let i = 0; i < 3; i++) {
581
611
  info.log += "attempt " + i + ": total locators " + selectors.locators.length + "\n";
582
612
  for (let j = 0; j < selectors.locators.length; j++) {
@@ -590,13 +620,16 @@ class StableBrowser {
590
620
  }
591
621
  throw new Error("unable to locate element " + JSON.stringify(selectors));
592
622
  }
593
- async _locate_internal(selectors, info, _params, timeout = 30000) {
594
- let highPriorityTimeout = 5000;
595
- let visibleOnlyTimeout = 6000;
596
- let startTime = performance.now();
597
- let locatorsCount = 0;
598
- //let arrayMode = Array.isArray(selectors);
623
+ async _findFrameScope(selectors, timeout = 30000, info) {
624
+ if (!info) {
625
+ info = {};
626
+ info.failCause = {};
627
+ info.log = "";
628
+ }
599
629
  let scope = this.page;
630
+ if (selectors.frame) {
631
+ return selectors.frame;
632
+ }
600
633
  if (selectors.iframe_src || selectors.frameLocators) {
601
634
  const findFrame = async (frame, framescope) => {
602
635
  for (let i = 0; i < frame.selectors.length; i++) {
@@ -623,7 +656,6 @@ class StableBrowser {
623
656
  }
624
657
  return framescope;
625
658
  };
626
- info.log += "searching for iframe " + selectors.iframe_src + "/" + selectors.frameLocators + "\n";
627
659
  while (true) {
628
660
  let frameFound = false;
629
661
  if (selectors.nestFrmLoc) {
@@ -647,6 +679,8 @@ class StableBrowser {
647
679
  if (!scope) {
648
680
  info.log += "unable to locate iframe " + selectors.iframe_src + "\n";
649
681
  if (performance.now() - startTime > timeout) {
682
+ info.failCause.iframeNotFound = true;
683
+ info.failCause.lastError = "unable to locate iframe " + selectors.iframe_src;
650
684
  throw new Error("unable to locate iframe " + selectors.iframe_src);
651
685
  }
652
686
  await new Promise((resolve) => setTimeout(resolve, 1000));
@@ -656,6 +690,30 @@ class StableBrowser {
656
690
  }
657
691
  }
658
692
  }
693
+ if (!scope) {
694
+ scope = this.page;
695
+ }
696
+ return scope;
697
+ }
698
+ async _getDocumentBody(selectors, timeout = 30000, info) {
699
+ let scope = await this._findFrameScope(selectors, timeout, info);
700
+ return scope.evaluate(() => {
701
+ var bodyContent = document.body.innerHTML;
702
+ return bodyContent;
703
+ });
704
+ }
705
+ async _locate_internal(selectors, info, _params, timeout = 30000) {
706
+ if (!info) {
707
+ info = {};
708
+ info.failCause = {};
709
+ info.log = "";
710
+ }
711
+ let highPriorityTimeout = 5000;
712
+ let visibleOnlyTimeout = 6000;
713
+ let startTime = performance.now();
714
+ let locatorsCount = 0;
715
+ //let arrayMode = Array.isArray(selectors);
716
+ let scope = await this._findFrameScope(selectors, timeout, info);
659
717
  let selectorsLocators = null;
660
718
  selectorsLocators = selectors.locators;
661
719
  // group selectors by priority
@@ -757,6 +815,8 @@ class StableBrowser {
757
815
  }
758
816
  this.logger.debug("unable to locate unique element, total elements found " + locatorsCount);
759
817
  info.log += "failed to locate unique element, total elements found " + locatorsCount + "\n";
818
+ info.failCause.locatorNotFound = true;
819
+ info.failCause.lastError = "failed to locate unique element";
760
820
  throw new Error("failed to locate first element no elements found, " + info.log);
761
821
  }
762
822
  async _scanLocatorsGroup(locatorsGroup, scope, _params, info, visibleOnly) {
@@ -788,89 +848,129 @@ class StableBrowser {
788
848
  });
789
849
  result.locatorIndex = i;
790
850
  }
851
+ if (foundLocators.length > 1) {
852
+ info.failCause.foundMultiple = true;
853
+ }
791
854
  }
792
855
  return result;
793
856
  }
794
- async click(selectors, _params, options = {}, world = null) {
795
- this._validateSelectors(selectors);
857
+ async simpleClick(elementDescription, _params, options = {}, world = null) {
796
858
  const startTime = Date.now();
797
- if (options && options.context) {
798
- selectors.locators[0].text = options.context;
859
+ let timeout = 30000;
860
+ if (options && options.timeout) {
861
+ timeout = options.timeout;
799
862
  }
800
- const info = {};
801
- info.log = "***** click on " + selectors.element_name + " *****\n";
802
- info.operation = "click";
803
- info.selectors = selectors;
804
- let error = null;
805
- let screenshotId = null;
806
- let screenshotPath = null;
863
+ while (true) {
864
+ try {
865
+ const result = await locate_element(this.context, elementDescription, "click");
866
+ if (result?.elementNumber >= 0) {
867
+ const selectors = {
868
+ frame: result?.frame,
869
+ locators: [
870
+ {
871
+ css: result?.css,
872
+ },
873
+ ],
874
+ };
875
+ await this.click(selectors, _params, options, world);
876
+ return;
877
+ }
878
+ }
879
+ catch (e) {
880
+ if (performance.now() - startTime > timeout) {
881
+ // throw e;
882
+ await _commandError({ text: "simpleClick", operation: "simpleClick", elementDescription, info: {} }, e, this);
883
+ }
884
+ }
885
+ await new Promise((resolve) => setTimeout(resolve, 3000));
886
+ }
887
+ }
888
+ async simpleClickType(elementDescription, value, _params, options = {}, world = null) {
889
+ const startTime = Date.now();
890
+ let timeout = 30000;
891
+ if (options && options.timeout) {
892
+ timeout = options.timeout;
893
+ }
894
+ while (true) {
895
+ try {
896
+ const result = await locate_element(this.context, elementDescription, "fill", value);
897
+ if (result?.elementNumber >= 0) {
898
+ const selectors = {
899
+ frame: result?.frame,
900
+ locators: [
901
+ {
902
+ css: result?.css,
903
+ },
904
+ ],
905
+ };
906
+ await this.clickType(selectors, value, false, _params, options, world);
907
+ return;
908
+ }
909
+ }
910
+ catch (e) {
911
+ if (performance.now() - startTime > timeout) {
912
+ // throw e;
913
+ await _commandError({ text: "simpleClickType", operation: "simpleClickType", value, elementDescription, info: {} }, e, this);
914
+ }
915
+ }
916
+ await new Promise((resolve) => setTimeout(resolve, 3000));
917
+ }
918
+ }
919
+ async click(selectors, _params, options = {}, world = null) {
920
+ const state = {
921
+ selectors,
922
+ _params,
923
+ options,
924
+ world,
925
+ text: "Click element",
926
+ type: Types.CLICK,
927
+ operation: "click",
928
+ log: "***** click on " + selectors.element_name + " *****\n",
929
+ };
807
930
  try {
808
- let element = await this._locate(selectors, info, _params);
809
- await this.scrollIfNeeded(element, info);
810
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
931
+ await _preCommand(state, this);
932
+ if (state.options && state.options.context) {
933
+ state.selectors.locators[0].text = state.options.context;
934
+ }
811
935
  try {
812
- await this._highlightElements(element);
813
- await element.click();
814
- await new Promise((resolve) => setTimeout(resolve, 1000));
936
+ await state.element.click();
937
+ // await new Promise((resolve) => setTimeout(resolve, 1000));
815
938
  }
816
939
  catch (e) {
817
940
  // await this.closeUnexpectedPopups();
818
- info.log += "click failed, will try again" + "\n";
819
- element = await this._locate(selectors, info, _params);
820
- await element.dispatchEvent("click");
821
- await new Promise((resolve) => setTimeout(resolve, 1000));
941
+ state.element = await this._locate(selectors, state.info, _params);
942
+ await state.element.dispatchEvent("click");
943
+ // await new Promise((resolve) => setTimeout(resolve, 1000));
822
944
  }
823
945
  await this.waitForPageLoad();
824
- return info;
946
+ return state.info;
825
947
  }
826
948
  catch (e) {
827
- this.logger.error("click failed " + info.log);
828
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
829
- info.screenshotPath = screenshotPath;
830
- Object.assign(e, { info: info });
831
- error = e;
832
- throw e;
949
+ await _commandError(state, e, this);
833
950
  }
834
951
  finally {
835
- const endTime = Date.now();
836
- this._reportToWorld(world, {
837
- element_name: selectors.element_name,
838
- type: Types.CLICK,
839
- text: `Click element`,
840
- screenshotId,
841
- result: error
842
- ? {
843
- status: "FAILED",
844
- startTime,
845
- endTime,
846
- message: error === null || error === void 0 ? void 0 : error.message,
847
- }
848
- : {
849
- status: "PASSED",
850
- startTime,
851
- endTime,
852
- },
853
- info: info,
854
- });
952
+ _commandFinally(state, this);
855
953
  }
856
954
  }
857
955
  async setCheck(selectors, checked = true, _params, options = {}, world = null) {
858
- this._validateSelectors(selectors);
859
- const startTime = Date.now();
860
- const info = {};
861
- info.log = "";
862
- info.operation = "setCheck";
863
- info.checked = checked;
864
- info.selectors = selectors;
865
- let error = null;
866
- let screenshotId = null;
867
- let screenshotPath = null;
956
+ const state = {
957
+ selectors,
958
+ _params,
959
+ options,
960
+ world,
961
+ type: checked ? Types.CHECK : Types.UNCHECK,
962
+ text: checked ? `Check element` : `Uncheck element`,
963
+ operation: "setCheck",
964
+ log: "***** check " + selectors.element_name + " *****\n",
965
+ };
868
966
  try {
869
- let element = await this._locate(selectors, info, _params);
870
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
967
+ await _preCommand(state, this);
968
+ state.info.checked = checked;
969
+ // let element = await this._locate(selectors, info, _params);
970
+ // ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
871
971
  try {
872
- await this._highlightElements(element);
873
- await element.setChecked(checked);
972
+ // await this._highlightElements(element);
973
+ await state.element.setChecked(checked);
874
974
  await new Promise((resolve) => setTimeout(resolve, 1000));
875
975
  }
876
976
  catch (e) {
@@ -879,179 +979,108 @@ class StableBrowser {
879
979
  }
880
980
  else {
881
981
  //await this.closeUnexpectedPopups();
882
- info.log += "setCheck failed, will try again" + "\n";
883
- element = await this._locate(selectors, info, _params);
884
- await element.setChecked(checked, { timeout: 5000, force: true });
982
+ state.info.log += "setCheck failed, will try again" + "\n";
983
+ state.element = await this._locate(selectors, state.info, _params);
984
+ await state.element.setChecked(checked, { timeout: 5000, force: true });
885
985
  await new Promise((resolve) => setTimeout(resolve, 1000));
886
986
  }
887
987
  }
888
988
  await this.waitForPageLoad();
889
- return info;
989
+ return state.info;
890
990
  }
891
991
  catch (e) {
892
- this.logger.error("setCheck failed " + info.log);
893
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
894
- info.screenshotPath = screenshotPath;
895
- Object.assign(e, { info: info });
896
- error = e;
897
- throw e;
992
+ await _commandError(state, e, this);
898
993
  }
899
994
  finally {
900
- const endTime = Date.now();
901
- this._reportToWorld(world, {
902
- element_name: selectors.element_name,
903
- type: checked ? Types.CHECK : Types.UNCHECK,
904
- text: checked ? `Check element` : `Uncheck element`,
905
- screenshotId,
906
- result: error
907
- ? {
908
- status: "FAILED",
909
- startTime,
910
- endTime,
911
- message: error === null || error === void 0 ? void 0 : error.message,
912
- }
913
- : {
914
- status: "PASSED",
915
- startTime,
916
- endTime,
917
- },
918
- info: info,
919
- });
995
+ _commandFinally(state, this);
920
996
  }
921
997
  }
922
998
  async hover(selectors, _params, options = {}, world = null) {
923
- this._validateSelectors(selectors);
924
- const startTime = Date.now();
925
- const info = {};
926
- info.log = "";
927
- info.operation = "hover";
928
- info.selectors = selectors;
929
- let error = null;
930
- let screenshotId = null;
931
- let screenshotPath = null;
999
+ const state = {
1000
+ selectors,
1001
+ _params,
1002
+ options,
1003
+ world,
1004
+ type: Types.HOVER,
1005
+ text: `Hover element`,
1006
+ operation: "hover",
1007
+ log: "***** hover " + selectors.element_name + " *****\n",
1008
+ };
932
1009
  try {
933
- let element = await this._locate(selectors, info, _params);
934
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1010
+ await _preCommand(state, this);
935
1011
  try {
936
- await this._highlightElements(element);
937
- await element.hover();
1012
+ await state.element.hover();
938
1013
  await new Promise((resolve) => setTimeout(resolve, 1000));
939
1014
  }
940
1015
  catch (e) {
941
1016
  //await this.closeUnexpectedPopups();
942
- info.log += "hover failed, will try again" + "\n";
943
- element = await this._locate(selectors, info, _params);
944
- await element.hover({ timeout: 10000 });
1017
+ state.info.log += "hover failed, will try again" + "\n";
1018
+ state.element = await this._locate(selectors, state.info, _params);
1019
+ await state.element.hover({ timeout: 10000 });
945
1020
  await new Promise((resolve) => setTimeout(resolve, 1000));
946
1021
  }
947
1022
  await this.waitForPageLoad();
948
- return info;
1023
+ return state.info;
949
1024
  }
950
1025
  catch (e) {
951
- this.logger.error("hover failed " + info.log);
952
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
953
- info.screenshotPath = screenshotPath;
954
- Object.assign(e, { info: info });
955
- error = e;
956
- throw e;
1026
+ await _commandError(state, e, this);
957
1027
  }
958
1028
  finally {
959
- const endTime = Date.now();
960
- this._reportToWorld(world, {
961
- element_name: selectors.element_name,
962
- type: Types.HOVER,
963
- text: `Hover element`,
964
- screenshotId,
965
- result: error
966
- ? {
967
- status: "FAILED",
968
- startTime,
969
- endTime,
970
- message: error === null || error === void 0 ? void 0 : error.message,
971
- }
972
- : {
973
- status: "PASSED",
974
- startTime,
975
- endTime,
976
- },
977
- info: info,
978
- });
1029
+ _commandFinally(state, this);
979
1030
  }
980
1031
  }
981
1032
  async selectOption(selectors, values, _params = null, options = {}, world = null) {
982
- this._validateSelectors(selectors);
983
1033
  if (!values) {
984
1034
  throw new Error("values is null");
985
1035
  }
986
- const startTime = Date.now();
987
- let error = null;
988
- let screenshotId = null;
989
- let screenshotPath = null;
990
- const info = {};
991
- info.log = "";
992
- info.operation = "selectOptions";
993
- info.selectors = selectors;
1036
+ const state = {
1037
+ selectors,
1038
+ _params,
1039
+ options,
1040
+ world,
1041
+ value: values.toString(),
1042
+ type: Types.SELECT,
1043
+ text: `Select option: ${values}`,
1044
+ operation: "selectOption",
1045
+ log: "***** select option " + selectors.element_name + " *****\n",
1046
+ };
994
1047
  try {
995
- let element = await this._locate(selectors, info, _params);
996
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1048
+ await _preCommand(state, this);
997
1049
  try {
998
- await this._highlightElements(element);
999
- await element.selectOption(values);
1050
+ await state.element.selectOption(values);
1000
1051
  }
1001
1052
  catch (e) {
1002
1053
  //await this.closeUnexpectedPopups();
1003
- info.log += "selectOption failed, will try force" + "\n";
1004
- await element.selectOption(values, { timeout: 10000, force: true });
1054
+ state.info.log += "selectOption failed, will try force" + "\n";
1055
+ await state.element.selectOption(values, { timeout: 10000, force: true });
1005
1056
  }
1006
1057
  await this.waitForPageLoad();
1007
- return info;
1058
+ return state.info;
1008
1059
  }
1009
1060
  catch (e) {
1010
- this.logger.error("selectOption failed " + info.log);
1011
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1012
- info.screenshotPath = screenshotPath;
1013
- Object.assign(e, { info: info });
1014
- this.logger.info("click failed, will try next selector");
1015
- error = e;
1016
- throw e;
1061
+ await _commandError(state, e, this);
1017
1062
  }
1018
1063
  finally {
1019
- const endTime = Date.now();
1020
- this._reportToWorld(world, {
1021
- element_name: selectors.element_name,
1022
- type: Types.SELECT,
1023
- text: `Select option: ${values}`,
1024
- value: values.toString(),
1025
- screenshotId,
1026
- result: error
1027
- ? {
1028
- status: "FAILED",
1029
- startTime,
1030
- endTime,
1031
- message: error === null || error === void 0 ? void 0 : error.message,
1032
- }
1033
- : {
1034
- status: "PASSED",
1035
- startTime,
1036
- endTime,
1037
- },
1038
- info: info,
1039
- });
1064
+ _commandFinally(state, this);
1040
1065
  }
1041
1066
  }
1042
1067
  async type(_value, _params = null, options = {}, world = null) {
1043
- const startTime = Date.now();
1044
- let error = null;
1045
- let screenshotId = null;
1046
- let screenshotPath = null;
1047
- const info = {};
1048
- info.log = "";
1049
- info.operation = "type";
1050
- _value = this._fixUsingParams(_value, _params);
1051
- info.value = _value;
1068
+ const state = {
1069
+ value: _value,
1070
+ _params,
1071
+ options,
1072
+ world,
1073
+ locate: false,
1074
+ scroll: false,
1075
+ highlight: false,
1076
+ type: Types.TYPE_PRESS,
1077
+ text: `Type value: ${_value}`,
1078
+ operation: "type",
1079
+ log: "",
1080
+ };
1052
1081
  try {
1053
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1054
- const valueSegment = _value.split("&&");
1082
+ await _preCommand(state, this);
1083
+ const valueSegment = state.value.split("&&");
1055
1084
  for (let i = 0; i < valueSegment.length; i++) {
1056
1085
  if (i > 0) {
1057
1086
  await new Promise((resolve) => setTimeout(resolve, 1000));
@@ -1071,134 +1100,76 @@ class StableBrowser {
1071
1100
  await this.page.keyboard.type(value);
1072
1101
  }
1073
1102
  }
1074
- return info;
1103
+ return state.info;
1075
1104
  }
1076
1105
  catch (e) {
1077
- //await this.closeUnexpectedPopups();
1078
- this.logger.error("type failed " + info.log);
1079
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1080
- info.screenshotPath = screenshotPath;
1081
- Object.assign(e, { info: info });
1082
- error = e;
1083
- throw e;
1106
+ await _commandError(state, e, this);
1084
1107
  }
1085
1108
  finally {
1086
- const endTime = Date.now();
1087
- this._reportToWorld(world, {
1088
- type: Types.TYPE_PRESS,
1089
- screenshotId,
1090
- value: _value,
1091
- text: `type value: ${_value}`,
1092
- result: error
1093
- ? {
1094
- status: "FAILED",
1095
- startTime,
1096
- endTime,
1097
- message: error === null || error === void 0 ? void 0 : error.message,
1098
- }
1099
- : {
1100
- status: "PASSED",
1101
- startTime,
1102
- endTime,
1103
- },
1104
- info: info,
1105
- });
1109
+ _commandFinally(state, this);
1106
1110
  }
1107
1111
  }
1108
1112
  async setInputValue(selectors, value, _params = null, options = {}, world = null) {
1109
- // set input value for non fillable inputs like date, time, range, color, etc.
1110
- this._validateSelectors(selectors);
1111
- const startTime = Date.now();
1112
- const info = {};
1113
- info.log = "***** set input value " + selectors.element_name + " *****\n";
1114
- info.operation = "setInputValue";
1115
- info.selectors = selectors;
1116
- value = this._fixUsingParams(value, _params);
1117
- info.value = value;
1118
- let error = null;
1119
- let screenshotId = null;
1120
- let screenshotPath = null;
1113
+ const state = {
1114
+ selectors,
1115
+ _params,
1116
+ value,
1117
+ options,
1118
+ world,
1119
+ type: Types.SET_INPUT,
1120
+ text: `Set input value`,
1121
+ operation: "setInputValue",
1122
+ log: "***** set input value " + selectors.element_name + " *****\n",
1123
+ };
1121
1124
  try {
1122
- value = await this._replaceWithLocalData(value, this);
1123
- let element = await this._locate(selectors, info, _params);
1124
- await this.scrollIfNeeded(element, info);
1125
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1126
- await this._highlightElements(element);
1125
+ await _preCommand(state, this);
1126
+ let value = await this._replaceWithLocalData(state.value, this);
1127
1127
  try {
1128
- await element.evaluateHandle((el, value) => {
1128
+ await state.element.evaluateHandle((el, value) => {
1129
1129
  el.value = value;
1130
1130
  }, value);
1131
1131
  }
1132
1132
  catch (error) {
1133
1133
  this.logger.error("setInputValue failed, will try again");
1134
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1135
- info.screenshotPath = screenshotPath;
1136
- Object.assign(error, { info: info });
1137
- await element.evaluateHandle((el, value) => {
1134
+ await _screenshot(state, this);
1135
+ Object.assign(error, { info: state.info });
1136
+ await state.element.evaluateHandle((el, value) => {
1138
1137
  el.value = value;
1139
1138
  });
1140
1139
  }
1141
1140
  }
1142
1141
  catch (e) {
1143
- this.logger.error("setInputValue failed " + info.log);
1144
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1145
- info.screenshotPath = screenshotPath;
1146
- Object.assign(e, { info: info });
1147
- error = e;
1148
- throw e;
1142
+ await _commandError(state, e, this);
1149
1143
  }
1150
1144
  finally {
1151
- const endTime = Date.now();
1152
- this._reportToWorld(world, {
1153
- element_name: selectors.element_name,
1154
- type: Types.SET_INPUT,
1155
- text: `Set input value`,
1156
- value: value,
1157
- screenshotId,
1158
- result: error
1159
- ? {
1160
- status: "FAILED",
1161
- startTime,
1162
- endTime,
1163
- message: error === null || error === void 0 ? void 0 : error.message,
1164
- }
1165
- : {
1166
- status: "PASSED",
1167
- startTime,
1168
- endTime,
1169
- },
1170
- info: info,
1171
- });
1145
+ _commandFinally(state, this);
1172
1146
  }
1173
1147
  }
1174
1148
  async setDateTime(selectors, value, format = null, enter = false, _params = null, options = {}, world = null) {
1175
- this._validateSelectors(selectors);
1176
- const startTime = Date.now();
1177
- let error = null;
1178
- let screenshotId = null;
1179
- let screenshotPath = null;
1180
- const info = {};
1181
- info.log = "";
1182
- info.operation = Types.SET_DATE_TIME;
1183
- info.selectors = selectors;
1184
- info.value = value;
1149
+ const state = {
1150
+ selectors,
1151
+ _params,
1152
+ value: await this._replaceWithLocalData(value, this),
1153
+ options,
1154
+ world,
1155
+ type: Types.SET_DATE_TIME,
1156
+ text: `Set date time value: ${value}`,
1157
+ operation: "setDateTime",
1158
+ log: "***** set date time value " + selectors.element_name + " *****\n",
1159
+ throwError: false,
1160
+ };
1185
1161
  try {
1186
- value = await this._replaceWithLocalData(value, this);
1187
- let element = await this._locate(selectors, info, _params);
1188
- //insert red border around the element
1189
- await this.scrollIfNeeded(element, info);
1190
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1191
- await this._highlightElements(element);
1162
+ await _preCommand(state, this);
1192
1163
  try {
1193
- await element.click();
1164
+ await state.element.click();
1194
1165
  await new Promise((resolve) => setTimeout(resolve, 500));
1195
1166
  if (format) {
1196
- value = dayjs(value).format(format);
1197
- await element.fill(value);
1167
+ state.value = dayjs(state.value).format(format);
1168
+ await state.element.fill(state.value);
1198
1169
  }
1199
1170
  else {
1200
- const dateTimeValue = await getDateTimeValue({ value, element });
1201
- await element.evaluateHandle((el, dateTimeValue) => {
1171
+ const dateTimeValue = await getDateTimeValue({ value: state.value, element: state.element });
1172
+ await state.element.evaluateHandle((el, dateTimeValue) => {
1202
1173
  el.value = ""; // clear input
1203
1174
  el.value = dateTimeValue;
1204
1175
  }, dateTimeValue);
@@ -1211,20 +1182,19 @@ class StableBrowser {
1211
1182
  }
1212
1183
  catch (err) {
1213
1184
  //await this.closeUnexpectedPopups();
1214
- this.logger.error("setting date time input failed " + JSON.stringify(info));
1185
+ this.logger.error("setting date time input failed " + JSON.stringify(state.info));
1215
1186
  this.logger.info("Trying again");
1216
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1217
- info.screenshotPath = screenshotPath;
1218
- Object.assign(err, { info: info });
1187
+ await _screenshot(state, this);
1188
+ Object.assign(err, { info: state.info });
1219
1189
  await element.click();
1220
1190
  await new Promise((resolve) => setTimeout(resolve, 500));
1221
1191
  if (format) {
1222
- value = dayjs(value).format(format);
1223
- await element.fill(value);
1192
+ state.value = dayjs(state.value).format(format);
1193
+ await state.element.fill(state.value);
1224
1194
  }
1225
1195
  else {
1226
- const dateTimeValue = await getDateTimeValue({ value, element });
1227
- await element.evaluateHandle((el, dateTimeValue) => {
1196
+ const dateTimeValue = await getDateTimeValue({ value: state.value, element: state.element });
1197
+ await state.element.evaluateHandle((el, dateTimeValue) => {
1228
1198
  el.value = ""; // clear input
1229
1199
  el.value = dateTimeValue;
1230
1200
  }, dateTimeValue);
@@ -1237,60 +1207,39 @@ class StableBrowser {
1237
1207
  }
1238
1208
  }
1239
1209
  catch (e) {
1240
- error = e;
1241
- throw e;
1210
+ await _commandError(state, e, this);
1242
1211
  }
1243
1212
  finally {
1244
- const endTime = Date.now();
1245
- this._reportToWorld(world, {
1246
- element_name: selectors.element_name,
1247
- type: Types.SET_DATE_TIME,
1248
- screenshotId,
1249
- value: value,
1250
- text: `setDateTime input with value: ${value}`,
1251
- result: error
1252
- ? {
1253
- status: "FAILED",
1254
- startTime,
1255
- endTime,
1256
- message: error === null || error === void 0 ? void 0 : error.message,
1257
- }
1258
- : {
1259
- status: "PASSED",
1260
- startTime,
1261
- endTime,
1262
- },
1263
- info: info,
1264
- });
1213
+ _commandFinally(state, this);
1265
1214
  }
1266
1215
  }
1267
1216
  async clickType(selectors, _value, enter = false, _params = null, options = {}, world = null) {
1268
1217
  _value = unEscapeString(_value);
1269
- this._validateSelectors(selectors);
1270
- const startTime = Date.now();
1271
- let error = null;
1272
- let screenshotId = null;
1273
- let screenshotPath = null;
1274
- const info = {};
1275
- info.log = "***** clickType on " + selectors.element_name + " with value " + _value + "*****\n";
1276
- info.operation = "clickType";
1277
- info.selectors = selectors;
1278
1218
  const newValue = await this._replaceWithLocalData(_value, world);
1219
+ const state = {
1220
+ selectors,
1221
+ _params,
1222
+ value: newValue,
1223
+ originalValue: _value,
1224
+ options,
1225
+ world,
1226
+ type: Types.FILL,
1227
+ text: `Click type input with value: ${_value}`,
1228
+ operation: "clickType",
1229
+ log: "***** clickType on " + selectors.element_name + " with value " + maskValue(_value) + "*****\n",
1230
+ };
1279
1231
  if (newValue !== _value) {
1280
1232
  //this.logger.info(_value + "=" + newValue);
1281
1233
  _value = newValue;
1282
1234
  }
1283
- info.value = _value;
1284
1235
  try {
1285
- let element = await this._locate(selectors, info, _params);
1286
- //insert red border around the element
1287
- await this.scrollIfNeeded(element, info);
1288
- await this._highlightElements(element);
1236
+ await _preCommand(state, this);
1237
+ state.info.value = _value;
1289
1238
  if (options === null || options === undefined || !options.press) {
1290
1239
  try {
1291
- let currentValue = await element.inputValue();
1240
+ let currentValue = await state.element.inputValue();
1292
1241
  if (currentValue) {
1293
- await element.fill("");
1242
+ await state.element.fill("");
1294
1243
  }
1295
1244
  }
1296
1245
  catch (e) {
@@ -1299,22 +1248,22 @@ class StableBrowser {
1299
1248
  }
1300
1249
  if (options === null || options === undefined || options.press) {
1301
1250
  try {
1302
- await element.click({ timeout: 5000 });
1251
+ await state.element.click({ timeout: 5000 });
1303
1252
  }
1304
1253
  catch (e) {
1305
- await element.dispatchEvent("click");
1254
+ await state.element.dispatchEvent("click");
1306
1255
  }
1307
1256
  }
1308
1257
  else {
1309
1258
  try {
1310
- await element.focus();
1259
+ await state.element.focus();
1311
1260
  }
1312
1261
  catch (e) {
1313
- await element.dispatchEvent("focus");
1262
+ await state.element.dispatchEvent("focus");
1314
1263
  }
1315
1264
  }
1316
1265
  await new Promise((resolve) => setTimeout(resolve, 500));
1317
- const valueSegment = _value.split("&&");
1266
+ const valueSegment = state.value.split("&&");
1318
1267
  for (let i = 0; i < valueSegment.length; i++) {
1319
1268
  if (i > 0) {
1320
1269
  await new Promise((resolve) => setTimeout(resolve, 1000));
@@ -1334,14 +1283,14 @@ class StableBrowser {
1334
1283
  await new Promise((resolve) => setTimeout(resolve, 500));
1335
1284
  }
1336
1285
  }
1337
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1286
+ await _screenshot(state, this);
1338
1287
  if (enter === true) {
1339
1288
  await new Promise((resolve) => setTimeout(resolve, 2000));
1340
1289
  await this.page.keyboard.press("Enter");
1341
1290
  await this.waitForPageLoad();
1342
1291
  }
1343
1292
  else if (enter === false) {
1344
- await element.dispatchEvent("change");
1293
+ await state.element.dispatchEvent("change");
1345
1294
  //await this.page.keyboard.press("Tab");
1346
1295
  }
1347
1296
  else {
@@ -1350,104 +1299,50 @@ class StableBrowser {
1350
1299
  await this.waitForPageLoad();
1351
1300
  }
1352
1301
  }
1353
- return info;
1302
+ return state.info;
1354
1303
  }
1355
1304
  catch (e) {
1356
- //await this.closeUnexpectedPopups();
1357
- this.logger.error("fill failed " + JSON.stringify(info));
1358
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1359
- info.screenshotPath = screenshotPath;
1360
- Object.assign(e, { info: info });
1361
- error = e;
1362
- throw e;
1305
+ await _commandError(state, e, this);
1363
1306
  }
1364
1307
  finally {
1365
- const endTime = Date.now();
1366
- this._reportToWorld(world, {
1367
- element_name: selectors.element_name,
1368
- type: Types.FILL,
1369
- screenshotId,
1370
- value: _value,
1371
- text: `clickType input with value: ${_value}`,
1372
- result: error
1373
- ? {
1374
- status: "FAILED",
1375
- startTime,
1376
- endTime,
1377
- message: error === null || error === void 0 ? void 0 : error.message,
1378
- }
1379
- : {
1380
- status: "PASSED",
1381
- startTime,
1382
- endTime,
1383
- },
1384
- info: info,
1385
- });
1308
+ _commandFinally(state, this);
1386
1309
  }
1387
1310
  }
1388
1311
  async fill(selectors, value, enter = false, _params = null, options = {}, world = null) {
1389
- this._validateSelectors(selectors);
1390
- value = unEscapeString(value);
1391
- const startTime = Date.now();
1392
- let error = null;
1393
- let screenshotId = null;
1394
- let screenshotPath = null;
1395
- const info = {};
1396
- info.log = "***** fill on " + selectors.element_name + " with value " + value + "*****\n";
1397
- info.operation = "fill";
1398
- info.selectors = selectors;
1399
- info.value = value;
1312
+ const state = {
1313
+ selectors,
1314
+ _params,
1315
+ value: unEscapeString(value),
1316
+ options,
1317
+ world,
1318
+ type: Types.FILL,
1319
+ text: `Fill input with value: ${value}`,
1320
+ operation: "fill",
1321
+ log: "***** fill on " + selectors.element_name + " with value " + value + "*****\n",
1322
+ };
1400
1323
  try {
1401
- let element = await this._locate(selectors, info, _params);
1402
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1403
- await this._highlightElements(element);
1404
- await element.fill(value);
1405
- await element.dispatchEvent("change");
1324
+ await _preCommand(state, this);
1325
+ await state.element.fill(value);
1326
+ await state.element.dispatchEvent("change");
1406
1327
  if (enter) {
1407
1328
  await new Promise((resolve) => setTimeout(resolve, 2000));
1408
1329
  await this.page.keyboard.press("Enter");
1409
1330
  }
1410
1331
  await this.waitForPageLoad();
1411
- return info;
1332
+ return state.info;
1412
1333
  }
1413
- catch (e) {
1414
- //await this.closeUnexpectedPopups();
1415
- this.logger.error("fill failed " + info.log);
1416
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1417
- info.screenshotPath = screenshotPath;
1418
- Object.assign(e, { info: info });
1419
- error = e;
1420
- throw e;
1334
+ catch (e) {
1335
+ await _commandError(state, e, this);
1421
1336
  }
1422
1337
  finally {
1423
- const endTime = Date.now();
1424
- this._reportToWorld(world, {
1425
- element_name: selectors.element_name,
1426
- type: Types.FILL,
1427
- screenshotId,
1428
- value,
1429
- text: `Fill input with value: ${value}`,
1430
- result: error
1431
- ? {
1432
- status: "FAILED",
1433
- startTime,
1434
- endTime,
1435
- message: error === null || error === void 0 ? void 0 : error.message,
1436
- }
1437
- : {
1438
- status: "PASSED",
1439
- startTime,
1440
- endTime,
1441
- },
1442
- info: info,
1443
- });
1338
+ _commandFinally(state, this);
1444
1339
  }
1445
1340
  }
1446
1341
  async getText(selectors, _params = null, options = {}, info = {}, world = null) {
1447
1342
  return await this._getText(selectors, 0, _params, options, info, world);
1448
1343
  }
1449
1344
  async _getText(selectors, climb, _params = null, options = {}, info = {}, world = null) {
1450
- this._validateSelectors(selectors);
1345
+ _validateSelectors(selectors);
1451
1346
  let screenshotId = null;
1452
1347
  let screenshotPath = null;
1453
1348
  if (!info.log) {
@@ -1491,166 +1386,124 @@ class StableBrowser {
1491
1386
  }
1492
1387
  }
1493
1388
  async containsPattern(selectors, pattern, text, _params = null, options = {}, world = null) {
1494
- var _a;
1495
- this._validateSelectors(selectors);
1496
1389
  if (!pattern) {
1497
1390
  throw new Error("pattern is null");
1498
1391
  }
1499
1392
  if (!text) {
1500
1393
  throw new Error("text is null");
1501
1394
  }
1395
+ const state = {
1396
+ selectors,
1397
+ _params,
1398
+ pattern,
1399
+ value: pattern,
1400
+ options,
1401
+ world,
1402
+ locate: false,
1403
+ scroll: false,
1404
+ screenshot: false,
1405
+ highlight: false,
1406
+ type: Types.VERIFY_ELEMENT_CONTAINS_TEXT,
1407
+ text: `Verify element contains pattern: ${pattern}`,
1408
+ operation: "containsPattern",
1409
+ log: "***** verify element " + selectors.element_name + " contains pattern " + pattern + " *****\n",
1410
+ };
1502
1411
  const newValue = await this._replaceWithLocalData(text, world);
1503
1412
  if (newValue !== text) {
1504
1413
  this.logger.info(text + "=" + newValue);
1505
1414
  text = newValue;
1506
1415
  }
1507
- const startTime = Date.now();
1508
- let error = null;
1509
- let screenshotId = null;
1510
- let screenshotPath = null;
1511
- const info = {};
1512
- info.log =
1513
- "***** verify element " + selectors.element_name + " contains pattern " + pattern + "/" + text + " *****\n";
1514
- info.operation = "containsPattern";
1515
- info.selectors = selectors;
1516
- info.value = text;
1517
- info.pattern = pattern;
1518
1416
  let foundObj = null;
1519
1417
  try {
1520
- foundObj = await this._getText(selectors, 0, _params, options, info, world);
1418
+ await _preCommand(state, this);
1419
+ state.info.pattern = pattern;
1420
+ foundObj = await this._getText(selectors, 0, _params, options, state.info, world);
1521
1421
  if (foundObj && foundObj.element) {
1522
- await this.scrollIfNeeded(foundObj.element, info);
1422
+ await this.scrollIfNeeded(foundObj.element, state.info);
1523
1423
  }
1524
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1424
+ await _screenshot(state, this);
1525
1425
  let escapedText = text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
1526
1426
  pattern = pattern.replace("{text}", escapedText);
1527
1427
  let regex = new RegExp(pattern, "im");
1528
- if (!regex.test(foundObj === null || foundObj === void 0 ? void 0 : foundObj.text) && !((_a = foundObj === null || foundObj === void 0 ? void 0 : foundObj.value) === null || _a === void 0 ? void 0 : _a.includes(text))) {
1529
- info.foundText = foundObj === null || foundObj === void 0 ? void 0 : foundObj.text;
1428
+ if (!regex.test(foundObj?.text) && !foundObj?.value?.includes(text)) {
1429
+ state.info.foundText = foundObj?.text;
1530
1430
  throw new Error("element doesn't contain text " + text);
1531
1431
  }
1532
- return info;
1432
+ return state.info;
1533
1433
  }
1534
1434
  catch (e) {
1535
- //await this.closeUnexpectedPopups();
1536
- this.logger.error("verify element contains text failed " + info.log);
1537
- this.logger.error("found text " + (foundObj === null || foundObj === void 0 ? void 0 : foundObj.text) + " pattern " + pattern);
1538
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1539
- info.screenshotPath = screenshotPath;
1540
- Object.assign(e, { info: info });
1541
- error = e;
1542
- throw e;
1435
+ this.logger.error("found text " + foundObj?.text + " pattern " + pattern);
1436
+ await _commandError(state, e, this);
1543
1437
  }
1544
1438
  finally {
1545
- const endTime = Date.now();
1546
- this._reportToWorld(world, {
1547
- element_name: selectors.element_name,
1548
- type: Types.VERIFY_ELEMENT_CONTAINS_TEXT,
1549
- value: pattern,
1550
- text: `Verify element contains pattern: ${pattern}`,
1551
- screenshotId: foundObj === null || foundObj === void 0 ? void 0 : foundObj.screenshotId,
1552
- result: error
1553
- ? {
1554
- status: "FAILED",
1555
- startTime,
1556
- endTime,
1557
- message: error === null || error === void 0 ? void 0 : error.message,
1558
- }
1559
- : {
1560
- status: "PASSED",
1561
- startTime,
1562
- endTime,
1563
- },
1564
- info: info,
1565
- });
1439
+ _commandFinally(state, this);
1566
1440
  }
1567
1441
  }
1568
1442
  async containsText(selectors, text, climb, _params = null, options = {}, world = null) {
1569
- var _a, _b, _c;
1570
- this._validateSelectors(selectors);
1571
- text = unEscapeString(text);
1443
+ const state = {
1444
+ selectors,
1445
+ _params,
1446
+ value: text,
1447
+ options,
1448
+ world,
1449
+ locate: false,
1450
+ scroll: false,
1451
+ screenshot: false,
1452
+ highlight: false,
1453
+ type: Types.VERIFY_ELEMENT_CONTAINS_TEXT,
1454
+ text: `Verify element contains text: ${text}`,
1455
+ operation: "containsText",
1456
+ log: "***** verify element " + selectors.element_name + " contains text " + text + " *****\n",
1457
+ };
1572
1458
  if (!text) {
1573
1459
  throw new Error("text is null");
1574
1460
  }
1575
- const startTime = Date.now();
1576
- let error = null;
1577
- let screenshotId = null;
1578
- let screenshotPath = null;
1579
- const info = {};
1580
- info.log = "***** verify element " + selectors.element_name + " contains text " + text + " *****\n";
1581
- info.operation = "containsText";
1582
- info.selectors = selectors;
1461
+ text = unEscapeString(text);
1583
1462
  const newValue = await this._replaceWithLocalData(text, world);
1584
1463
  if (newValue !== text) {
1585
1464
  this.logger.info(text + "=" + newValue);
1586
1465
  text = newValue;
1587
1466
  }
1588
- info.value = text;
1589
1467
  let foundObj = null;
1590
1468
  try {
1591
- foundObj = await this._getText(selectors, climb, _params, options, info, world);
1469
+ await _preCommand(state, this);
1470
+ foundObj = await this._getText(selectors, climb, _params, options, state.info, world);
1592
1471
  if (foundObj && foundObj.element) {
1593
- await this.scrollIfNeeded(foundObj.element, info);
1472
+ await this.scrollIfNeeded(foundObj.element, state.info);
1594
1473
  }
1595
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1474
+ await _screenshot(state, this);
1596
1475
  const dateAlternatives = findDateAlternatives(text);
1597
1476
  const numberAlternatives = findNumberAlternatives(text);
1598
1477
  if (dateAlternatives.date) {
1599
1478
  for (let i = 0; i < dateAlternatives.dates.length; i++) {
1600
- if ((foundObj === null || foundObj === void 0 ? void 0 : foundObj.text.includes(dateAlternatives.dates[i])) ||
1601
- ((_a = foundObj === null || foundObj === void 0 ? void 0 : foundObj.value) === null || _a === void 0 ? void 0 : _a.includes(dateAlternatives.dates[i]))) {
1602
- return info;
1479
+ if (foundObj?.text.includes(dateAlternatives.dates[i]) ||
1480
+ foundObj?.value?.includes(dateAlternatives.dates[i])) {
1481
+ return state.info;
1603
1482
  }
1604
1483
  }
1605
1484
  throw new Error("element doesn't contain text " + text);
1606
1485
  }
1607
1486
  else if (numberAlternatives.number) {
1608
1487
  for (let i = 0; i < numberAlternatives.numbers.length; i++) {
1609
- if ((foundObj === null || foundObj === void 0 ? void 0 : foundObj.text.includes(numberAlternatives.numbers[i])) ||
1610
- ((_b = foundObj === null || foundObj === void 0 ? void 0 : foundObj.value) === null || _b === void 0 ? void 0 : _b.includes(numberAlternatives.numbers[i]))) {
1611
- return info;
1488
+ if (foundObj?.text.includes(numberAlternatives.numbers[i]) ||
1489
+ foundObj?.value?.includes(numberAlternatives.numbers[i])) {
1490
+ return state.info;
1612
1491
  }
1613
1492
  }
1614
1493
  throw new Error("element doesn't contain text " + text);
1615
1494
  }
1616
- else if (!(foundObj === null || foundObj === void 0 ? void 0 : foundObj.text.includes(text)) && !((_c = foundObj === null || foundObj === void 0 ? void 0 : foundObj.value) === null || _c === void 0 ? void 0 : _c.includes(text))) {
1617
- info.foundText = foundObj === null || foundObj === void 0 ? void 0 : foundObj.text;
1618
- info.value = foundObj === null || foundObj === void 0 ? void 0 : foundObj.value;
1495
+ else if (!foundObj?.text.includes(text) && !foundObj?.value?.includes(text)) {
1496
+ state.info.foundText = foundObj?.text;
1497
+ state.info.value = foundObj?.value;
1619
1498
  throw new Error("element doesn't contain text " + text);
1620
1499
  }
1621
- return info;
1500
+ return state.info;
1622
1501
  }
1623
1502
  catch (e) {
1624
- //await this.closeUnexpectedPopups();
1625
- this.logger.error("verify element contains text failed " + info.log);
1626
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1627
- info.screenshotPath = screenshotPath;
1628
- Object.assign(e, { info: info });
1629
- error = e;
1630
- throw e;
1503
+ await _commandError(state, e, this);
1631
1504
  }
1632
1505
  finally {
1633
- const endTime = Date.now();
1634
- this._reportToWorld(world, {
1635
- element_name: selectors.element_name,
1636
- type: Types.VERIFY_ELEMENT_CONTAINS_TEXT,
1637
- text: `Verify element contains text: ${text}`,
1638
- value: text,
1639
- screenshotId: foundObj === null || foundObj === void 0 ? void 0 : foundObj.screenshotId,
1640
- result: error
1641
- ? {
1642
- status: "FAILED",
1643
- startTime,
1644
- endTime,
1645
- message: error === null || error === void 0 ? void 0 : error.message,
1646
- }
1647
- : {
1648
- status: "PASSED",
1649
- startTime,
1650
- endTime,
1651
- },
1652
- info: info,
1653
- });
1506
+ _commandFinally(state, this);
1654
1507
  }
1655
1508
  }
1656
1509
  _getDataFile(world = null) {
@@ -1924,127 +1777,69 @@ class StableBrowser {
1924
1777
  }
1925
1778
  }
1926
1779
  async verifyElementExistInPage(selectors, _params = null, options = {}, world = null) {
1927
- this._validateSelectors(selectors);
1928
- const startTime = Date.now();
1929
- let error = null;
1930
- let screenshotId = null;
1931
- let screenshotPath = null;
1780
+ const state = {
1781
+ selectors,
1782
+ _params,
1783
+ options,
1784
+ world,
1785
+ type: Types.VERIFY_ELEMENT_CONTAINS_TEXT,
1786
+ text: `Verify element exists in page`,
1787
+ operation: "verifyElementExistInPage",
1788
+ log: "***** verify element " + selectors.element_name + " exists in page *****\n",
1789
+ };
1932
1790
  await new Promise((resolve) => setTimeout(resolve, 2000));
1933
- const info = {};
1934
- info.log = "***** verify element " + selectors.element_name + " exists in page *****\n";
1935
- info.operation = "verify";
1936
- info.selectors = selectors;
1937
1791
  try {
1938
- const element = await this._locate(selectors, info, _params);
1939
- if (element) {
1940
- await this.scrollIfNeeded(element, info);
1941
- }
1942
- await this._highlightElements(element);
1943
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1944
- await expect(element).toHaveCount(1, { timeout: 10000 });
1945
- return info;
1792
+ await _preCommand(state, this);
1793
+ await expect(state.element).toHaveCount(1, { timeout: 10000 });
1794
+ return state.info;
1946
1795
  }
1947
1796
  catch (e) {
1948
- //await this.closeUnexpectedPopups();
1949
- this.logger.error("verify failed " + info.log);
1950
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1951
- info.screenshotPath = screenshotPath;
1952
- Object.assign(e, { info: info });
1953
- error = e;
1954
- throw e;
1797
+ await _commandError(state, e, this);
1955
1798
  }
1956
1799
  finally {
1957
- const endTime = Date.now();
1958
- this._reportToWorld(world, {
1959
- element_name: selectors.element_name,
1960
- type: Types.VERIFY_ELEMENT_CONTAINS_TEXT,
1961
- text: "Verify element exists in page",
1962
- screenshotId,
1963
- result: error
1964
- ? {
1965
- status: "FAILED",
1966
- startTime,
1967
- endTime,
1968
- message: error === null || error === void 0 ? void 0 : error.message,
1969
- }
1970
- : {
1971
- status: "PASSED",
1972
- startTime,
1973
- endTime,
1974
- },
1975
- info: info,
1976
- });
1800
+ _commandFinally(state, this);
1977
1801
  }
1978
1802
  }
1979
1803
  async extractAttribute(selectors, attribute, variable, _params = null, options = {}, world = null) {
1980
- this._validateSelectors(selectors);
1981
- const startTime = Date.now();
1982
- let error = null;
1983
- let screenshotId = null;
1984
- let screenshotPath = null;
1804
+ const state = {
1805
+ selectors,
1806
+ _params,
1807
+ attribute,
1808
+ variable,
1809
+ options,
1810
+ world,
1811
+ type: Types.EXTRACT,
1812
+ text: `Extract attribute from element`,
1813
+ operation: "extractAttribute",
1814
+ log: "***** extract attribute " + attribute + " from " + selectors.element_name + " *****\n",
1815
+ };
1985
1816
  await new Promise((resolve) => setTimeout(resolve, 2000));
1986
- const info = {};
1987
- info.log = "***** extract attribute " + attribute + " from " + selectors.element_name + " *****\n";
1988
- info.operation = "extract";
1989
- info.selectors = selectors;
1990
1817
  try {
1991
- const element = await this._locate(selectors, info, _params);
1992
- await this._highlightElements(element);
1993
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1818
+ await _preCommand(state, this);
1994
1819
  switch (attribute) {
1995
1820
  case "inner_text":
1996
- info.value = await element.innerText();
1821
+ state.value = await state.element.innerText();
1997
1822
  break;
1998
1823
  case "href":
1999
- info.value = await element.getAttribute("href");
1824
+ state.value = await state.element.getAttribute("href");
2000
1825
  break;
2001
1826
  case "value":
2002
- info.value = await element.inputValue();
1827
+ state.value = await state.element.inputValue();
2003
1828
  break;
2004
1829
  default:
2005
- info.value = await element.getAttribute(attribute);
1830
+ state.value = await state.element.getAttribute(attribute);
2006
1831
  break;
2007
1832
  }
2008
- this[variable] = info.value;
2009
- if (world) {
2010
- world[variable] = info.value;
2011
- }
2012
- this.setTestData({ [variable]: info.value }, world);
2013
- this.logger.info("set test data: " + variable + "=" + info.value);
2014
- return info;
1833
+ state.info.value = state.value;
1834
+ this.setTestData({ [variable]: state.value }, world);
1835
+ this.logger.info("set test data: " + variable + "=" + state.value);
1836
+ return state.info;
2015
1837
  }
2016
1838
  catch (e) {
2017
- //await this.closeUnexpectedPopups();
2018
- this.logger.error("extract failed " + info.log);
2019
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
2020
- info.screenshotPath = screenshotPath;
2021
- Object.assign(e, { info: info });
2022
- error = e;
2023
- throw e;
1839
+ await _commandError(state, e, this);
2024
1840
  }
2025
1841
  finally {
2026
- const endTime = Date.now();
2027
- this._reportToWorld(world, {
2028
- element_name: selectors.element_name,
2029
- type: Types.EXTRACT_ATTRIBUTE,
2030
- variable: variable,
2031
- value: info.value,
2032
- text: "Extract attribute from element",
2033
- screenshotId,
2034
- result: error
2035
- ? {
2036
- status: "FAILED",
2037
- startTime,
2038
- endTime,
2039
- message: error === null || error === void 0 ? void 0 : error.message,
2040
- }
2041
- : {
2042
- status: "PASSED",
2043
- startTime,
2044
- endTime,
2045
- },
2046
- info: info,
2047
- });
1842
+ _commandFinally(state, this);
2048
1843
  }
2049
1844
  }
2050
1845
  async extractEmailData(emailAddress, options, world) {
@@ -2121,7 +1916,8 @@ class StableBrowser {
2121
1916
  catch (e) {
2122
1917
  errorCount++;
2123
1918
  if (errorCount > 3) {
2124
- throw e;
1919
+ // throw e;
1920
+ await _commandError({ text: "extractEmailData", operation: "extractEmailData", emailAddress, info: {} }, e, this);
2125
1921
  }
2126
1922
  // ignore
2127
1923
  }
@@ -2232,11 +2028,12 @@ class StableBrowser {
2232
2028
  info.screenshotPath = screenshotPath;
2233
2029
  Object.assign(e, { info: info });
2234
2030
  error = e;
2235
- throw e;
2031
+ // throw e;
2032
+ await _commandError({ text: "verifyPagePath", operation: "verifyPagePath", pathPart, info }, e, this);
2236
2033
  }
2237
2034
  finally {
2238
2035
  const endTime = Date.now();
2239
- this._reportToWorld(world, {
2036
+ _reportToWorld(world, {
2240
2037
  type: Types.VERIFY_PAGE_PATH,
2241
2038
  text: "Verify page path",
2242
2039
  screenshotId,
@@ -2245,7 +2042,7 @@ class StableBrowser {
2245
2042
  status: "FAILED",
2246
2043
  startTime,
2247
2044
  endTime,
2248
- message: error === null || error === void 0 ? void 0 : error.message,
2045
+ message: error?.message,
2249
2046
  }
2250
2047
  : {
2251
2048
  status: "PASSED",
@@ -2258,52 +2055,58 @@ class StableBrowser {
2258
2055
  }
2259
2056
  async verifyTextExistInPage(text, options = {}, world = null) {
2260
2057
  text = unEscapeString(text);
2261
- const startTime = Date.now();
2058
+ const state = {
2059
+ text_search: text,
2060
+ options,
2061
+ world,
2062
+ locate: false,
2063
+ scroll: false,
2064
+ highlight: false,
2065
+ type: Types.VERIFY_ELEMENT_CONTAINS_TEXT,
2066
+ text: `Verify text exists in page`,
2067
+ operation: "verifyTextExistInPage",
2068
+ log: "***** verify text " + text + " exists in page *****\n",
2069
+ };
2262
2070
  const timeout = this._getLoadTimeout(options);
2263
- let error = null;
2264
- let screenshotId = null;
2265
- let screenshotPath = null;
2266
2071
  await new Promise((resolve) => setTimeout(resolve, 2000));
2267
- const info = {};
2268
- info.log = "***** verify text " + text + " exists in page *****\n";
2269
- info.operation = "verifyTextExistInPage";
2270
2072
  const newValue = await this._replaceWithLocalData(text, world);
2271
2073
  if (newValue !== text) {
2272
2074
  this.logger.info(text + "=" + newValue);
2273
2075
  text = newValue;
2274
2076
  }
2275
- info.text = text;
2276
2077
  let dateAlternatives = findDateAlternatives(text);
2277
2078
  let numberAlternatives = findNumberAlternatives(text);
2278
2079
  try {
2080
+ await _preCommand(state, this);
2081
+ state.info.text = text;
2279
2082
  while (true) {
2280
2083
  const frames = this.page.frames();
2281
2084
  let results = [];
2282
2085
  for (let i = 0; i < frames.length; i++) {
2283
2086
  if (dateAlternatives.date) {
2284
2087
  for (let j = 0; j < dateAlternatives.dates.length; j++) {
2285
- const result = await this._locateElementByText(frames[i], dateAlternatives.dates[j], "*", true, {});
2088
+ const result = await this._locateElementByText(frames[i], dateAlternatives.dates[j], "*:not(script, style, head)", true, true, {});
2286
2089
  result.frame = frames[i];
2287
2090
  results.push(result);
2288
2091
  }
2289
2092
  }
2290
2093
  else if (numberAlternatives.number) {
2291
2094
  for (let j = 0; j < numberAlternatives.numbers.length; j++) {
2292
- const result = await this._locateElementByText(frames[i], numberAlternatives.numbers[j], "*", true, {});
2095
+ const result = await this._locateElementByText(frames[i], numberAlternatives.numbers[j], "*:not(script, style, head)", true, true, {});
2293
2096
  result.frame = frames[i];
2294
2097
  results.push(result);
2295
2098
  }
2296
2099
  }
2297
2100
  else {
2298
- const result = await this._locateElementByText(frames[i], text, "*", true, {});
2101
+ const result = await this._locateElementByText(frames[i], text, "*:not(script, style, head)", true, true, {});
2299
2102
  result.frame = frames[i];
2300
2103
  results.push(result);
2301
2104
  }
2302
2105
  }
2303
- info.results = results;
2106
+ state.info.results = results;
2304
2107
  const resultWithElementsFound = results.filter((result) => result.elementCount > 0);
2305
2108
  if (resultWithElementsFound.length === 0) {
2306
- if (Date.now() - startTime > timeout) {
2109
+ if (Date.now() - state.startTime > timeout) {
2307
2110
  throw new Error(`Text ${text} not found in page`);
2308
2111
  }
2309
2112
  await new Promise((resolve) => setTimeout(resolve, 1000));
@@ -2315,44 +2118,89 @@ class StableBrowser {
2315
2118
  await this._highlightElements(frame, dataAttribute);
2316
2119
  const element = await frame.$(dataAttribute);
2317
2120
  if (element) {
2318
- await this.scrollIfNeeded(element, info);
2121
+ await this.scrollIfNeeded(element, state.info);
2319
2122
  await element.dispatchEvent("bvt_verify_page_contains_text");
2320
2123
  }
2321
2124
  }
2322
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
2323
- return info;
2125
+ await _screenshot(state, this);
2126
+ return state.info;
2324
2127
  }
2325
2128
  // await expect(element).toHaveCount(1, { timeout: 10000 });
2326
2129
  }
2327
2130
  catch (e) {
2328
- //await this.closeUnexpectedPopups();
2329
- this.logger.error("verify text exist in page failed " + info.log);
2330
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
2331
- info.screenshotPath = screenshotPath;
2332
- Object.assign(e, { info: info });
2333
- error = e;
2334
- throw e;
2131
+ await _commandError(state, e, this);
2335
2132
  }
2336
2133
  finally {
2337
- const endTime = Date.now();
2338
- this._reportToWorld(world, {
2339
- type: Types.VERIFY_ELEMENT_CONTAINS_TEXT,
2340
- text: "Verify text exists in page",
2341
- screenshotId,
2342
- result: error
2343
- ? {
2344
- status: "FAILED",
2345
- startTime,
2346
- endTime,
2347
- message: error === null || error === void 0 ? void 0 : error.message,
2134
+ _commandFinally(state, this);
2135
+ }
2136
+ }
2137
+ async waitForTextToDisappear(text, options = {}, world = null) {
2138
+ text = unEscapeString(text);
2139
+ const state = {
2140
+ text_search: text,
2141
+ options,
2142
+ world,
2143
+ locate: false,
2144
+ scroll: false,
2145
+ highlight: false,
2146
+ type: Types.WAIT_FOR_TEXT_TO_DISAPPEAR,
2147
+ text: `Verify text does not exist in page`,
2148
+ operation: "verifyTextNotExistInPage",
2149
+ log: "***** verify text " + text + " does not exist in page *****\n",
2150
+ };
2151
+ const timeout = this._getLoadTimeout(options);
2152
+ await new Promise((resolve) => setTimeout(resolve, 2000));
2153
+ const newValue = await this._replaceWithLocalData(text, world);
2154
+ if (newValue !== text) {
2155
+ this.logger.info(text + "=" + newValue);
2156
+ text = newValue;
2157
+ }
2158
+ let dateAlternatives = findDateAlternatives(text);
2159
+ let numberAlternatives = findNumberAlternatives(text);
2160
+ try {
2161
+ await _preCommand(state, this);
2162
+ state.info.text = text;
2163
+ while (true) {
2164
+ const frames = this.page.frames();
2165
+ let results = [];
2166
+ for (let i = 0; i < frames.length; i++) {
2167
+ if (dateAlternatives.date) {
2168
+ for (let j = 0; j < dateAlternatives.dates.length; j++) {
2169
+ const result = await this._locateElementByText(frames[i], dateAlternatives.dates[j], "*:not(script, style, head)", true, true, {});
2170
+ result.frame = frames[i];
2171
+ results.push(result);
2172
+ }
2348
2173
  }
2349
- : {
2350
- status: "PASSED",
2351
- startTime,
2352
- endTime,
2353
- },
2354
- info: info,
2355
- });
2174
+ else if (numberAlternatives.number) {
2175
+ for (let j = 0; j < numberAlternatives.numbers.length; j++) {
2176
+ const result = await this._locateElementByText(frames[i], numberAlternatives.numbers[j], "*:not(script, style, head)", true, true, {});
2177
+ result.frame = frames[i];
2178
+ results.push(result);
2179
+ }
2180
+ }
2181
+ else {
2182
+ const result = await this._locateElementByText(frames[i], text, "*:not(script, style, head)", true, true, {});
2183
+ result.frame = frames[i];
2184
+ results.push(result);
2185
+ }
2186
+ }
2187
+ state.info.results = results;
2188
+ const resultWithElementsFound = results.filter((result) => result.elementCount > 0);
2189
+ if (resultWithElementsFound.length === 0) {
2190
+ await _screenshot(state, this);
2191
+ return state.info;
2192
+ }
2193
+ if (Date.now() - state.startTime > timeout) {
2194
+ throw new Error(`Text ${text} found in page`);
2195
+ }
2196
+ await new Promise((resolve) => setTimeout(resolve, 1000));
2197
+ }
2198
+ }
2199
+ catch (e) {
2200
+ await _commandError(state, e, this);
2201
+ }
2202
+ finally {
2203
+ _commandFinally(state, this);
2356
2204
  }
2357
2205
  }
2358
2206
  _getServerUrl() {
@@ -2415,11 +2263,12 @@ class StableBrowser {
2415
2263
  info.screenshotPath = screenshotPath;
2416
2264
  Object.assign(e, { info: info });
2417
2265
  error = e;
2418
- throw e;
2266
+ // throw e;
2267
+ await _commandError({ text: "visualVerification", operation: "visualVerification", text, info }, e, this);
2419
2268
  }
2420
2269
  finally {
2421
2270
  const endTime = Date.now();
2422
- this._reportToWorld(world, {
2271
+ _reportToWorld(world, {
2423
2272
  type: Types.VERIFY_VISUAL,
2424
2273
  text: "Visual verification",
2425
2274
  screenshotId,
@@ -2428,7 +2277,7 @@ class StableBrowser {
2428
2277
  status: "FAILED",
2429
2278
  startTime,
2430
2279
  endTime,
2431
- message: error === null || error === void 0 ? void 0 : error.message,
2280
+ message: error?.message,
2432
2281
  }
2433
2282
  : {
2434
2283
  status: "PASSED",
@@ -2460,7 +2309,7 @@ class StableBrowser {
2460
2309
  this.logger.info("Table data verified");
2461
2310
  }
2462
2311
  async getTableData(selectors, _params = null, options = {}, world = null) {
2463
- this._validateSelectors(selectors);
2312
+ _validateSelectors(selectors);
2464
2313
  const startTime = Date.now();
2465
2314
  let error = null;
2466
2315
  let screenshotId = null;
@@ -2482,11 +2331,12 @@ class StableBrowser {
2482
2331
  info.screenshotPath = screenshotPath;
2483
2332
  Object.assign(e, { info: info });
2484
2333
  error = e;
2485
- throw e;
2334
+ // throw e;
2335
+ await _commandError({ text: "getTableData", operation: "getTableData", selectors, info }, e, this);
2486
2336
  }
2487
2337
  finally {
2488
2338
  const endTime = Date.now();
2489
- this._reportToWorld(world, {
2339
+ _reportToWorld(world, {
2490
2340
  element_name: selectors.element_name,
2491
2341
  type: Types.GET_TABLE_DATA,
2492
2342
  text: "Get table data",
@@ -2496,7 +2346,7 @@ class StableBrowser {
2496
2346
  status: "FAILED",
2497
2347
  startTime,
2498
2348
  endTime,
2499
- message: error === null || error === void 0 ? void 0 : error.message,
2349
+ message: error?.message,
2500
2350
  }
2501
2351
  : {
2502
2352
  status: "PASSED",
@@ -2508,7 +2358,7 @@ class StableBrowser {
2508
2358
  }
2509
2359
  }
2510
2360
  async analyzeTable(selectors, query, operator, value, _params = null, options = {}, world = null) {
2511
- this._validateSelectors(selectors);
2361
+ _validateSelectors(selectors);
2512
2362
  if (!query) {
2513
2363
  throw new Error("query is null");
2514
2364
  }
@@ -2647,11 +2497,12 @@ class StableBrowser {
2647
2497
  info.screenshotPath = screenshotPath;
2648
2498
  Object.assign(e, { info: info });
2649
2499
  error = e;
2650
- throw e;
2500
+ // throw e;
2501
+ await _commandError({ text: "analyzeTable", operation: "analyzeTable", selectors, query, operator, value }, e, this);
2651
2502
  }
2652
2503
  finally {
2653
2504
  const endTime = Date.now();
2654
- this._reportToWorld(world, {
2505
+ _reportToWorld(world, {
2655
2506
  element_name: selectors.element_name,
2656
2507
  type: Types.ANALYZE_TABLE,
2657
2508
  text: "Analyze table",
@@ -2661,7 +2512,7 @@ class StableBrowser {
2661
2512
  status: "FAILED",
2662
2513
  startTime,
2663
2514
  endTime,
2664
- message: error === null || error === void 0 ? void 0 : error.message,
2515
+ message: error?.message,
2665
2516
  }
2666
2517
  : {
2667
2518
  status: "PASSED",
@@ -2673,27 +2524,7 @@ class StableBrowser {
2673
2524
  }
2674
2525
  }
2675
2526
  async _replaceWithLocalData(value, world, _decrypt = true, totpWait = true) {
2676
- if (!value) {
2677
- return value;
2678
- }
2679
- // find all the accurance of {{(.*?)}} and replace with the value
2680
- let regex = /{{(.*?)}}/g;
2681
- let matches = value.match(regex);
2682
- if (matches) {
2683
- const testData = this.getTestData(world);
2684
- for (let i = 0; i < matches.length; i++) {
2685
- let match = matches[i];
2686
- let key = match.substring(2, match.length - 2);
2687
- let newValue = objectPath.get(testData, key, null);
2688
- if (newValue !== null) {
2689
- value = value.replace(match, newValue);
2690
- }
2691
- }
2692
- }
2693
- if ((value.startsWith("secret:") || value.startsWith("totp:")) && _decrypt) {
2694
- return await decrypt(value, null, totpWait);
2695
- }
2696
- return value;
2527
+ return await replaceWithLocalTestData(value, world, _decrypt, totpWait, this.context, this);
2697
2528
  }
2698
2529
  _getLoadTimeout(options) {
2699
2530
  let timeout = 15000;
@@ -2744,7 +2575,7 @@ class StableBrowser {
2744
2575
  await new Promise((resolve) => setTimeout(resolve, 2000));
2745
2576
  ({ screenshotId, screenshotPath } = await this._screenShot(options, world));
2746
2577
  const endTime = Date.now();
2747
- this._reportToWorld(world, {
2578
+ _reportToWorld(world, {
2748
2579
  type: Types.GET_PAGE_STATUS,
2749
2580
  text: "Wait for page load",
2750
2581
  screenshotId,
@@ -2753,7 +2584,7 @@ class StableBrowser {
2753
2584
  status: "FAILED",
2754
2585
  startTime,
2755
2586
  endTime,
2756
- message: error === null || error === void 0 ? void 0 : error.message,
2587
+ message: error?.message,
2757
2588
  }
2758
2589
  : {
2759
2590
  status: "PASSED",
@@ -2764,41 +2595,35 @@ class StableBrowser {
2764
2595
  }
2765
2596
  }
2766
2597
  async closePage(options = {}, world = null) {
2767
- const startTime = Date.now();
2768
- let error = null;
2769
- let screenshotId = null;
2770
- let screenshotPath = null;
2771
- const info = {};
2598
+ const state = {
2599
+ options,
2600
+ world,
2601
+ locate: false,
2602
+ scroll: false,
2603
+ highlight: false,
2604
+ type: Types.CLOSE_PAGE,
2605
+ text: `Close page`,
2606
+ operation: "closePage",
2607
+ log: "***** close page *****\n",
2608
+ throwError: false,
2609
+ };
2772
2610
  try {
2611
+ await _preCommand(state, this);
2773
2612
  await this.page.close();
2774
2613
  }
2775
2614
  catch (e) {
2776
2615
  console.log(".");
2616
+ await _commandError(state, e, this);
2777
2617
  }
2778
2618
  finally {
2779
- await new Promise((resolve) => setTimeout(resolve, 2000));
2780
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world));
2781
- const endTime = Date.now();
2782
- this._reportToWorld(world, {
2783
- type: Types.CLOSE_PAGE,
2784
- text: "close page",
2785
- screenshotId,
2786
- result: error
2787
- ? {
2788
- status: "FAILED",
2789
- startTime,
2790
- endTime,
2791
- message: error === null || error === void 0 ? void 0 : error.message,
2792
- }
2793
- : {
2794
- status: "PASSED",
2795
- startTime,
2796
- endTime,
2797
- },
2798
- info: info,
2799
- });
2619
+ _commandFinally(state, this);
2800
2620
  }
2801
2621
  }
2622
+ saveTestDataAsGlobal(options, world) {
2623
+ const dataFile = this._getDataFile(world);
2624
+ process.env.GLOBAL_TEST_DATA_FILE = dataFile;
2625
+ this.logger.info("Save the scenario test data as global for the following scenarios.");
2626
+ }
2802
2627
  async setViewportSize(width, hight, options = {}, world = null) {
2803
2628
  const startTime = Date.now();
2804
2629
  let error = null;
@@ -2816,12 +2641,13 @@ class StableBrowser {
2816
2641
  }
2817
2642
  catch (e) {
2818
2643
  console.log(".");
2644
+ await _commandError({ text: "setViewportSize", operation: "setViewportSize", width, hight, info }, e, this);
2819
2645
  }
2820
2646
  finally {
2821
2647
  await new Promise((resolve) => setTimeout(resolve, 2000));
2822
2648
  ({ screenshotId, screenshotPath } = await this._screenShot(options, world));
2823
2649
  const endTime = Date.now();
2824
- this._reportToWorld(world, {
2650
+ _reportToWorld(world, {
2825
2651
  type: Types.SET_VIEWPORT,
2826
2652
  text: "set viewport size to " + width + "x" + hight,
2827
2653
  screenshotId,
@@ -2830,7 +2656,7 @@ class StableBrowser {
2830
2656
  status: "FAILED",
2831
2657
  startTime,
2832
2658
  endTime,
2833
- message: error === null || error === void 0 ? void 0 : error.message,
2659
+ message: error?.message,
2834
2660
  }
2835
2661
  : {
2836
2662
  status: "PASSED",
@@ -2852,12 +2678,13 @@ class StableBrowser {
2852
2678
  }
2853
2679
  catch (e) {
2854
2680
  console.log(".");
2681
+ await _commandError({ text: "reloadPage", operation: "reloadPage", info }, e, this);
2855
2682
  }
2856
2683
  finally {
2857
2684
  await new Promise((resolve) => setTimeout(resolve, 2000));
2858
2685
  ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
2859
2686
  const endTime = Date.now();
2860
- this._reportToWorld(world, {
2687
+ _reportToWorld(world, {
2861
2688
  type: Types.GET_PAGE_STATUS,
2862
2689
  text: "page relaod",
2863
2690
  screenshotId,
@@ -2866,7 +2693,7 @@ class StableBrowser {
2866
2693
  status: "FAILED",
2867
2694
  startTime,
2868
2695
  endTime,
2869
- message: error === null || error === void 0 ? void 0 : error.message,
2696
+ message: error?.message,
2870
2697
  }
2871
2698
  : {
2872
2699
  status: "PASSED",
@@ -2893,11 +2720,37 @@ class StableBrowser {
2893
2720
  console.log("#-#");
2894
2721
  }
2895
2722
  }
2896
- _reportToWorld(world, properties) {
2897
- if (!world || !world.attach) {
2898
- return;
2723
+ async beforeStep(world, step) {
2724
+ this.stepName = step.pickleStep.text;
2725
+ this.logger.info("step: " + this.stepName);
2726
+ if (this.stepIndex === undefined) {
2727
+ this.stepIndex = 0;
2728
+ }
2729
+ else {
2730
+ this.stepIndex++;
2731
+ }
2732
+ if (this.context && this.context.browserObject && this.context.browserObject.trace === true) {
2733
+ if (this.context.browserObject.context) {
2734
+ await this.context.browserObject.context.tracing.startChunk({ title: this.stepName });
2735
+ }
2736
+ }
2737
+ if (this.tags === null && step && step.pickle && step.pickle.tags) {
2738
+ this.tags = step.pickle.tags.map((tag) => tag.name);
2739
+ // check if @global_test_data tag is present
2740
+ if (this.tags.includes("@global_test_data")) {
2741
+ this.saveTestDataAsGlobal({}, world);
2742
+ }
2743
+ }
2744
+ }
2745
+ async afterStep(world, step) {
2746
+ this.stepName = null;
2747
+ if (this.context && this.context.browserObject && this.context.browserObject.trace === true) {
2748
+ if (this.context.browserObject.context) {
2749
+ await this.context.browserObject.context.tracing.stopChunk({
2750
+ path: path.join(this.context.browserObject.traceFolder, `trace-${this.stepIndex}.zip`),
2751
+ });
2752
+ }
2899
2753
  }
2900
- world.attach(JSON.stringify(properties), { mediaType: "application/json" });
2901
2754
  }
2902
2755
  }
2903
2756
  function createTimedPromise(promise, label) {