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