automation_model 1.0.463-dev → 1.0.463-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 +181 -7
  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 +182 -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 +632 -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,19 +476,39 @@ 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];
489
+ try {
490
+ locatorSearch = JSON.parse(this._fixUsingParams(JSON.stringify(locatorSearch), _params));
491
+ }
492
+ catch (e) {
493
+ console.error(e);
494
+ }
477
495
  //info.log += "searching for locator " + JSON.stringify(locatorSearch) + "\n";
478
496
  let locator = null;
479
497
  if (locatorSearch.climb && locatorSearch.climb >= 0) {
480
498
  let locatorString = await this._locateElmentByTextClimbCss(scope, locatorSearch.text, locatorSearch.climb, locatorSearch.css, _params);
481
499
  if (!locatorString) {
500
+ info.failCause.textNotFound = true;
501
+ info.failCause.lastError = "failed to locate element by text: " + locatorSearch.text;
482
502
  return;
483
503
  }
484
504
  locator = this._getLocator({ css: locatorString }, scope, _params);
485
505
  }
486
506
  else if (locatorSearch.text) {
487
- 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);
488
509
  if (result.elementCount === 0) {
510
+ info.failCause.textNotFound = true;
511
+ info.failCause.lastError = "failed to locate element by text: " + text;
489
512
  return;
490
513
  }
491
514
  locatorSearch.css = "[data-blinq-id='blinq-id-" + result.randomToken + "']";
@@ -502,6 +525,9 @@ class StableBrowser {
502
525
  // cssHref = true;
503
526
  // }
504
527
  let count = await locator.count();
528
+ if (count > 0 && !info.failCause.count) {
529
+ info.failCause.count = count;
530
+ }
505
531
  //info.log += "total elements found " + count + "\n";
506
532
  //let visibleCount = 0;
507
533
  let visibleLocator = null;
@@ -519,6 +545,8 @@ class StableBrowser {
519
545
  foundLocators.push(locator.nth(j));
520
546
  }
521
547
  else {
548
+ info.failCause.visible = visible;
549
+ info.failCause.enabled = enabled;
522
550
  if (!info.printMessages) {
523
551
  info.printMessages = {};
524
552
  }
@@ -530,6 +558,11 @@ class StableBrowser {
530
558
  }
531
559
  }
532
560
  async closeUnexpectedPopups(info, _params) {
561
+ if (!info) {
562
+ info = {};
563
+ info.failCause = {};
564
+ info.log = "";
565
+ }
533
566
  if (this.configuration.popupHandlers && this.configuration.popupHandlers.length > 0) {
534
567
  if (!info) {
535
568
  info = {};
@@ -570,7 +603,10 @@ class StableBrowser {
570
603
  }
571
604
  return { rerun: false };
572
605
  }
573
- async _locate(selectors, info, _params, timeout = 30000) {
606
+ async _locate(selectors, info, _params, timeout) {
607
+ if (!timeout) {
608
+ timeout = 30000;
609
+ }
574
610
  for (let i = 0; i < 3; i++) {
575
611
  info.log += "attempt " + i + ": total locators " + selectors.locators.length + "\n";
576
612
  for (let j = 0; j < selectors.locators.length; j++) {
@@ -584,13 +620,16 @@ class StableBrowser {
584
620
  }
585
621
  throw new Error("unable to locate element " + JSON.stringify(selectors));
586
622
  }
587
- async _locate_internal(selectors, info, _params, timeout = 30000) {
588
- let highPriorityTimeout = 5000;
589
- let visibleOnlyTimeout = 6000;
590
- let startTime = performance.now();
591
- let locatorsCount = 0;
592
- //let arrayMode = Array.isArray(selectors);
623
+ async _findFrameScope(selectors, timeout = 30000, info) {
624
+ if (!info) {
625
+ info = {};
626
+ info.failCause = {};
627
+ info.log = "";
628
+ }
593
629
  let scope = this.page;
630
+ if (selectors.frame) {
631
+ return selectors.frame;
632
+ }
594
633
  if (selectors.iframe_src || selectors.frameLocators) {
595
634
  const findFrame = async (frame, framescope) => {
596
635
  for (let i = 0; i < frame.selectors.length; i++) {
@@ -617,7 +656,6 @@ class StableBrowser {
617
656
  }
618
657
  return framescope;
619
658
  };
620
- info.log += "searching for iframe " + selectors.iframe_src + "/" + selectors.frameLocators + "\n";
621
659
  while (true) {
622
660
  let frameFound = false;
623
661
  if (selectors.nestFrmLoc) {
@@ -641,6 +679,8 @@ class StableBrowser {
641
679
  if (!scope) {
642
680
  info.log += "unable to locate iframe " + selectors.iframe_src + "\n";
643
681
  if (performance.now() - startTime > timeout) {
682
+ info.failCause.iframeNotFound = true;
683
+ info.failCause.lastError = "unable to locate iframe " + selectors.iframe_src;
644
684
  throw new Error("unable to locate iframe " + selectors.iframe_src);
645
685
  }
646
686
  await new Promise((resolve) => setTimeout(resolve, 1000));
@@ -650,6 +690,30 @@ class StableBrowser {
650
690
  }
651
691
  }
652
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);
653
717
  let selectorsLocators = null;
654
718
  selectorsLocators = selectors.locators;
655
719
  // group selectors by priority
@@ -751,6 +815,8 @@ class StableBrowser {
751
815
  }
752
816
  this.logger.debug("unable to locate unique element, total elements found " + locatorsCount);
753
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";
754
820
  throw new Error("failed to locate first element no elements found, " + info.log);
755
821
  }
756
822
  async _scanLocatorsGroup(locatorsGroup, scope, _params, info, visibleOnly) {
@@ -782,89 +848,129 @@ class StableBrowser {
782
848
  });
783
849
  result.locatorIndex = i;
784
850
  }
851
+ if (foundLocators.length > 1) {
852
+ info.failCause.foundMultiple = true;
853
+ }
785
854
  }
786
855
  return result;
787
856
  }
788
- async click(selectors, _params, options = {}, world = null) {
789
- this._validateSelectors(selectors);
857
+ async simpleClick(elementDescription, _params, options = {}, world = null) {
790
858
  const startTime = Date.now();
791
- if (options && options.context) {
792
- selectors.locators[0].text = options.context;
859
+ let timeout = 30000;
860
+ if (options && options.timeout) {
861
+ timeout = options.timeout;
793
862
  }
794
- const info = {};
795
- info.log = "***** click on " + selectors.element_name + " *****\n";
796
- info.operation = "click";
797
- info.selectors = selectors;
798
- let error = null;
799
- let screenshotId = null;
800
- 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
+ };
801
930
  try {
802
- let element = await this._locate(selectors, info, _params);
803
- await this.scrollIfNeeded(element, info);
804
- ({ 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
+ }
805
935
  try {
806
- await this._highlightElements(element);
807
- await element.click();
808
- await new Promise((resolve) => setTimeout(resolve, 1000));
936
+ await state.element.click();
937
+ // await new Promise((resolve) => setTimeout(resolve, 1000));
809
938
  }
810
939
  catch (e) {
811
940
  // await this.closeUnexpectedPopups();
812
- info.log += "click failed, will try again" + "\n";
813
- element = await this._locate(selectors, info, _params);
814
- await element.dispatchEvent("click");
815
- 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));
816
944
  }
817
945
  await this.waitForPageLoad();
818
- return info;
946
+ return state.info;
819
947
  }
820
948
  catch (e) {
821
- this.logger.error("click failed " + info.log);
822
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
823
- info.screenshotPath = screenshotPath;
824
- Object.assign(e, { info: info });
825
- error = e;
826
- throw e;
949
+ await _commandError(state, e, this);
827
950
  }
828
951
  finally {
829
- const endTime = Date.now();
830
- this._reportToWorld(world, {
831
- element_name: selectors.element_name,
832
- type: Types.CLICK,
833
- text: `Click element`,
834
- screenshotId,
835
- result: error
836
- ? {
837
- status: "FAILED",
838
- startTime,
839
- endTime,
840
- message: error === null || error === void 0 ? void 0 : error.message,
841
- }
842
- : {
843
- status: "PASSED",
844
- startTime,
845
- endTime,
846
- },
847
- info: info,
848
- });
952
+ _commandFinally(state, this);
849
953
  }
850
954
  }
851
955
  async setCheck(selectors, checked = true, _params, options = {}, world = null) {
852
- this._validateSelectors(selectors);
853
- const startTime = Date.now();
854
- const info = {};
855
- info.log = "";
856
- info.operation = "setCheck";
857
- info.checked = checked;
858
- info.selectors = selectors;
859
- let error = null;
860
- let screenshotId = null;
861
- 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
+ };
862
966
  try {
863
- let element = await this._locate(selectors, info, _params);
864
- ({ 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));
865
971
  try {
866
- await this._highlightElements(element);
867
- await element.setChecked(checked);
972
+ // await this._highlightElements(element);
973
+ await state.element.setChecked(checked);
868
974
  await new Promise((resolve) => setTimeout(resolve, 1000));
869
975
  }
870
976
  catch (e) {
@@ -873,179 +979,108 @@ class StableBrowser {
873
979
  }
874
980
  else {
875
981
  //await this.closeUnexpectedPopups();
876
- info.log += "setCheck failed, will try again" + "\n";
877
- element = await this._locate(selectors, info, _params);
878
- 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 });
879
985
  await new Promise((resolve) => setTimeout(resolve, 1000));
880
986
  }
881
987
  }
882
988
  await this.waitForPageLoad();
883
- return info;
989
+ return state.info;
884
990
  }
885
991
  catch (e) {
886
- this.logger.error("setCheck failed " + info.log);
887
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
888
- info.screenshotPath = screenshotPath;
889
- Object.assign(e, { info: info });
890
- error = e;
891
- throw e;
992
+ await _commandError(state, e, this);
892
993
  }
893
994
  finally {
894
- const endTime = Date.now();
895
- this._reportToWorld(world, {
896
- element_name: selectors.element_name,
897
- type: checked ? Types.CHECK : Types.UNCHECK,
898
- text: checked ? `Check element` : `Uncheck element`,
899
- screenshotId,
900
- result: error
901
- ? {
902
- status: "FAILED",
903
- startTime,
904
- endTime,
905
- message: error === null || error === void 0 ? void 0 : error.message,
906
- }
907
- : {
908
- status: "PASSED",
909
- startTime,
910
- endTime,
911
- },
912
- info: info,
913
- });
995
+ _commandFinally(state, this);
914
996
  }
915
997
  }
916
998
  async hover(selectors, _params, options = {}, world = null) {
917
- this._validateSelectors(selectors);
918
- const startTime = Date.now();
919
- const info = {};
920
- info.log = "";
921
- info.operation = "hover";
922
- info.selectors = selectors;
923
- let error = null;
924
- let screenshotId = null;
925
- 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
+ };
926
1009
  try {
927
- let element = await this._locate(selectors, info, _params);
928
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1010
+ await _preCommand(state, this);
929
1011
  try {
930
- await this._highlightElements(element);
931
- await element.hover();
1012
+ await state.element.hover();
932
1013
  await new Promise((resolve) => setTimeout(resolve, 1000));
933
1014
  }
934
1015
  catch (e) {
935
1016
  //await this.closeUnexpectedPopups();
936
- info.log += "hover failed, will try again" + "\n";
937
- element = await this._locate(selectors, info, _params);
938
- 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 });
939
1020
  await new Promise((resolve) => setTimeout(resolve, 1000));
940
1021
  }
941
1022
  await this.waitForPageLoad();
942
- return info;
1023
+ return state.info;
943
1024
  }
944
1025
  catch (e) {
945
- this.logger.error("hover failed " + info.log);
946
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
947
- info.screenshotPath = screenshotPath;
948
- Object.assign(e, { info: info });
949
- error = e;
950
- throw e;
1026
+ await _commandError(state, e, this);
951
1027
  }
952
1028
  finally {
953
- const endTime = Date.now();
954
- this._reportToWorld(world, {
955
- element_name: selectors.element_name,
956
- type: Types.HOVER,
957
- text: `Hover element`,
958
- screenshotId,
959
- result: error
960
- ? {
961
- status: "FAILED",
962
- startTime,
963
- endTime,
964
- message: error === null || error === void 0 ? void 0 : error.message,
965
- }
966
- : {
967
- status: "PASSED",
968
- startTime,
969
- endTime,
970
- },
971
- info: info,
972
- });
1029
+ _commandFinally(state, this);
973
1030
  }
974
1031
  }
975
1032
  async selectOption(selectors, values, _params = null, options = {}, world = null) {
976
- this._validateSelectors(selectors);
977
1033
  if (!values) {
978
1034
  throw new Error("values is null");
979
1035
  }
980
- const startTime = Date.now();
981
- let error = null;
982
- let screenshotId = null;
983
- let screenshotPath = null;
984
- const info = {};
985
- info.log = "";
986
- info.operation = "selectOptions";
987
- 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
+ };
988
1047
  try {
989
- let element = await this._locate(selectors, info, _params);
990
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1048
+ await _preCommand(state, this);
991
1049
  try {
992
- await this._highlightElements(element);
993
- await element.selectOption(values);
1050
+ await state.element.selectOption(values);
994
1051
  }
995
1052
  catch (e) {
996
1053
  //await this.closeUnexpectedPopups();
997
- info.log += "selectOption failed, will try force" + "\n";
998
- 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 });
999
1056
  }
1000
1057
  await this.waitForPageLoad();
1001
- return info;
1058
+ return state.info;
1002
1059
  }
1003
1060
  catch (e) {
1004
- this.logger.error("selectOption failed " + info.log);
1005
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1006
- info.screenshotPath = screenshotPath;
1007
- Object.assign(e, { info: info });
1008
- this.logger.info("click failed, will try next selector");
1009
- error = e;
1010
- throw e;
1061
+ await _commandError(state, e, this);
1011
1062
  }
1012
1063
  finally {
1013
- const endTime = Date.now();
1014
- this._reportToWorld(world, {
1015
- element_name: selectors.element_name,
1016
- type: Types.SELECT,
1017
- text: `Select option: ${values}`,
1018
- value: values.toString(),
1019
- screenshotId,
1020
- result: error
1021
- ? {
1022
- status: "FAILED",
1023
- startTime,
1024
- endTime,
1025
- message: error === null || error === void 0 ? void 0 : error.message,
1026
- }
1027
- : {
1028
- status: "PASSED",
1029
- startTime,
1030
- endTime,
1031
- },
1032
- info: info,
1033
- });
1064
+ _commandFinally(state, this);
1034
1065
  }
1035
1066
  }
1036
1067
  async type(_value, _params = null, options = {}, world = null) {
1037
- const startTime = Date.now();
1038
- let error = null;
1039
- let screenshotId = null;
1040
- let screenshotPath = null;
1041
- const info = {};
1042
- info.log = "";
1043
- info.operation = "type";
1044
- _value = this._fixUsingParams(_value, _params);
1045
- 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
+ };
1046
1081
  try {
1047
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1048
- const valueSegment = _value.split("&&");
1082
+ await _preCommand(state, this);
1083
+ const valueSegment = state.value.split("&&");
1049
1084
  for (let i = 0; i < valueSegment.length; i++) {
1050
1085
  if (i > 0) {
1051
1086
  await new Promise((resolve) => setTimeout(resolve, 1000));
@@ -1065,134 +1100,76 @@ class StableBrowser {
1065
1100
  await this.page.keyboard.type(value);
1066
1101
  }
1067
1102
  }
1068
- return info;
1103
+ return state.info;
1069
1104
  }
1070
1105
  catch (e) {
1071
- //await this.closeUnexpectedPopups();
1072
- this.logger.error("type failed " + info.log);
1073
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1074
- info.screenshotPath = screenshotPath;
1075
- Object.assign(e, { info: info });
1076
- error = e;
1077
- throw e;
1106
+ await _commandError(state, e, this);
1078
1107
  }
1079
1108
  finally {
1080
- const endTime = Date.now();
1081
- this._reportToWorld(world, {
1082
- type: Types.TYPE_PRESS,
1083
- screenshotId,
1084
- value: _value,
1085
- text: `type value: ${_value}`,
1086
- result: error
1087
- ? {
1088
- status: "FAILED",
1089
- startTime,
1090
- endTime,
1091
- message: error === null || error === void 0 ? void 0 : error.message,
1092
- }
1093
- : {
1094
- status: "PASSED",
1095
- startTime,
1096
- endTime,
1097
- },
1098
- info: info,
1099
- });
1109
+ _commandFinally(state, this);
1100
1110
  }
1101
1111
  }
1102
1112
  async setInputValue(selectors, value, _params = null, options = {}, world = null) {
1103
- // set input value for non fillable inputs like date, time, range, color, etc.
1104
- this._validateSelectors(selectors);
1105
- const startTime = Date.now();
1106
- const info = {};
1107
- info.log = "***** set input value " + selectors.element_name + " *****\n";
1108
- info.operation = "setInputValue";
1109
- info.selectors = selectors;
1110
- value = this._fixUsingParams(value, _params);
1111
- info.value = value;
1112
- let error = null;
1113
- let screenshotId = null;
1114
- 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
+ };
1115
1124
  try {
1116
- value = await this._replaceWithLocalData(value, this);
1117
- let element = await this._locate(selectors, info, _params);
1118
- await this.scrollIfNeeded(element, info);
1119
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1120
- await this._highlightElements(element);
1125
+ await _preCommand(state, this);
1126
+ let value = await this._replaceWithLocalData(state.value, this);
1121
1127
  try {
1122
- await element.evaluateHandle((el, value) => {
1128
+ await state.element.evaluateHandle((el, value) => {
1123
1129
  el.value = value;
1124
1130
  }, value);
1125
1131
  }
1126
1132
  catch (error) {
1127
1133
  this.logger.error("setInputValue failed, will try again");
1128
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1129
- info.screenshotPath = screenshotPath;
1130
- Object.assign(error, { info: info });
1131
- await element.evaluateHandle((el, value) => {
1134
+ await _screenshot(state, this);
1135
+ Object.assign(error, { info: state.info });
1136
+ await state.element.evaluateHandle((el, value) => {
1132
1137
  el.value = value;
1133
1138
  });
1134
1139
  }
1135
1140
  }
1136
1141
  catch (e) {
1137
- this.logger.error("setInputValue failed " + info.log);
1138
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1139
- info.screenshotPath = screenshotPath;
1140
- Object.assign(e, { info: info });
1141
- error = e;
1142
- throw e;
1142
+ await _commandError(state, e, this);
1143
1143
  }
1144
1144
  finally {
1145
- const endTime = Date.now();
1146
- this._reportToWorld(world, {
1147
- element_name: selectors.element_name,
1148
- type: Types.SET_INPUT,
1149
- text: `Set input value`,
1150
- value: value,
1151
- screenshotId,
1152
- result: error
1153
- ? {
1154
- status: "FAILED",
1155
- startTime,
1156
- endTime,
1157
- message: error === null || error === void 0 ? void 0 : error.message,
1158
- }
1159
- : {
1160
- status: "PASSED",
1161
- startTime,
1162
- endTime,
1163
- },
1164
- info: info,
1165
- });
1145
+ _commandFinally(state, this);
1166
1146
  }
1167
1147
  }
1168
1148
  async setDateTime(selectors, value, format = null, enter = false, _params = null, options = {}, world = null) {
1169
- this._validateSelectors(selectors);
1170
- const startTime = Date.now();
1171
- let error = null;
1172
- let screenshotId = null;
1173
- let screenshotPath = null;
1174
- const info = {};
1175
- info.log = "";
1176
- info.operation = Types.SET_DATE_TIME;
1177
- info.selectors = selectors;
1178
- 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
+ };
1179
1161
  try {
1180
- value = await this._replaceWithLocalData(value, this);
1181
- let element = await this._locate(selectors, info, _params);
1182
- //insert red border around the element
1183
- await this.scrollIfNeeded(element, info);
1184
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1185
- await this._highlightElements(element);
1162
+ await _preCommand(state, this);
1186
1163
  try {
1187
- await element.click();
1164
+ await state.element.click();
1188
1165
  await new Promise((resolve) => setTimeout(resolve, 500));
1189
1166
  if (format) {
1190
- value = dayjs(value).format(format);
1191
- await element.fill(value);
1167
+ state.value = dayjs(state.value).format(format);
1168
+ await state.element.fill(state.value);
1192
1169
  }
1193
1170
  else {
1194
- const dateTimeValue = await getDateTimeValue({ value, element });
1195
- await element.evaluateHandle((el, dateTimeValue) => {
1171
+ const dateTimeValue = await getDateTimeValue({ value: state.value, element: state.element });
1172
+ await state.element.evaluateHandle((el, dateTimeValue) => {
1196
1173
  el.value = ""; // clear input
1197
1174
  el.value = dateTimeValue;
1198
1175
  }, dateTimeValue);
@@ -1205,20 +1182,19 @@ class StableBrowser {
1205
1182
  }
1206
1183
  catch (err) {
1207
1184
  //await this.closeUnexpectedPopups();
1208
- this.logger.error("setting date time input failed " + JSON.stringify(info));
1185
+ this.logger.error("setting date time input failed " + JSON.stringify(state.info));
1209
1186
  this.logger.info("Trying again");
1210
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1211
- info.screenshotPath = screenshotPath;
1212
- Object.assign(err, { info: info });
1187
+ await _screenshot(state, this);
1188
+ Object.assign(err, { info: state.info });
1213
1189
  await element.click();
1214
1190
  await new Promise((resolve) => setTimeout(resolve, 500));
1215
1191
  if (format) {
1216
- value = dayjs(value).format(format);
1217
- await element.fill(value);
1192
+ state.value = dayjs(state.value).format(format);
1193
+ await state.element.fill(state.value);
1218
1194
  }
1219
1195
  else {
1220
- const dateTimeValue = await getDateTimeValue({ value, element });
1221
- await element.evaluateHandle((el, dateTimeValue) => {
1196
+ const dateTimeValue = await getDateTimeValue({ value: state.value, element: state.element });
1197
+ await state.element.evaluateHandle((el, dateTimeValue) => {
1222
1198
  el.value = ""; // clear input
1223
1199
  el.value = dateTimeValue;
1224
1200
  }, dateTimeValue);
@@ -1231,60 +1207,39 @@ class StableBrowser {
1231
1207
  }
1232
1208
  }
1233
1209
  catch (e) {
1234
- error = e;
1235
- throw e;
1210
+ await _commandError(state, e, this);
1236
1211
  }
1237
1212
  finally {
1238
- const endTime = Date.now();
1239
- this._reportToWorld(world, {
1240
- element_name: selectors.element_name,
1241
- type: Types.SET_DATE_TIME,
1242
- screenshotId,
1243
- value: value,
1244
- text: `setDateTime input with value: ${value}`,
1245
- result: error
1246
- ? {
1247
- status: "FAILED",
1248
- startTime,
1249
- endTime,
1250
- message: error === null || error === void 0 ? void 0 : error.message,
1251
- }
1252
- : {
1253
- status: "PASSED",
1254
- startTime,
1255
- endTime,
1256
- },
1257
- info: info,
1258
- });
1213
+ _commandFinally(state, this);
1259
1214
  }
1260
1215
  }
1261
1216
  async clickType(selectors, _value, enter = false, _params = null, options = {}, world = null) {
1262
1217
  _value = unEscapeString(_value);
1263
- this._validateSelectors(selectors);
1264
- const startTime = Date.now();
1265
- let error = null;
1266
- let screenshotId = null;
1267
- let screenshotPath = null;
1268
- const info = {};
1269
- info.log = "***** clickType on " + selectors.element_name + " with value " + _value + "*****\n";
1270
- info.operation = "clickType";
1271
- info.selectors = selectors;
1272
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
+ };
1273
1231
  if (newValue !== _value) {
1274
1232
  //this.logger.info(_value + "=" + newValue);
1275
1233
  _value = newValue;
1276
1234
  }
1277
- info.value = _value;
1278
1235
  try {
1279
- let element = await this._locate(selectors, info, _params);
1280
- //insert red border around the element
1281
- await this.scrollIfNeeded(element, info);
1282
- await this._highlightElements(element);
1236
+ await _preCommand(state, this);
1237
+ state.info.value = _value;
1283
1238
  if (options === null || options === undefined || !options.press) {
1284
1239
  try {
1285
- let currentValue = await element.inputValue();
1240
+ let currentValue = await state.element.inputValue();
1286
1241
  if (currentValue) {
1287
- await element.fill("");
1242
+ await state.element.fill("");
1288
1243
  }
1289
1244
  }
1290
1245
  catch (e) {
@@ -1293,22 +1248,22 @@ class StableBrowser {
1293
1248
  }
1294
1249
  if (options === null || options === undefined || options.press) {
1295
1250
  try {
1296
- await element.click({ timeout: 5000 });
1251
+ await state.element.click({ timeout: 5000 });
1297
1252
  }
1298
1253
  catch (e) {
1299
- await element.dispatchEvent("click");
1254
+ await state.element.dispatchEvent("click");
1300
1255
  }
1301
1256
  }
1302
1257
  else {
1303
1258
  try {
1304
- await element.focus();
1259
+ await state.element.focus();
1305
1260
  }
1306
1261
  catch (e) {
1307
- await element.dispatchEvent("focus");
1262
+ await state.element.dispatchEvent("focus");
1308
1263
  }
1309
1264
  }
1310
1265
  await new Promise((resolve) => setTimeout(resolve, 500));
1311
- const valueSegment = _value.split("&&");
1266
+ const valueSegment = state.value.split("&&");
1312
1267
  for (let i = 0; i < valueSegment.length; i++) {
1313
1268
  if (i > 0) {
1314
1269
  await new Promise((resolve) => setTimeout(resolve, 1000));
@@ -1328,14 +1283,14 @@ class StableBrowser {
1328
1283
  await new Promise((resolve) => setTimeout(resolve, 500));
1329
1284
  }
1330
1285
  }
1331
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1286
+ await _screenshot(state, this);
1332
1287
  if (enter === true) {
1333
1288
  await new Promise((resolve) => setTimeout(resolve, 2000));
1334
1289
  await this.page.keyboard.press("Enter");
1335
1290
  await this.waitForPageLoad();
1336
1291
  }
1337
1292
  else if (enter === false) {
1338
- await element.dispatchEvent("change");
1293
+ await state.element.dispatchEvent("change");
1339
1294
  //await this.page.keyboard.press("Tab");
1340
1295
  }
1341
1296
  else {
@@ -1344,104 +1299,50 @@ class StableBrowser {
1344
1299
  await this.waitForPageLoad();
1345
1300
  }
1346
1301
  }
1347
- return info;
1302
+ return state.info;
1348
1303
  }
1349
1304
  catch (e) {
1350
- //await this.closeUnexpectedPopups();
1351
- this.logger.error("fill failed " + JSON.stringify(info));
1352
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1353
- info.screenshotPath = screenshotPath;
1354
- Object.assign(e, { info: info });
1355
- error = e;
1356
- throw e;
1305
+ await _commandError(state, e, this);
1357
1306
  }
1358
1307
  finally {
1359
- const endTime = Date.now();
1360
- this._reportToWorld(world, {
1361
- element_name: selectors.element_name,
1362
- type: Types.FILL,
1363
- screenshotId,
1364
- value: _value,
1365
- text: `clickType input with value: ${_value}`,
1366
- result: error
1367
- ? {
1368
- status: "FAILED",
1369
- startTime,
1370
- endTime,
1371
- message: error === null || error === void 0 ? void 0 : error.message,
1372
- }
1373
- : {
1374
- status: "PASSED",
1375
- startTime,
1376
- endTime,
1377
- },
1378
- info: info,
1379
- });
1308
+ _commandFinally(state, this);
1380
1309
  }
1381
1310
  }
1382
1311
  async fill(selectors, value, enter = false, _params = null, options = {}, world = null) {
1383
- this._validateSelectors(selectors);
1384
- value = unEscapeString(value);
1385
- const startTime = Date.now();
1386
- let error = null;
1387
- let screenshotId = null;
1388
- let screenshotPath = null;
1389
- const info = {};
1390
- info.log = "***** fill on " + selectors.element_name + " with value " + value + "*****\n";
1391
- info.operation = "fill";
1392
- info.selectors = selectors;
1393
- 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
+ };
1394
1323
  try {
1395
- let element = await this._locate(selectors, info, _params);
1396
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1397
- await this._highlightElements(element);
1398
- await element.fill(value);
1399
- await element.dispatchEvent("change");
1324
+ await _preCommand(state, this);
1325
+ await state.element.fill(value);
1326
+ await state.element.dispatchEvent("change");
1400
1327
  if (enter) {
1401
1328
  await new Promise((resolve) => setTimeout(resolve, 2000));
1402
1329
  await this.page.keyboard.press("Enter");
1403
1330
  }
1404
1331
  await this.waitForPageLoad();
1405
- return info;
1332
+ return state.info;
1406
1333
  }
1407
- catch (e) {
1408
- //await this.closeUnexpectedPopups();
1409
- this.logger.error("fill failed " + info.log);
1410
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1411
- info.screenshotPath = screenshotPath;
1412
- Object.assign(e, { info: info });
1413
- error = e;
1414
- throw e;
1334
+ catch (e) {
1335
+ await _commandError(state, e, this);
1415
1336
  }
1416
1337
  finally {
1417
- const endTime = Date.now();
1418
- this._reportToWorld(world, {
1419
- element_name: selectors.element_name,
1420
- type: Types.FILL,
1421
- screenshotId,
1422
- value,
1423
- text: `Fill input with value: ${value}`,
1424
- result: error
1425
- ? {
1426
- status: "FAILED",
1427
- startTime,
1428
- endTime,
1429
- message: error === null || error === void 0 ? void 0 : error.message,
1430
- }
1431
- : {
1432
- status: "PASSED",
1433
- startTime,
1434
- endTime,
1435
- },
1436
- info: info,
1437
- });
1338
+ _commandFinally(state, this);
1438
1339
  }
1439
1340
  }
1440
1341
  async getText(selectors, _params = null, options = {}, info = {}, world = null) {
1441
1342
  return await this._getText(selectors, 0, _params, options, info, world);
1442
1343
  }
1443
1344
  async _getText(selectors, climb, _params = null, options = {}, info = {}, world = null) {
1444
- this._validateSelectors(selectors);
1345
+ _validateSelectors(selectors);
1445
1346
  let screenshotId = null;
1446
1347
  let screenshotPath = null;
1447
1348
  if (!info.log) {
@@ -1485,166 +1386,124 @@ class StableBrowser {
1485
1386
  }
1486
1387
  }
1487
1388
  async containsPattern(selectors, pattern, text, _params = null, options = {}, world = null) {
1488
- var _a;
1489
- this._validateSelectors(selectors);
1490
1389
  if (!pattern) {
1491
1390
  throw new Error("pattern is null");
1492
1391
  }
1493
1392
  if (!text) {
1494
1393
  throw new Error("text is null");
1495
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
+ };
1496
1411
  const newValue = await this._replaceWithLocalData(text, world);
1497
1412
  if (newValue !== text) {
1498
1413
  this.logger.info(text + "=" + newValue);
1499
1414
  text = newValue;
1500
1415
  }
1501
- const startTime = Date.now();
1502
- let error = null;
1503
- let screenshotId = null;
1504
- let screenshotPath = null;
1505
- const info = {};
1506
- info.log =
1507
- "***** verify element " + selectors.element_name + " contains pattern " + pattern + "/" + text + " *****\n";
1508
- info.operation = "containsPattern";
1509
- info.selectors = selectors;
1510
- info.value = text;
1511
- info.pattern = pattern;
1512
1416
  let foundObj = null;
1513
1417
  try {
1514
- 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);
1515
1421
  if (foundObj && foundObj.element) {
1516
- await this.scrollIfNeeded(foundObj.element, info);
1422
+ await this.scrollIfNeeded(foundObj.element, state.info);
1517
1423
  }
1518
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1424
+ await _screenshot(state, this);
1519
1425
  let escapedText = text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
1520
1426
  pattern = pattern.replace("{text}", escapedText);
1521
1427
  let regex = new RegExp(pattern, "im");
1522
- 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))) {
1523
- 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;
1524
1430
  throw new Error("element doesn't contain text " + text);
1525
1431
  }
1526
- return info;
1432
+ return state.info;
1527
1433
  }
1528
1434
  catch (e) {
1529
- //await this.closeUnexpectedPopups();
1530
- this.logger.error("verify element contains text failed " + info.log);
1531
- this.logger.error("found text " + (foundObj === null || foundObj === void 0 ? void 0 : foundObj.text) + " pattern " + pattern);
1532
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1533
- info.screenshotPath = screenshotPath;
1534
- Object.assign(e, { info: info });
1535
- error = e;
1536
- throw e;
1435
+ this.logger.error("found text " + foundObj?.text + " pattern " + pattern);
1436
+ await _commandError(state, e, this);
1537
1437
  }
1538
1438
  finally {
1539
- const endTime = Date.now();
1540
- this._reportToWorld(world, {
1541
- element_name: selectors.element_name,
1542
- type: Types.VERIFY_ELEMENT_CONTAINS_TEXT,
1543
- value: pattern,
1544
- text: `Verify element contains pattern: ${pattern}`,
1545
- screenshotId: foundObj === null || foundObj === void 0 ? void 0 : foundObj.screenshotId,
1546
- result: error
1547
- ? {
1548
- status: "FAILED",
1549
- startTime,
1550
- endTime,
1551
- message: error === null || error === void 0 ? void 0 : error.message,
1552
- }
1553
- : {
1554
- status: "PASSED",
1555
- startTime,
1556
- endTime,
1557
- },
1558
- info: info,
1559
- });
1439
+ _commandFinally(state, this);
1560
1440
  }
1561
1441
  }
1562
1442
  async containsText(selectors, text, climb, _params = null, options = {}, world = null) {
1563
- var _a, _b, _c;
1564
- this._validateSelectors(selectors);
1565
- 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
+ };
1566
1458
  if (!text) {
1567
1459
  throw new Error("text is null");
1568
1460
  }
1569
- const startTime = Date.now();
1570
- let error = null;
1571
- let screenshotId = null;
1572
- let screenshotPath = null;
1573
- const info = {};
1574
- info.log = "***** verify element " + selectors.element_name + " contains text " + text + " *****\n";
1575
- info.operation = "containsText";
1576
- info.selectors = selectors;
1461
+ text = unEscapeString(text);
1577
1462
  const newValue = await this._replaceWithLocalData(text, world);
1578
1463
  if (newValue !== text) {
1579
1464
  this.logger.info(text + "=" + newValue);
1580
1465
  text = newValue;
1581
1466
  }
1582
- info.value = text;
1583
1467
  let foundObj = null;
1584
1468
  try {
1585
- 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);
1586
1471
  if (foundObj && foundObj.element) {
1587
- await this.scrollIfNeeded(foundObj.element, info);
1472
+ await this.scrollIfNeeded(foundObj.element, state.info);
1588
1473
  }
1589
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1474
+ await _screenshot(state, this);
1590
1475
  const dateAlternatives = findDateAlternatives(text);
1591
1476
  const numberAlternatives = findNumberAlternatives(text);
1592
1477
  if (dateAlternatives.date) {
1593
1478
  for (let i = 0; i < dateAlternatives.dates.length; i++) {
1594
- if ((foundObj === null || foundObj === void 0 ? void 0 : foundObj.text.includes(dateAlternatives.dates[i])) ||
1595
- ((_a = foundObj === null || foundObj === void 0 ? void 0 : foundObj.value) === null || _a === void 0 ? void 0 : _a.includes(dateAlternatives.dates[i]))) {
1596
- return info;
1479
+ if (foundObj?.text.includes(dateAlternatives.dates[i]) ||
1480
+ foundObj?.value?.includes(dateAlternatives.dates[i])) {
1481
+ return state.info;
1597
1482
  }
1598
1483
  }
1599
1484
  throw new Error("element doesn't contain text " + text);
1600
1485
  }
1601
1486
  else if (numberAlternatives.number) {
1602
1487
  for (let i = 0; i < numberAlternatives.numbers.length; i++) {
1603
- if ((foundObj === null || foundObj === void 0 ? void 0 : foundObj.text.includes(numberAlternatives.numbers[i])) ||
1604
- ((_b = foundObj === null || foundObj === void 0 ? void 0 : foundObj.value) === null || _b === void 0 ? void 0 : _b.includes(numberAlternatives.numbers[i]))) {
1605
- return info;
1488
+ if (foundObj?.text.includes(numberAlternatives.numbers[i]) ||
1489
+ foundObj?.value?.includes(numberAlternatives.numbers[i])) {
1490
+ return state.info;
1606
1491
  }
1607
1492
  }
1608
1493
  throw new Error("element doesn't contain text " + text);
1609
1494
  }
1610
- 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))) {
1611
- info.foundText = foundObj === null || foundObj === void 0 ? void 0 : foundObj.text;
1612
- 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;
1613
1498
  throw new Error("element doesn't contain text " + text);
1614
1499
  }
1615
- return info;
1500
+ return state.info;
1616
1501
  }
1617
1502
  catch (e) {
1618
- //await this.closeUnexpectedPopups();
1619
- this.logger.error("verify element contains text failed " + info.log);
1620
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1621
- info.screenshotPath = screenshotPath;
1622
- Object.assign(e, { info: info });
1623
- error = e;
1624
- throw e;
1503
+ await _commandError(state, e, this);
1625
1504
  }
1626
1505
  finally {
1627
- const endTime = Date.now();
1628
- this._reportToWorld(world, {
1629
- element_name: selectors.element_name,
1630
- type: Types.VERIFY_ELEMENT_CONTAINS_TEXT,
1631
- text: `Verify element contains text: ${text}`,
1632
- value: text,
1633
- screenshotId: foundObj === null || foundObj === void 0 ? void 0 : foundObj.screenshotId,
1634
- result: error
1635
- ? {
1636
- status: "FAILED",
1637
- startTime,
1638
- endTime,
1639
- message: error === null || error === void 0 ? void 0 : error.message,
1640
- }
1641
- : {
1642
- status: "PASSED",
1643
- startTime,
1644
- endTime,
1645
- },
1646
- info: info,
1647
- });
1506
+ _commandFinally(state, this);
1648
1507
  }
1649
1508
  }
1650
1509
  _getDataFile(world = null) {
@@ -1918,127 +1777,69 @@ class StableBrowser {
1918
1777
  }
1919
1778
  }
1920
1779
  async verifyElementExistInPage(selectors, _params = null, options = {}, world = null) {
1921
- this._validateSelectors(selectors);
1922
- const startTime = Date.now();
1923
- let error = null;
1924
- let screenshotId = null;
1925
- 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
+ };
1926
1790
  await new Promise((resolve) => setTimeout(resolve, 2000));
1927
- const info = {};
1928
- info.log = "***** verify element " + selectors.element_name + " exists in page *****\n";
1929
- info.operation = "verify";
1930
- info.selectors = selectors;
1931
1791
  try {
1932
- const element = await this._locate(selectors, info, _params);
1933
- if (element) {
1934
- await this.scrollIfNeeded(element, info);
1935
- }
1936
- await this._highlightElements(element);
1937
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1938
- await expect(element).toHaveCount(1, { timeout: 10000 });
1939
- return info;
1792
+ await _preCommand(state, this);
1793
+ await expect(state.element).toHaveCount(1, { timeout: 10000 });
1794
+ return state.info;
1940
1795
  }
1941
1796
  catch (e) {
1942
- //await this.closeUnexpectedPopups();
1943
- this.logger.error("verify failed " + info.log);
1944
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1945
- info.screenshotPath = screenshotPath;
1946
- Object.assign(e, { info: info });
1947
- error = e;
1948
- throw e;
1797
+ await _commandError(state, e, this);
1949
1798
  }
1950
1799
  finally {
1951
- const endTime = Date.now();
1952
- this._reportToWorld(world, {
1953
- element_name: selectors.element_name,
1954
- type: Types.VERIFY_ELEMENT_CONTAINS_TEXT,
1955
- text: "Verify element exists in page",
1956
- screenshotId,
1957
- result: error
1958
- ? {
1959
- status: "FAILED",
1960
- startTime,
1961
- endTime,
1962
- message: error === null || error === void 0 ? void 0 : error.message,
1963
- }
1964
- : {
1965
- status: "PASSED",
1966
- startTime,
1967
- endTime,
1968
- },
1969
- info: info,
1970
- });
1800
+ _commandFinally(state, this);
1971
1801
  }
1972
1802
  }
1973
1803
  async extractAttribute(selectors, attribute, variable, _params = null, options = {}, world = null) {
1974
- this._validateSelectors(selectors);
1975
- const startTime = Date.now();
1976
- let error = null;
1977
- let screenshotId = null;
1978
- 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
+ };
1979
1816
  await new Promise((resolve) => setTimeout(resolve, 2000));
1980
- const info = {};
1981
- info.log = "***** extract attribute " + attribute + " from " + selectors.element_name + " *****\n";
1982
- info.operation = "extract";
1983
- info.selectors = selectors;
1984
1817
  try {
1985
- const element = await this._locate(selectors, info, _params);
1986
- await this._highlightElements(element);
1987
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1818
+ await _preCommand(state, this);
1988
1819
  switch (attribute) {
1989
1820
  case "inner_text":
1990
- info.value = await element.innerText();
1821
+ state.value = await state.element.innerText();
1991
1822
  break;
1992
1823
  case "href":
1993
- info.value = await element.getAttribute("href");
1824
+ state.value = await state.element.getAttribute("href");
1994
1825
  break;
1995
1826
  case "value":
1996
- info.value = await element.inputValue();
1827
+ state.value = await state.element.inputValue();
1997
1828
  break;
1998
1829
  default:
1999
- info.value = await element.getAttribute(attribute);
1830
+ state.value = await state.element.getAttribute(attribute);
2000
1831
  break;
2001
1832
  }
2002
- this[variable] = info.value;
2003
- if (world) {
2004
- world[variable] = info.value;
2005
- }
2006
- this.setTestData({ [variable]: info.value }, world);
2007
- this.logger.info("set test data: " + variable + "=" + info.value);
2008
- 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;
2009
1837
  }
2010
1838
  catch (e) {
2011
- //await this.closeUnexpectedPopups();
2012
- this.logger.error("extract failed " + info.log);
2013
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
2014
- info.screenshotPath = screenshotPath;
2015
- Object.assign(e, { info: info });
2016
- error = e;
2017
- throw e;
1839
+ await _commandError(state, e, this);
2018
1840
  }
2019
1841
  finally {
2020
- const endTime = Date.now();
2021
- this._reportToWorld(world, {
2022
- element_name: selectors.element_name,
2023
- type: Types.EXTRACT_ATTRIBUTE,
2024
- variable: variable,
2025
- value: info.value,
2026
- text: "Extract attribute from element",
2027
- screenshotId,
2028
- result: error
2029
- ? {
2030
- status: "FAILED",
2031
- startTime,
2032
- endTime,
2033
- message: error === null || error === void 0 ? void 0 : error.message,
2034
- }
2035
- : {
2036
- status: "PASSED",
2037
- startTime,
2038
- endTime,
2039
- },
2040
- info: info,
2041
- });
1842
+ _commandFinally(state, this);
2042
1843
  }
2043
1844
  }
2044
1845
  async extractEmailData(emailAddress, options, world) {
@@ -2115,7 +1916,8 @@ class StableBrowser {
2115
1916
  catch (e) {
2116
1917
  errorCount++;
2117
1918
  if (errorCount > 3) {
2118
- throw e;
1919
+ // throw e;
1920
+ await _commandError({ text: "extractEmailData", operation: "extractEmailData", emailAddress, info: {} }, e, this);
2119
1921
  }
2120
1922
  // ignore
2121
1923
  }
@@ -2226,11 +2028,12 @@ class StableBrowser {
2226
2028
  info.screenshotPath = screenshotPath;
2227
2029
  Object.assign(e, { info: info });
2228
2030
  error = e;
2229
- throw e;
2031
+ // throw e;
2032
+ await _commandError({ text: "verifyPagePath", operation: "verifyPagePath", pathPart, info }, e, this);
2230
2033
  }
2231
2034
  finally {
2232
2035
  const endTime = Date.now();
2233
- this._reportToWorld(world, {
2036
+ _reportToWorld(world, {
2234
2037
  type: Types.VERIFY_PAGE_PATH,
2235
2038
  text: "Verify page path",
2236
2039
  screenshotId,
@@ -2239,7 +2042,7 @@ class StableBrowser {
2239
2042
  status: "FAILED",
2240
2043
  startTime,
2241
2044
  endTime,
2242
- message: error === null || error === void 0 ? void 0 : error.message,
2045
+ message: error?.message,
2243
2046
  }
2244
2047
  : {
2245
2048
  status: "PASSED",
@@ -2252,52 +2055,58 @@ class StableBrowser {
2252
2055
  }
2253
2056
  async verifyTextExistInPage(text, options = {}, world = null) {
2254
2057
  text = unEscapeString(text);
2255
- 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
+ };
2256
2070
  const timeout = this._getLoadTimeout(options);
2257
- let error = null;
2258
- let screenshotId = null;
2259
- let screenshotPath = null;
2260
2071
  await new Promise((resolve) => setTimeout(resolve, 2000));
2261
- const info = {};
2262
- info.log = "***** verify text " + text + " exists in page *****\n";
2263
- info.operation = "verifyTextExistInPage";
2264
2072
  const newValue = await this._replaceWithLocalData(text, world);
2265
2073
  if (newValue !== text) {
2266
2074
  this.logger.info(text + "=" + newValue);
2267
2075
  text = newValue;
2268
2076
  }
2269
- info.text = text;
2270
2077
  let dateAlternatives = findDateAlternatives(text);
2271
2078
  let numberAlternatives = findNumberAlternatives(text);
2272
2079
  try {
2080
+ await _preCommand(state, this);
2081
+ state.info.text = text;
2273
2082
  while (true) {
2274
2083
  const frames = this.page.frames();
2275
2084
  let results = [];
2276
2085
  for (let i = 0; i < frames.length; i++) {
2277
2086
  if (dateAlternatives.date) {
2278
2087
  for (let j = 0; j < dateAlternatives.dates.length; j++) {
2279
- 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, {});
2280
2089
  result.frame = frames[i];
2281
2090
  results.push(result);
2282
2091
  }
2283
2092
  }
2284
2093
  else if (numberAlternatives.number) {
2285
2094
  for (let j = 0; j < numberAlternatives.numbers.length; j++) {
2286
- 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, {});
2287
2096
  result.frame = frames[i];
2288
2097
  results.push(result);
2289
2098
  }
2290
2099
  }
2291
2100
  else {
2292
- const result = await this._locateElementByText(frames[i], text, "*", true, {});
2101
+ const result = await this._locateElementByText(frames[i], text, "*:not(script, style, head)", true, true, {});
2293
2102
  result.frame = frames[i];
2294
2103
  results.push(result);
2295
2104
  }
2296
2105
  }
2297
- info.results = results;
2106
+ state.info.results = results;
2298
2107
  const resultWithElementsFound = results.filter((result) => result.elementCount > 0);
2299
2108
  if (resultWithElementsFound.length === 0) {
2300
- if (Date.now() - startTime > timeout) {
2109
+ if (Date.now() - state.startTime > timeout) {
2301
2110
  throw new Error(`Text ${text} not found in page`);
2302
2111
  }
2303
2112
  await new Promise((resolve) => setTimeout(resolve, 1000));
@@ -2309,44 +2118,89 @@ class StableBrowser {
2309
2118
  await this._highlightElements(frame, dataAttribute);
2310
2119
  const element = await frame.$(dataAttribute);
2311
2120
  if (element) {
2312
- await this.scrollIfNeeded(element, info);
2121
+ await this.scrollIfNeeded(element, state.info);
2313
2122
  await element.dispatchEvent("bvt_verify_page_contains_text");
2314
2123
  }
2315
2124
  }
2316
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
2317
- return info;
2125
+ await _screenshot(state, this);
2126
+ return state.info;
2318
2127
  }
2319
2128
  // await expect(element).toHaveCount(1, { timeout: 10000 });
2320
2129
  }
2321
2130
  catch (e) {
2322
- //await this.closeUnexpectedPopups();
2323
- this.logger.error("verify text exist in page failed " + info.log);
2324
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
2325
- info.screenshotPath = screenshotPath;
2326
- Object.assign(e, { info: info });
2327
- error = e;
2328
- throw e;
2131
+ await _commandError(state, e, this);
2329
2132
  }
2330
2133
  finally {
2331
- const endTime = Date.now();
2332
- this._reportToWorld(world, {
2333
- type: Types.VERIFY_ELEMENT_CONTAINS_TEXT,
2334
- text: "Verify text exists in page",
2335
- screenshotId,
2336
- result: error
2337
- ? {
2338
- status: "FAILED",
2339
- startTime,
2340
- endTime,
2341
- 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
+ }
2342
2173
  }
2343
- : {
2344
- status: "PASSED",
2345
- startTime,
2346
- endTime,
2347
- },
2348
- info: info,
2349
- });
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);
2350
2204
  }
2351
2205
  }
2352
2206
  _getServerUrl() {
@@ -2409,11 +2263,12 @@ class StableBrowser {
2409
2263
  info.screenshotPath = screenshotPath;
2410
2264
  Object.assign(e, { info: info });
2411
2265
  error = e;
2412
- throw e;
2266
+ // throw e;
2267
+ await _commandError({ text: "visualVerification", operation: "visualVerification", text, info }, e, this);
2413
2268
  }
2414
2269
  finally {
2415
2270
  const endTime = Date.now();
2416
- this._reportToWorld(world, {
2271
+ _reportToWorld(world, {
2417
2272
  type: Types.VERIFY_VISUAL,
2418
2273
  text: "Visual verification",
2419
2274
  screenshotId,
@@ -2422,7 +2277,7 @@ class StableBrowser {
2422
2277
  status: "FAILED",
2423
2278
  startTime,
2424
2279
  endTime,
2425
- message: error === null || error === void 0 ? void 0 : error.message,
2280
+ message: error?.message,
2426
2281
  }
2427
2282
  : {
2428
2283
  status: "PASSED",
@@ -2454,7 +2309,7 @@ class StableBrowser {
2454
2309
  this.logger.info("Table data verified");
2455
2310
  }
2456
2311
  async getTableData(selectors, _params = null, options = {}, world = null) {
2457
- this._validateSelectors(selectors);
2312
+ _validateSelectors(selectors);
2458
2313
  const startTime = Date.now();
2459
2314
  let error = null;
2460
2315
  let screenshotId = null;
@@ -2476,11 +2331,12 @@ class StableBrowser {
2476
2331
  info.screenshotPath = screenshotPath;
2477
2332
  Object.assign(e, { info: info });
2478
2333
  error = e;
2479
- throw e;
2334
+ // throw e;
2335
+ await _commandError({ text: "getTableData", operation: "getTableData", selectors, info }, e, this);
2480
2336
  }
2481
2337
  finally {
2482
2338
  const endTime = Date.now();
2483
- this._reportToWorld(world, {
2339
+ _reportToWorld(world, {
2484
2340
  element_name: selectors.element_name,
2485
2341
  type: Types.GET_TABLE_DATA,
2486
2342
  text: "Get table data",
@@ -2490,7 +2346,7 @@ class StableBrowser {
2490
2346
  status: "FAILED",
2491
2347
  startTime,
2492
2348
  endTime,
2493
- message: error === null || error === void 0 ? void 0 : error.message,
2349
+ message: error?.message,
2494
2350
  }
2495
2351
  : {
2496
2352
  status: "PASSED",
@@ -2502,7 +2358,7 @@ class StableBrowser {
2502
2358
  }
2503
2359
  }
2504
2360
  async analyzeTable(selectors, query, operator, value, _params = null, options = {}, world = null) {
2505
- this._validateSelectors(selectors);
2361
+ _validateSelectors(selectors);
2506
2362
  if (!query) {
2507
2363
  throw new Error("query is null");
2508
2364
  }
@@ -2641,11 +2497,12 @@ class StableBrowser {
2641
2497
  info.screenshotPath = screenshotPath;
2642
2498
  Object.assign(e, { info: info });
2643
2499
  error = e;
2644
- throw e;
2500
+ // throw e;
2501
+ await _commandError({ text: "analyzeTable", operation: "analyzeTable", selectors, query, operator, value }, e, this);
2645
2502
  }
2646
2503
  finally {
2647
2504
  const endTime = Date.now();
2648
- this._reportToWorld(world, {
2505
+ _reportToWorld(world, {
2649
2506
  element_name: selectors.element_name,
2650
2507
  type: Types.ANALYZE_TABLE,
2651
2508
  text: "Analyze table",
@@ -2655,7 +2512,7 @@ class StableBrowser {
2655
2512
  status: "FAILED",
2656
2513
  startTime,
2657
2514
  endTime,
2658
- message: error === null || error === void 0 ? void 0 : error.message,
2515
+ message: error?.message,
2659
2516
  }
2660
2517
  : {
2661
2518
  status: "PASSED",
@@ -2667,27 +2524,7 @@ class StableBrowser {
2667
2524
  }
2668
2525
  }
2669
2526
  async _replaceWithLocalData(value, world, _decrypt = true, totpWait = true) {
2670
- if (!value) {
2671
- return value;
2672
- }
2673
- // find all the accurance of {{(.*?)}} and replace with the value
2674
- let regex = /{{(.*?)}}/g;
2675
- let matches = value.match(regex);
2676
- if (matches) {
2677
- const testData = this.getTestData(world);
2678
- for (let i = 0; i < matches.length; i++) {
2679
- let match = matches[i];
2680
- let key = match.substring(2, match.length - 2);
2681
- let newValue = objectPath.get(testData, key, null);
2682
- if (newValue !== null) {
2683
- value = value.replace(match, newValue);
2684
- }
2685
- }
2686
- }
2687
- if ((value.startsWith("secret:") || value.startsWith("totp:")) && _decrypt) {
2688
- return await decrypt(value, null, totpWait);
2689
- }
2690
- return value;
2527
+ return await replaceWithLocalTestData(value, world, _decrypt, totpWait, this.context, this);
2691
2528
  }
2692
2529
  _getLoadTimeout(options) {
2693
2530
  let timeout = 15000;
@@ -2738,7 +2575,7 @@ class StableBrowser {
2738
2575
  await new Promise((resolve) => setTimeout(resolve, 2000));
2739
2576
  ({ screenshotId, screenshotPath } = await this._screenShot(options, world));
2740
2577
  const endTime = Date.now();
2741
- this._reportToWorld(world, {
2578
+ _reportToWorld(world, {
2742
2579
  type: Types.GET_PAGE_STATUS,
2743
2580
  text: "Wait for page load",
2744
2581
  screenshotId,
@@ -2747,7 +2584,7 @@ class StableBrowser {
2747
2584
  status: "FAILED",
2748
2585
  startTime,
2749
2586
  endTime,
2750
- message: error === null || error === void 0 ? void 0 : error.message,
2587
+ message: error?.message,
2751
2588
  }
2752
2589
  : {
2753
2590
  status: "PASSED",
@@ -2758,41 +2595,35 @@ class StableBrowser {
2758
2595
  }
2759
2596
  }
2760
2597
  async closePage(options = {}, world = null) {
2761
- const startTime = Date.now();
2762
- let error = null;
2763
- let screenshotId = null;
2764
- let screenshotPath = null;
2765
- 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
+ };
2766
2610
  try {
2611
+ await _preCommand(state, this);
2767
2612
  await this.page.close();
2768
2613
  }
2769
2614
  catch (e) {
2770
2615
  console.log(".");
2616
+ await _commandError(state, e, this);
2771
2617
  }
2772
2618
  finally {
2773
- await new Promise((resolve) => setTimeout(resolve, 2000));
2774
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world));
2775
- const endTime = Date.now();
2776
- this._reportToWorld(world, {
2777
- type: Types.CLOSE_PAGE,
2778
- text: "close page",
2779
- screenshotId,
2780
- result: error
2781
- ? {
2782
- status: "FAILED",
2783
- startTime,
2784
- endTime,
2785
- message: error === null || error === void 0 ? void 0 : error.message,
2786
- }
2787
- : {
2788
- status: "PASSED",
2789
- startTime,
2790
- endTime,
2791
- },
2792
- info: info,
2793
- });
2619
+ _commandFinally(state, this);
2794
2620
  }
2795
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
+ }
2796
2627
  async setViewportSize(width, hight, options = {}, world = null) {
2797
2628
  const startTime = Date.now();
2798
2629
  let error = null;
@@ -2810,12 +2641,13 @@ class StableBrowser {
2810
2641
  }
2811
2642
  catch (e) {
2812
2643
  console.log(".");
2644
+ await _commandError({ text: "setViewportSize", operation: "setViewportSize", width, hight, info }, e, this);
2813
2645
  }
2814
2646
  finally {
2815
2647
  await new Promise((resolve) => setTimeout(resolve, 2000));
2816
2648
  ({ screenshotId, screenshotPath } = await this._screenShot(options, world));
2817
2649
  const endTime = Date.now();
2818
- this._reportToWorld(world, {
2650
+ _reportToWorld(world, {
2819
2651
  type: Types.SET_VIEWPORT,
2820
2652
  text: "set viewport size to " + width + "x" + hight,
2821
2653
  screenshotId,
@@ -2824,7 +2656,7 @@ class StableBrowser {
2824
2656
  status: "FAILED",
2825
2657
  startTime,
2826
2658
  endTime,
2827
- message: error === null || error === void 0 ? void 0 : error.message,
2659
+ message: error?.message,
2828
2660
  }
2829
2661
  : {
2830
2662
  status: "PASSED",
@@ -2846,12 +2678,13 @@ class StableBrowser {
2846
2678
  }
2847
2679
  catch (e) {
2848
2680
  console.log(".");
2681
+ await _commandError({ text: "reloadPage", operation: "reloadPage", info }, e, this);
2849
2682
  }
2850
2683
  finally {
2851
2684
  await new Promise((resolve) => setTimeout(resolve, 2000));
2852
2685
  ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
2853
2686
  const endTime = Date.now();
2854
- this._reportToWorld(world, {
2687
+ _reportToWorld(world, {
2855
2688
  type: Types.GET_PAGE_STATUS,
2856
2689
  text: "page relaod",
2857
2690
  screenshotId,
@@ -2860,7 +2693,7 @@ class StableBrowser {
2860
2693
  status: "FAILED",
2861
2694
  startTime,
2862
2695
  endTime,
2863
- message: error === null || error === void 0 ? void 0 : error.message,
2696
+ message: error?.message,
2864
2697
  }
2865
2698
  : {
2866
2699
  status: "PASSED",
@@ -2887,11 +2720,37 @@ class StableBrowser {
2887
2720
  console.log("#-#");
2888
2721
  }
2889
2722
  }
2890
- _reportToWorld(world, properties) {
2891
- if (!world || !world.attach) {
2892
- 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
+ }
2893
2753
  }
2894
- world.attach(JSON.stringify(properties), { mediaType: "application/json" });
2895
2754
  }
2896
2755
  }
2897
2756
  function createTimedPromise(promise, label) {