automation_model 1.0.453-dev → 1.0.453-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.
@@ -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 } 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,26 @@ 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";
48
61
  constructor(browser, page, logger = null, context = null, world = null) {
49
62
  this.browser = browser;
50
63
  this.page = page;
51
64
  this.logger = logger;
52
65
  this.context = context;
53
66
  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
67
  if (!this.logger) {
60
68
  this.logger = console;
61
69
  }
@@ -80,11 +88,13 @@ class StableBrowser {
80
88
  catch (e) {
81
89
  this.logger.error("unable to read ai_config.json");
82
90
  }
83
- context.pageLoading = { status: false };
84
- context.pages = [this.page];
85
91
  const logFolder = path.join(this.project_path, "logs", "web");
86
92
  this.world = world;
93
+ context.pages = [this.page];
94
+ context.pageLoading = { status: false };
87
95
  this.registerEventListeners(this.context);
96
+ registerNetworkEvents(this.world, this, this.context, this.page);
97
+ registerDownloadEvent(this.page, this.world, this.context);
88
98
  }
89
99
  registerEventListeners(context) {
90
100
  this.registerConsoleLogListener(this.page, context);
@@ -93,10 +103,17 @@ class StableBrowser {
93
103
  context.pageLoading = { status: false };
94
104
  }
95
105
  context.playContext.on("page", async function (page) {
106
+ if (this.configuration && this.configuration.closePopups === true) {
107
+ console.log("close unexpected popups");
108
+ await page.close();
109
+ return;
110
+ }
96
111
  context.pageLoading.status = true;
97
112
  this.page = page;
98
113
  context.page = page;
99
114
  context.pages.push(page);
115
+ registerNetworkEvents(this.world, this, context, this.page);
116
+ registerDownloadEvent(this.page, this.world, context);
100
117
  page.on("close", async () => {
101
118
  if (this.context && this.context.pages && this.context.pages.length > 1) {
102
119
  this.context.pages.pop();
@@ -126,9 +143,9 @@ class StableBrowser {
126
143
  if (this.appName === appName) {
127
144
  return;
128
145
  }
129
- let newContextCreated = false;
146
+ let navigate = false;
130
147
  if (!apps[appName]) {
131
- let newContext = await getContext(null, this.context.headless ? this.context.headless : false, this, this.logger, appName, false, this);
148
+ let newContext = await getContext(null, this.context.headless ? this.context.headless : false, this, this.logger, appName, false, this, -1, this.context.reportFolder);
132
149
  newContextCreated = true;
133
150
  apps[appName] = {
134
151
  context: newContext,
@@ -141,8 +158,7 @@ class StableBrowser {
141
158
  this._copyContext(apps[appName], this);
142
159
  apps[this.appName] = tempContext;
143
160
  this.appName = appName;
144
- if (newContextCreated) {
145
- this.registerEventListeners(this.context);
161
+ if (navigate) {
146
162
  await this.goto(this.context.environment.baseUrl);
147
163
  await this.waitForPageLoad();
148
164
  }
@@ -168,7 +184,6 @@ class StableBrowser {
168
184
  this.context.webLogger = [];
169
185
  }
170
186
  page.on("console", async (msg) => {
171
- var _a;
172
187
  const obj = {
173
188
  type: msg.type(),
174
189
  text: msg.text(),
@@ -176,7 +191,9 @@ class StableBrowser {
176
191
  time: new Date().toISOString(),
177
192
  };
178
193
  this.context.webLogger.push(obj);
179
- (_a = this.world) === null || _a === void 0 ? void 0 : _a.attach(JSON.stringify(obj), { mediaType: "application/json+log" });
194
+ if (msg.type() === "error") {
195
+ this.world?.attach(JSON.stringify(obj), { mediaType: "application/json+log" });
196
+ }
180
197
  });
181
198
  }
182
199
  registerRequestListener(page, context, logFile) {
@@ -184,7 +201,6 @@ class StableBrowser {
184
201
  this.context.networkLogger = [];
185
202
  }
186
203
  page.on("request", async (data) => {
187
- var _a;
188
204
  const startTime = new Date().getTime();
189
205
  try {
190
206
  const pageUrl = new URL(page.url());
@@ -209,7 +225,7 @@ class StableBrowser {
209
225
  startTime,
210
226
  };
211
227
  context.networkLogger.push(obj);
212
- (_a = this.world) === null || _a === void 0 ? void 0 : _a.attach(JSON.stringify(obj), { mediaType: "application/json+network" });
228
+ this.world?.attach(JSON.stringify(obj), { mediaType: "application/json+network" });
213
229
  }
214
230
  catch (error) {
215
231
  console.error("Error in request listener", error);
@@ -234,20 +250,6 @@ class StableBrowser {
234
250
  timeout: 60000,
235
251
  });
236
252
  }
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
253
  _fixUsingParams(text, _params) {
252
254
  if (!_params || typeof text !== "string") {
253
255
  return text;
@@ -315,7 +317,7 @@ class StableBrowser {
315
317
  locatorReturn = scope.getByRole(role, { name }, { exact: flags === "i" });
316
318
  }
317
319
  }
318
- if (locator === null || locator === void 0 ? void 0 : locator.engine) {
320
+ if (locator?.engine) {
319
321
  if (locator.engine === "css") {
320
322
  locatorReturn = scope.locator(locator.selector);
321
323
  }
@@ -336,7 +338,10 @@ class StableBrowser {
336
338
  return locatorReturn;
337
339
  }
338
340
  async _locateElmentByTextClimbCss(scope, text, climb, css, _params) {
339
- let result = await this._locateElementByText(scope, this._fixUsingParams(text, _params), "*", false, true, _params);
341
+ if (css && css.locator) {
342
+ css = css.locator;
343
+ }
344
+ let result = await this._locateElementByText(scope, this._fixUsingParams(text, _params), "*:not(script, style, head)", false, false, _params);
340
345
  if (result.elementCount === 0) {
341
346
  return;
342
347
  }
@@ -351,7 +356,7 @@ class StableBrowser {
351
356
  }
352
357
  async _locateElementByText(scope, text1, tag1, regex1 = false, partial1, _params) {
353
358
  //const stringifyText = JSON.stringify(text);
354
- return await scope.evaluate(([text, tag, regex, partial]) => {
359
+ return await scope.locator(":root").evaluate((_node, [text, tag, regex, partial]) => {
355
360
  function isParent(parent, child) {
356
361
  let currentNode = child.parentNode;
357
362
  while (currentNode !== null) {
@@ -363,6 +368,15 @@ class StableBrowser {
363
368
  return false;
364
369
  }
365
370
  document.isParent = isParent;
371
+ function getRegex(str) {
372
+ const match = str.match(/^\/(.*?)\/([gimuy]*)$/);
373
+ if (!match) {
374
+ return null;
375
+ }
376
+ let [_, pattern, flags] = match;
377
+ return new RegExp(pattern, flags);
378
+ }
379
+ document.getRegex = getRegex;
366
380
  function collectAllShadowDomElements(element, result = []) {
367
381
  // Check and add the element if it has a shadow root
368
382
  if (element.shadowRoot) {
@@ -379,7 +393,11 @@ class StableBrowser {
379
393
  }
380
394
  document.collectAllShadowDomElements = collectAllShadowDomElements;
381
395
  if (!tag) {
382
- tag = "*";
396
+ tag = "*:not(script, style, head)";
397
+ }
398
+ let regexpSearch = document.getRegex(text);
399
+ if (regexpSearch) {
400
+ regex = true;
383
401
  }
384
402
  let elements = Array.from(document.querySelectorAll(tag));
385
403
  let shadowHosts = [];
@@ -396,7 +414,9 @@ class StableBrowser {
396
414
  let randomToken = null;
397
415
  const foundElements = [];
398
416
  if (regex) {
399
- let regexpSearch = new RegExp(text, "im");
417
+ if (!regexpSearch) {
418
+ regexpSearch = new RegExp(text, "im");
419
+ }
400
420
  for (let i = 0; i < elements.length; i++) {
401
421
  const element = elements[i];
402
422
  if ((element.innerText && regexpSearch.test(element.innerText)) ||
@@ -410,8 +430,8 @@ class StableBrowser {
410
430
  for (let i = 0; i < elements.length; i++) {
411
431
  const element = elements[i];
412
432
  if (partial) {
413
- if ((element.innerText && element.innerText.trim().includes(text)) ||
414
- (element.value && element.value.includes(text))) {
433
+ if ((element.innerText && element.innerText.toLowerCase().trim().includes(text.toLowerCase())) ||
434
+ (element.value && element.value.toLowerCase().includes(text.toLowerCase()))) {
415
435
  foundElements.push(element);
416
436
  }
417
437
  }
@@ -456,18 +476,29 @@ class StableBrowser {
456
476
  }
457
477
  async _collectLocatorInformation(selectorHierarchy, index = 0, scope, foundLocators, _params, info, visibleOnly = true) {
458
478
  let locatorSearch = selectorHierarchy[index];
479
+ try {
480
+ locatorSearch = JSON.parse(this._fixUsingParams(JSON.stringify(locatorSearch), _params));
481
+ }
482
+ catch (e) {
483
+ console.error(e);
484
+ }
459
485
  //info.log += "searching for locator " + JSON.stringify(locatorSearch) + "\n";
460
486
  let locator = null;
461
487
  if (locatorSearch.climb && locatorSearch.climb >= 0) {
462
488
  let locatorString = await this._locateElmentByTextClimbCss(scope, locatorSearch.text, locatorSearch.climb, locatorSearch.css, _params);
463
489
  if (!locatorString) {
490
+ info.failCause.textNotFound = true;
491
+ info.failCause.lastError = "failed to locate element by text: " + locatorSearch.text;
464
492
  return;
465
493
  }
466
494
  locator = this._getLocator({ css: locatorString }, scope, _params);
467
495
  }
468
496
  else if (locatorSearch.text) {
469
- let result = await this._locateElementByText(scope, this._fixUsingParams(locatorSearch.text, _params), locatorSearch.tag, false, locatorSearch.partial === true, _params);
497
+ let text = this._fixUsingParams(locatorSearch.text, _params);
498
+ let result = await this._locateElementByText(scope, text, locatorSearch.tag, false, locatorSearch.partial === true, _params);
470
499
  if (result.elementCount === 0) {
500
+ info.failCause.textNotFound = true;
501
+ info.failCause.lastError = "failed to locate element by text: " + text;
471
502
  return;
472
503
  }
473
504
  locatorSearch.css = "[data-blinq-id='blinq-id-" + result.randomToken + "']";
@@ -484,6 +515,9 @@ class StableBrowser {
484
515
  // cssHref = true;
485
516
  // }
486
517
  let count = await locator.count();
518
+ if (count > 0 && !info.failCause.count) {
519
+ info.failCause.count = count;
520
+ }
487
521
  //info.log += "total elements found " + count + "\n";
488
522
  //let visibleCount = 0;
489
523
  let visibleLocator = null;
@@ -501,6 +535,8 @@ class StableBrowser {
501
535
  foundLocators.push(locator.nth(j));
502
536
  }
503
537
  else {
538
+ info.failCause.visible = visible;
539
+ info.failCause.enabled = enabled;
504
540
  if (!info.printMessages) {
505
541
  info.printMessages = {};
506
542
  }
@@ -512,6 +548,11 @@ class StableBrowser {
512
548
  }
513
549
  }
514
550
  async closeUnexpectedPopups(info, _params) {
551
+ if (!info) {
552
+ info = {};
553
+ info.failCause = {};
554
+ info.log = "";
555
+ }
515
556
  if (this.configuration.popupHandlers && this.configuration.popupHandlers.length > 0) {
516
557
  if (!info) {
517
558
  info = {};
@@ -552,7 +593,10 @@ class StableBrowser {
552
593
  }
553
594
  return { rerun: false };
554
595
  }
555
- async _locate(selectors, info, _params, timeout = 30000) {
596
+ async _locate(selectors, info, _params, timeout) {
597
+ if (!timeout) {
598
+ timeout = 30000;
599
+ }
556
600
  for (let i = 0; i < 3; i++) {
557
601
  info.log += "attempt " + i + ": total locators " + selectors.locators.length + "\n";
558
602
  for (let j = 0; j < selectors.locators.length; j++) {
@@ -566,32 +610,46 @@ class StableBrowser {
566
610
  }
567
611
  throw new Error("unable to locate element " + JSON.stringify(selectors));
568
612
  }
569
- async _locate_internal(selectors, info, _params, timeout = 30000) {
570
- let highPriorityTimeout = 5000;
571
- let visibleOnlyTimeout = 6000;
572
- let startTime = performance.now();
573
- let locatorsCount = 0;
574
- //let arrayMode = Array.isArray(selectors);
613
+ async _findFrameScope(selectors, timeout = 30000, info) {
614
+ if (!info) {
615
+ info = {};
616
+ info.failCause = {};
617
+ info.log = "";
618
+ }
575
619
  let scope = this.page;
620
+ if (selectors.frame) {
621
+ return selectors.frame;
622
+ }
576
623
  if (selectors.iframe_src || selectors.frameLocators) {
577
- const findFrame = (frame, framescope) => {
624
+ const findFrame = async (frame, framescope) => {
578
625
  for (let i = 0; i < frame.selectors.length; i++) {
579
626
  let frameLocator = frame.selectors[i];
580
627
  if (frameLocator.css) {
581
- framescope = framescope.frameLocator(frameLocator.css);
582
- break;
628
+ let testframescope = framescope.frameLocator(frameLocator.css);
629
+ if (frameLocator.index) {
630
+ testframescope = framescope.nth(frameLocator.index);
631
+ }
632
+ try {
633
+ await testframescope.owner().evaluateHandle(() => true, null, {
634
+ timeout: 5000,
635
+ });
636
+ framescope = testframescope;
637
+ break;
638
+ }
639
+ catch (error) {
640
+ console.error("frame not found " + frameLocator.css);
641
+ }
583
642
  }
584
643
  }
585
644
  if (frame.children) {
586
- return findFrame(frame.children, framescope);
645
+ return await findFrame(frame.children, framescope);
587
646
  }
588
647
  return framescope;
589
648
  };
590
- info.log += "searching for iframe " + selectors.iframe_src + "/" + selectors.frameLocators + "\n";
591
649
  while (true) {
592
650
  let frameFound = false;
593
651
  if (selectors.nestFrmLoc) {
594
- scope = findFrame(selectors.nestFrmLoc, scope);
652
+ scope = await findFrame(selectors.nestFrmLoc, scope);
595
653
  frameFound = true;
596
654
  break;
597
655
  }
@@ -611,6 +669,8 @@ class StableBrowser {
611
669
  if (!scope) {
612
670
  info.log += "unable to locate iframe " + selectors.iframe_src + "\n";
613
671
  if (performance.now() - startTime > timeout) {
672
+ info.failCause.iframeNotFound = true;
673
+ info.failCause.lastError = "unable to locate iframe " + selectors.iframe_src;
614
674
  throw new Error("unable to locate iframe " + selectors.iframe_src);
615
675
  }
616
676
  await new Promise((resolve) => setTimeout(resolve, 1000));
@@ -620,6 +680,30 @@ class StableBrowser {
620
680
  }
621
681
  }
622
682
  }
683
+ if (!scope) {
684
+ scope = this.page;
685
+ }
686
+ return scope;
687
+ }
688
+ async _getDocumentBody(selectors, timeout = 30000, info) {
689
+ let scope = await this._findFrameScope(selectors, timeout, info);
690
+ return scope.evaluate(() => {
691
+ var bodyContent = document.body.innerHTML;
692
+ return bodyContent;
693
+ });
694
+ }
695
+ async _locate_internal(selectors, info, _params, timeout = 30000) {
696
+ if (!info) {
697
+ info = {};
698
+ info.failCause = {};
699
+ info.log = "";
700
+ }
701
+ let highPriorityTimeout = 5000;
702
+ let visibleOnlyTimeout = 6000;
703
+ let startTime = performance.now();
704
+ let locatorsCount = 0;
705
+ //let arrayMode = Array.isArray(selectors);
706
+ let scope = await this._findFrameScope(selectors, timeout, info);
623
707
  let selectorsLocators = null;
624
708
  selectorsLocators = selectors.locators;
625
709
  // group selectors by priority
@@ -721,6 +805,8 @@ class StableBrowser {
721
805
  }
722
806
  this.logger.debug("unable to locate unique element, total elements found " + locatorsCount);
723
807
  info.log += "failed to locate unique element, total elements found " + locatorsCount + "\n";
808
+ info.failCause.locatorNotFound = true;
809
+ info.failCause.lastError = "failed to locate unique element";
724
810
  throw new Error("failed to locate first element no elements found, " + info.log);
725
811
  }
726
812
  async _scanLocatorsGroup(locatorsGroup, scope, _params, info, visibleOnly) {
@@ -752,89 +838,129 @@ class StableBrowser {
752
838
  });
753
839
  result.locatorIndex = i;
754
840
  }
841
+ if (foundLocators.length > 1) {
842
+ info.failCause.foundMultiple = true;
843
+ }
755
844
  }
756
845
  return result;
757
846
  }
758
- async click(selectors, _params, options = {}, world = null) {
759
- this._validateSelectors(selectors);
847
+ async simpleClick(elementDescription, _params, options = {}, world = null) {
760
848
  const startTime = Date.now();
761
- if (options && options.context) {
762
- selectors.locators[0].text = options.context;
849
+ let timeout = 30000;
850
+ if (options && options.timeout) {
851
+ timeout = options.timeout;
763
852
  }
764
- const info = {};
765
- info.log = "***** click on " + selectors.element_name + " *****\n";
766
- info.operation = "click";
767
- info.selectors = selectors;
768
- let error = null;
769
- let screenshotId = null;
770
- let screenshotPath = null;
853
+ while (true) {
854
+ try {
855
+ const result = await locate_element(this.context, elementDescription, "click");
856
+ if (result?.elementNumber >= 0) {
857
+ const selectors = {
858
+ frame: result?.frame,
859
+ locators: [
860
+ {
861
+ css: result?.css,
862
+ },
863
+ ],
864
+ };
865
+ await this.click(selectors, _params, options, world);
866
+ return;
867
+ }
868
+ }
869
+ catch (e) {
870
+ if (performance.now() - startTime > timeout) {
871
+ // throw e;
872
+ await _commandError({ text: "simpleClick", operation: "simpleClick", elementDescription, info: {} }, e, this);
873
+ }
874
+ }
875
+ await new Promise((resolve) => setTimeout(resolve, 3000));
876
+ }
877
+ }
878
+ async simpleClickType(elementDescription, value, _params, options = {}, world = null) {
879
+ const startTime = Date.now();
880
+ let timeout = 30000;
881
+ if (options && options.timeout) {
882
+ timeout = options.timeout;
883
+ }
884
+ while (true) {
885
+ try {
886
+ const result = await locate_element(this.context, elementDescription, "fill", value);
887
+ if (result?.elementNumber >= 0) {
888
+ const selectors = {
889
+ frame: result?.frame,
890
+ locators: [
891
+ {
892
+ css: result?.css,
893
+ },
894
+ ],
895
+ };
896
+ await this.clickType(selectors, value, false, _params, options, world);
897
+ return;
898
+ }
899
+ }
900
+ catch (e) {
901
+ if (performance.now() - startTime > timeout) {
902
+ // throw e;
903
+ await _commandError({ text: "simpleClickType", operation: "simpleClickType", value, elementDescription, info: {} }, e, this);
904
+ }
905
+ }
906
+ await new Promise((resolve) => setTimeout(resolve, 3000));
907
+ }
908
+ }
909
+ async click(selectors, _params, options = {}, world = null) {
910
+ const state = {
911
+ selectors,
912
+ _params,
913
+ options,
914
+ world,
915
+ text: "Click element",
916
+ type: Types.CLICK,
917
+ operation: "click",
918
+ log: "***** click on " + selectors.element_name + " *****\n",
919
+ };
771
920
  try {
772
- let element = await this._locate(selectors, info, _params);
773
- await this.scrollIfNeeded(element, info);
774
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
921
+ await _preCommand(state, this);
922
+ if (state.options && state.options.context) {
923
+ state.selectors.locators[0].text = state.options.context;
924
+ }
775
925
  try {
776
- await this._highlightElements(element);
777
- await element.click();
926
+ await state.element.click();
778
927
  await new Promise((resolve) => setTimeout(resolve, 1000));
779
928
  }
780
929
  catch (e) {
781
930
  // await this.closeUnexpectedPopups();
782
- info.log += "click failed, will try again" + "\n";
783
- element = await this._locate(selectors, info, _params);
784
- await element.dispatchEvent("click");
931
+ state.element = await this._locate(selectors, state.info, _params);
932
+ await state.element.dispatchEvent("click");
785
933
  await new Promise((resolve) => setTimeout(resolve, 1000));
786
934
  }
787
935
  await this.waitForPageLoad();
788
- return info;
936
+ return state.info;
789
937
  }
790
938
  catch (e) {
791
- this.logger.error("click failed " + info.log);
792
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
793
- info.screenshotPath = screenshotPath;
794
- Object.assign(e, { info: info });
795
- error = e;
796
- throw e;
939
+ await _commandError(state, e, this);
797
940
  }
798
941
  finally {
799
- const endTime = Date.now();
800
- this._reportToWorld(world, {
801
- element_name: selectors.element_name,
802
- type: Types.CLICK,
803
- text: `Click element`,
804
- screenshotId,
805
- result: error
806
- ? {
807
- status: "FAILED",
808
- startTime,
809
- endTime,
810
- message: error === null || error === void 0 ? void 0 : error.message,
811
- }
812
- : {
813
- status: "PASSED",
814
- startTime,
815
- endTime,
816
- },
817
- info: info,
818
- });
942
+ _commandFinally(state, this);
819
943
  }
820
944
  }
821
945
  async setCheck(selectors, checked = true, _params, options = {}, world = null) {
822
- this._validateSelectors(selectors);
823
- const startTime = Date.now();
824
- const info = {};
825
- info.log = "";
826
- info.operation = "setCheck";
827
- info.checked = checked;
828
- info.selectors = selectors;
829
- let error = null;
830
- let screenshotId = null;
831
- let screenshotPath = null;
946
+ const state = {
947
+ selectors,
948
+ _params,
949
+ options,
950
+ world,
951
+ type: checked ? Types.CHECK : Types.UNCHECK,
952
+ text: checked ? `Check element` : `Uncheck element`,
953
+ operation: "setCheck",
954
+ log: "***** check " + selectors.element_name + " *****\n",
955
+ };
832
956
  try {
833
- let element = await this._locate(selectors, info, _params);
834
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
957
+ await _preCommand(state, this);
958
+ state.info.checked = checked;
959
+ // let element = await this._locate(selectors, info, _params);
960
+ // ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
835
961
  try {
836
- await this._highlightElements(element);
837
- await element.setChecked(checked);
962
+ // await this._highlightElements(element);
963
+ await state.element.setChecked(checked);
838
964
  await new Promise((resolve) => setTimeout(resolve, 1000));
839
965
  }
840
966
  catch (e) {
@@ -843,179 +969,108 @@ class StableBrowser {
843
969
  }
844
970
  else {
845
971
  //await this.closeUnexpectedPopups();
846
- info.log += "setCheck failed, will try again" + "\n";
847
- element = await this._locate(selectors, info, _params);
848
- await element.setChecked(checked, { timeout: 5000, force: true });
972
+ state.info.log += "setCheck failed, will try again" + "\n";
973
+ state.element = await this._locate(selectors, state.info, _params);
974
+ await state.element.setChecked(checked, { timeout: 5000, force: true });
849
975
  await new Promise((resolve) => setTimeout(resolve, 1000));
850
976
  }
851
977
  }
852
978
  await this.waitForPageLoad();
853
- return info;
979
+ return state.info;
854
980
  }
855
981
  catch (e) {
856
- this.logger.error("setCheck failed " + info.log);
857
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
858
- info.screenshotPath = screenshotPath;
859
- Object.assign(e, { info: info });
860
- error = e;
861
- throw e;
982
+ await _commandError(state, e, this);
862
983
  }
863
984
  finally {
864
- const endTime = Date.now();
865
- this._reportToWorld(world, {
866
- element_name: selectors.element_name,
867
- type: checked ? Types.CHECK : Types.UNCHECK,
868
- text: checked ? `Check element` : `Uncheck element`,
869
- screenshotId,
870
- result: error
871
- ? {
872
- status: "FAILED",
873
- startTime,
874
- endTime,
875
- message: error === null || error === void 0 ? void 0 : error.message,
876
- }
877
- : {
878
- status: "PASSED",
879
- startTime,
880
- endTime,
881
- },
882
- info: info,
883
- });
985
+ _commandFinally(state, this);
884
986
  }
885
987
  }
886
988
  async hover(selectors, _params, options = {}, world = null) {
887
- this._validateSelectors(selectors);
888
- const startTime = Date.now();
889
- const info = {};
890
- info.log = "";
891
- info.operation = "hover";
892
- info.selectors = selectors;
893
- let error = null;
894
- let screenshotId = null;
895
- let screenshotPath = null;
989
+ const state = {
990
+ selectors,
991
+ _params,
992
+ options,
993
+ world,
994
+ type: Types.HOVER,
995
+ text: `Hover element`,
996
+ operation: "hover",
997
+ log: "***** hover " + selectors.element_name + " *****\n",
998
+ };
896
999
  try {
897
- let element = await this._locate(selectors, info, _params);
898
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1000
+ await _preCommand(state, this);
899
1001
  try {
900
- await this._highlightElements(element);
901
- await element.hover();
1002
+ await state.element.hover();
902
1003
  await new Promise((resolve) => setTimeout(resolve, 1000));
903
1004
  }
904
1005
  catch (e) {
905
1006
  //await this.closeUnexpectedPopups();
906
- info.log += "hover failed, will try again" + "\n";
907
- element = await this._locate(selectors, info, _params);
908
- await element.hover({ timeout: 10000 });
1007
+ state.info.log += "hover failed, will try again" + "\n";
1008
+ state.element = await this._locate(selectors, state.info, _params);
1009
+ await state.element.hover({ timeout: 10000 });
909
1010
  await new Promise((resolve) => setTimeout(resolve, 1000));
910
1011
  }
911
1012
  await this.waitForPageLoad();
912
- return info;
1013
+ return state.info;
913
1014
  }
914
1015
  catch (e) {
915
- this.logger.error("hover failed " + info.log);
916
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
917
- info.screenshotPath = screenshotPath;
918
- Object.assign(e, { info: info });
919
- error = e;
920
- throw e;
1016
+ await _commandError(state, e, this);
921
1017
  }
922
1018
  finally {
923
- const endTime = Date.now();
924
- this._reportToWorld(world, {
925
- element_name: selectors.element_name,
926
- type: Types.HOVER,
927
- text: `Hover element`,
928
- screenshotId,
929
- result: error
930
- ? {
931
- status: "FAILED",
932
- startTime,
933
- endTime,
934
- message: error === null || error === void 0 ? void 0 : error.message,
935
- }
936
- : {
937
- status: "PASSED",
938
- startTime,
939
- endTime,
940
- },
941
- info: info,
942
- });
1019
+ _commandFinally(state, this);
943
1020
  }
944
1021
  }
945
1022
  async selectOption(selectors, values, _params = null, options = {}, world = null) {
946
- this._validateSelectors(selectors);
947
1023
  if (!values) {
948
1024
  throw new Error("values is null");
949
1025
  }
950
- const startTime = Date.now();
951
- let error = null;
952
- let screenshotId = null;
953
- let screenshotPath = null;
954
- const info = {};
955
- info.log = "";
956
- info.operation = "selectOptions";
957
- info.selectors = selectors;
1026
+ const state = {
1027
+ selectors,
1028
+ _params,
1029
+ options,
1030
+ world,
1031
+ value: values.toString(),
1032
+ type: Types.SELECT,
1033
+ text: `Select option: ${values}`,
1034
+ operation: "selectOption",
1035
+ log: "***** select option " + selectors.element_name + " *****\n",
1036
+ };
958
1037
  try {
959
- let element = await this._locate(selectors, info, _params);
960
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1038
+ await _preCommand(state, this);
961
1039
  try {
962
- await this._highlightElements(element);
963
- await element.selectOption(values);
1040
+ await state.element.selectOption(values);
964
1041
  }
965
1042
  catch (e) {
966
1043
  //await this.closeUnexpectedPopups();
967
- info.log += "selectOption failed, will try force" + "\n";
968
- await element.selectOption(values, { timeout: 10000, force: true });
1044
+ state.info.log += "selectOption failed, will try force" + "\n";
1045
+ await state.element.selectOption(values, { timeout: 10000, force: true });
969
1046
  }
970
1047
  await this.waitForPageLoad();
971
- return info;
1048
+ return state.info;
972
1049
  }
973
1050
  catch (e) {
974
- this.logger.error("selectOption failed " + info.log);
975
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
976
- info.screenshotPath = screenshotPath;
977
- Object.assign(e, { info: info });
978
- this.logger.info("click failed, will try next selector");
979
- error = e;
980
- throw e;
1051
+ await _commandError(state, e, this);
981
1052
  }
982
1053
  finally {
983
- const endTime = Date.now();
984
- this._reportToWorld(world, {
985
- element_name: selectors.element_name,
986
- type: Types.SELECT,
987
- text: `Select option: ${values}`,
988
- value: values.toString(),
989
- screenshotId,
990
- result: error
991
- ? {
992
- status: "FAILED",
993
- startTime,
994
- endTime,
995
- message: error === null || error === void 0 ? void 0 : error.message,
996
- }
997
- : {
998
- status: "PASSED",
999
- startTime,
1000
- endTime,
1001
- },
1002
- info: info,
1003
- });
1054
+ _commandFinally(state, this);
1004
1055
  }
1005
1056
  }
1006
1057
  async type(_value, _params = null, options = {}, world = null) {
1007
- const startTime = Date.now();
1008
- let error = null;
1009
- let screenshotId = null;
1010
- let screenshotPath = null;
1011
- const info = {};
1012
- info.log = "";
1013
- info.operation = "type";
1014
- _value = this._fixUsingParams(_value, _params);
1015
- info.value = _value;
1058
+ const state = {
1059
+ value: _value,
1060
+ _params,
1061
+ options,
1062
+ world,
1063
+ locate: false,
1064
+ scroll: false,
1065
+ highlight: false,
1066
+ type: Types.TYPE_PRESS,
1067
+ text: `Type value: ${_value}`,
1068
+ operation: "type",
1069
+ log: "",
1070
+ };
1016
1071
  try {
1017
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1018
- const valueSegment = _value.split("&&");
1072
+ await _preCommand(state, this);
1073
+ const valueSegment = state.value.split("&&");
1019
1074
  for (let i = 0; i < valueSegment.length; i++) {
1020
1075
  if (i > 0) {
1021
1076
  await new Promise((resolve) => setTimeout(resolve, 1000));
@@ -1035,134 +1090,76 @@ class StableBrowser {
1035
1090
  await this.page.keyboard.type(value);
1036
1091
  }
1037
1092
  }
1038
- return info;
1093
+ return state.info;
1039
1094
  }
1040
1095
  catch (e) {
1041
- //await this.closeUnexpectedPopups();
1042
- this.logger.error("type failed " + info.log);
1043
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1044
- info.screenshotPath = screenshotPath;
1045
- Object.assign(e, { info: info });
1046
- error = e;
1047
- throw e;
1096
+ await _commandError(state, e, this);
1048
1097
  }
1049
1098
  finally {
1050
- const endTime = Date.now();
1051
- this._reportToWorld(world, {
1052
- type: Types.TYPE_PRESS,
1053
- screenshotId,
1054
- value: _value,
1055
- text: `type value: ${_value}`,
1056
- result: error
1057
- ? {
1058
- status: "FAILED",
1059
- startTime,
1060
- endTime,
1061
- message: error === null || error === void 0 ? void 0 : error.message,
1062
- }
1063
- : {
1064
- status: "PASSED",
1065
- startTime,
1066
- endTime,
1067
- },
1068
- info: info,
1069
- });
1099
+ _commandFinally(state, this);
1070
1100
  }
1071
1101
  }
1072
1102
  async setInputValue(selectors, value, _params = null, options = {}, world = null) {
1073
- // set input value for non fillable inputs like date, time, range, color, etc.
1074
- this._validateSelectors(selectors);
1075
- const startTime = Date.now();
1076
- const info = {};
1077
- info.log = "***** set input value " + selectors.element_name + " *****\n";
1078
- info.operation = "setInputValue";
1079
- info.selectors = selectors;
1080
- value = this._fixUsingParams(value, _params);
1081
- info.value = value;
1082
- let error = null;
1083
- let screenshotId = null;
1084
- let screenshotPath = null;
1103
+ const state = {
1104
+ selectors,
1105
+ _params,
1106
+ value,
1107
+ options,
1108
+ world,
1109
+ type: Types.SET_INPUT,
1110
+ text: `Set input value`,
1111
+ operation: "setInputValue",
1112
+ log: "***** set input value " + selectors.element_name + " *****\n",
1113
+ };
1085
1114
  try {
1086
- value = await this._replaceWithLocalData(value, this);
1087
- let element = await this._locate(selectors, info, _params);
1088
- await this.scrollIfNeeded(element, info);
1089
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1090
- await this._highlightElements(element);
1115
+ await _preCommand(state, this);
1116
+ let value = await this._replaceWithLocalData(state.value, this);
1091
1117
  try {
1092
- await element.evaluateHandle((el, value) => {
1118
+ await state.element.evaluateHandle((el, value) => {
1093
1119
  el.value = value;
1094
1120
  }, value);
1095
1121
  }
1096
1122
  catch (error) {
1097
1123
  this.logger.error("setInputValue failed, will try again");
1098
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1099
- info.screenshotPath = screenshotPath;
1100
- Object.assign(error, { info: info });
1101
- await element.evaluateHandle((el, value) => {
1124
+ await _screenshot(state, this);
1125
+ Object.assign(error, { info: state.info });
1126
+ await state.element.evaluateHandle((el, value) => {
1102
1127
  el.value = value;
1103
1128
  });
1104
1129
  }
1105
1130
  }
1106
1131
  catch (e) {
1107
- this.logger.error("setInputValue failed " + info.log);
1108
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1109
- info.screenshotPath = screenshotPath;
1110
- Object.assign(e, { info: info });
1111
- error = e;
1112
- throw e;
1132
+ await _commandError(state, e, this);
1113
1133
  }
1114
1134
  finally {
1115
- const endTime = Date.now();
1116
- this._reportToWorld(world, {
1117
- element_name: selectors.element_name,
1118
- type: Types.SET_INPUT,
1119
- text: `Set input value`,
1120
- value: value,
1121
- screenshotId,
1122
- result: error
1123
- ? {
1124
- status: "FAILED",
1125
- startTime,
1126
- endTime,
1127
- message: error === null || error === void 0 ? void 0 : error.message,
1128
- }
1129
- : {
1130
- status: "PASSED",
1131
- startTime,
1132
- endTime,
1133
- },
1134
- info: info,
1135
- });
1135
+ _commandFinally(state, this);
1136
1136
  }
1137
1137
  }
1138
1138
  async setDateTime(selectors, value, format = null, enter = false, _params = null, options = {}, world = null) {
1139
- this._validateSelectors(selectors);
1140
- const startTime = Date.now();
1141
- let error = null;
1142
- let screenshotId = null;
1143
- let screenshotPath = null;
1144
- const info = {};
1145
- info.log = "";
1146
- info.operation = Types.SET_DATE_TIME;
1147
- info.selectors = selectors;
1148
- info.value = value;
1139
+ const state = {
1140
+ selectors,
1141
+ _params,
1142
+ value: await this._replaceWithLocalData(value, this),
1143
+ options,
1144
+ world,
1145
+ type: Types.SET_DATE_TIME,
1146
+ text: `Set date time value: ${value}`,
1147
+ operation: "setDateTime",
1148
+ log: "***** set date time value " + selectors.element_name + " *****\n",
1149
+ throwError: false,
1150
+ };
1149
1151
  try {
1150
- value = await this._replaceWithLocalData(value, this);
1151
- let element = await this._locate(selectors, info, _params);
1152
- //insert red border around the element
1153
- await this.scrollIfNeeded(element, info);
1154
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1155
- await this._highlightElements(element);
1152
+ await _preCommand(state, this);
1156
1153
  try {
1157
- await element.click();
1154
+ await state.element.click();
1158
1155
  await new Promise((resolve) => setTimeout(resolve, 500));
1159
1156
  if (format) {
1160
- value = dayjs(value).format(format);
1161
- await element.fill(value);
1157
+ state.value = dayjs(state.value).format(format);
1158
+ await state.element.fill(state.value);
1162
1159
  }
1163
1160
  else {
1164
- const dateTimeValue = await getDateTimeValue({ value, element });
1165
- await element.evaluateHandle((el, dateTimeValue) => {
1161
+ const dateTimeValue = await getDateTimeValue({ value: state.value, element: state.element });
1162
+ await state.element.evaluateHandle((el, dateTimeValue) => {
1166
1163
  el.value = ""; // clear input
1167
1164
  el.value = dateTimeValue;
1168
1165
  }, dateTimeValue);
@@ -1175,20 +1172,19 @@ class StableBrowser {
1175
1172
  }
1176
1173
  catch (err) {
1177
1174
  //await this.closeUnexpectedPopups();
1178
- this.logger.error("setting date time input failed " + JSON.stringify(info));
1175
+ this.logger.error("setting date time input failed " + JSON.stringify(state.info));
1179
1176
  this.logger.info("Trying again");
1180
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1181
- info.screenshotPath = screenshotPath;
1182
- Object.assign(err, { info: info });
1177
+ await _screenshot(state, this);
1178
+ Object.assign(err, { info: state.info });
1183
1179
  await element.click();
1184
1180
  await new Promise((resolve) => setTimeout(resolve, 500));
1185
1181
  if (format) {
1186
- value = dayjs(value).format(format);
1187
- await element.fill(value);
1182
+ state.value = dayjs(state.value).format(format);
1183
+ await state.element.fill(state.value);
1188
1184
  }
1189
1185
  else {
1190
- const dateTimeValue = await getDateTimeValue({ value, element });
1191
- await element.evaluateHandle((el, dateTimeValue) => {
1186
+ const dateTimeValue = await getDateTimeValue({ value: state.value, element: state.element });
1187
+ await state.element.evaluateHandle((el, dateTimeValue) => {
1192
1188
  el.value = ""; // clear input
1193
1189
  el.value = dateTimeValue;
1194
1190
  }, dateTimeValue);
@@ -1201,61 +1197,39 @@ class StableBrowser {
1201
1197
  }
1202
1198
  }
1203
1199
  catch (e) {
1204
- error = e;
1205
- throw e;
1200
+ await _commandError(state, e, this);
1206
1201
  }
1207
1202
  finally {
1208
- const endTime = Date.now();
1209
- this._reportToWorld(world, {
1210
- element_name: selectors.element_name,
1211
- type: Types.SET_DATE_TIME,
1212
- screenshotId,
1213
- value: value,
1214
- text: `setDateTime input with value: ${value}`,
1215
- result: error
1216
- ? {
1217
- status: "FAILED",
1218
- startTime,
1219
- endTime,
1220
- message: error === null || error === void 0 ? void 0 : error.message,
1221
- }
1222
- : {
1223
- status: "PASSED",
1224
- startTime,
1225
- endTime,
1226
- },
1227
- info: info,
1228
- });
1203
+ _commandFinally(state, this);
1229
1204
  }
1230
1205
  }
1231
1206
  async clickType(selectors, _value, enter = false, _params = null, options = {}, world = null) {
1232
1207
  _value = unEscapeString(_value);
1233
- this._validateSelectors(selectors);
1234
- const startTime = Date.now();
1235
- let error = null;
1236
- let screenshotId = null;
1237
- let screenshotPath = null;
1238
- const info = {};
1239
- info.log = "***** clickType on " + selectors.element_name + " with value " + _value + "*****\n";
1240
- info.operation = "clickType";
1241
- info.selectors = selectors;
1242
1208
  const newValue = await this._replaceWithLocalData(_value, world);
1209
+ const state = {
1210
+ selectors,
1211
+ _params,
1212
+ value: newValue,
1213
+ originalValue: _value,
1214
+ options,
1215
+ world,
1216
+ type: Types.FILL,
1217
+ text: `Click type input with value: ${_value}`,
1218
+ operation: "clickType",
1219
+ log: "***** clickType on " + selectors.element_name + " with value " + maskValue(_value) + "*****\n",
1220
+ };
1243
1221
  if (newValue !== _value) {
1244
1222
  //this.logger.info(_value + "=" + newValue);
1245
1223
  _value = newValue;
1246
1224
  }
1247
- info.value = _value;
1248
1225
  try {
1249
- let element = await this._locate(selectors, info, _params);
1250
- //insert red border around the element
1251
- await this.scrollIfNeeded(element, info);
1252
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1253
- await this._highlightElements(element);
1226
+ await _preCommand(state, this);
1227
+ state.info.value = _value;
1254
1228
  if (options === null || options === undefined || !options.press) {
1255
1229
  try {
1256
- let currentValue = await element.inputValue();
1230
+ let currentValue = await state.element.inputValue();
1257
1231
  if (currentValue) {
1258
- await element.fill("");
1232
+ await state.element.fill("");
1259
1233
  }
1260
1234
  }
1261
1235
  catch (e) {
@@ -1264,22 +1238,22 @@ class StableBrowser {
1264
1238
  }
1265
1239
  if (options === null || options === undefined || options.press) {
1266
1240
  try {
1267
- await element.click({ timeout: 5000 });
1241
+ await state.element.click({ timeout: 5000 });
1268
1242
  }
1269
1243
  catch (e) {
1270
- await element.dispatchEvent("click");
1244
+ await state.element.dispatchEvent("click");
1271
1245
  }
1272
1246
  }
1273
1247
  else {
1274
1248
  try {
1275
- await element.focus();
1249
+ await state.element.focus();
1276
1250
  }
1277
1251
  catch (e) {
1278
- await element.dispatchEvent("focus");
1252
+ await state.element.dispatchEvent("focus");
1279
1253
  }
1280
1254
  }
1281
1255
  await new Promise((resolve) => setTimeout(resolve, 500));
1282
- const valueSegment = _value.split("&&");
1256
+ const valueSegment = state.value.split("&&");
1283
1257
  for (let i = 0; i < valueSegment.length; i++) {
1284
1258
  if (i > 0) {
1285
1259
  await new Promise((resolve) => setTimeout(resolve, 1000));
@@ -1299,13 +1273,14 @@ class StableBrowser {
1299
1273
  await new Promise((resolve) => setTimeout(resolve, 500));
1300
1274
  }
1301
1275
  }
1276
+ await _screenshot(state, this);
1302
1277
  if (enter === true) {
1303
1278
  await new Promise((resolve) => setTimeout(resolve, 2000));
1304
1279
  await this.page.keyboard.press("Enter");
1305
1280
  await this.waitForPageLoad();
1306
1281
  }
1307
1282
  else if (enter === false) {
1308
- await element.dispatchEvent("change");
1283
+ await state.element.dispatchEvent("change");
1309
1284
  //await this.page.keyboard.press("Tab");
1310
1285
  }
1311
1286
  else {
@@ -1314,104 +1289,50 @@ class StableBrowser {
1314
1289
  await this.waitForPageLoad();
1315
1290
  }
1316
1291
  }
1317
- return info;
1292
+ return state.info;
1318
1293
  }
1319
1294
  catch (e) {
1320
- //await this.closeUnexpectedPopups();
1321
- this.logger.error("fill failed " + JSON.stringify(info));
1322
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1323
- info.screenshotPath = screenshotPath;
1324
- Object.assign(e, { info: info });
1325
- error = e;
1326
- throw e;
1295
+ await _commandError(state, e, this);
1327
1296
  }
1328
1297
  finally {
1329
- const endTime = Date.now();
1330
- this._reportToWorld(world, {
1331
- element_name: selectors.element_name,
1332
- type: Types.FILL,
1333
- screenshotId,
1334
- value: _value,
1335
- text: `clickType input with value: ${_value}`,
1336
- result: error
1337
- ? {
1338
- status: "FAILED",
1339
- startTime,
1340
- endTime,
1341
- message: error === null || error === void 0 ? void 0 : error.message,
1342
- }
1343
- : {
1344
- status: "PASSED",
1345
- startTime,
1346
- endTime,
1347
- },
1348
- info: info,
1349
- });
1298
+ _commandFinally(state, this);
1350
1299
  }
1351
1300
  }
1352
1301
  async fill(selectors, value, enter = false, _params = null, options = {}, world = null) {
1353
- this._validateSelectors(selectors);
1354
- value = unEscapeString(value);
1355
- const startTime = Date.now();
1356
- let error = null;
1357
- let screenshotId = null;
1358
- let screenshotPath = null;
1359
- const info = {};
1360
- info.log = "***** fill on " + selectors.element_name + " with value " + value + "*****\n";
1361
- info.operation = "fill";
1362
- info.selectors = selectors;
1363
- info.value = value;
1302
+ const state = {
1303
+ selectors,
1304
+ _params,
1305
+ value: unEscapeString(value),
1306
+ options,
1307
+ world,
1308
+ type: Types.FILL,
1309
+ text: `Fill input with value: ${value}`,
1310
+ operation: "fill",
1311
+ log: "***** fill on " + selectors.element_name + " with value " + value + "*****\n",
1312
+ };
1364
1313
  try {
1365
- let element = await this._locate(selectors, info, _params);
1366
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1367
- await this._highlightElements(element);
1368
- await element.fill(value);
1369
- await element.dispatchEvent("change");
1314
+ await _preCommand(state, this);
1315
+ await state.element.fill(value);
1316
+ await state.element.dispatchEvent("change");
1370
1317
  if (enter) {
1371
1318
  await new Promise((resolve) => setTimeout(resolve, 2000));
1372
1319
  await this.page.keyboard.press("Enter");
1373
1320
  }
1374
1321
  await this.waitForPageLoad();
1375
- return info;
1322
+ return state.info;
1376
1323
  }
1377
1324
  catch (e) {
1378
- //await this.closeUnexpectedPopups();
1379
- this.logger.error("fill failed " + info.log);
1380
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1381
- info.screenshotPath = screenshotPath;
1382
- Object.assign(e, { info: info });
1383
- error = e;
1384
- throw e;
1325
+ await _commandError(state, e, this);
1385
1326
  }
1386
1327
  finally {
1387
- const endTime = Date.now();
1388
- this._reportToWorld(world, {
1389
- element_name: selectors.element_name,
1390
- type: Types.FILL,
1391
- screenshotId,
1392
- value,
1393
- text: `Fill input with value: ${value}`,
1394
- result: error
1395
- ? {
1396
- status: "FAILED",
1397
- startTime,
1398
- endTime,
1399
- message: error === null || error === void 0 ? void 0 : error.message,
1400
- }
1401
- : {
1402
- status: "PASSED",
1403
- startTime,
1404
- endTime,
1405
- },
1406
- info: info,
1407
- });
1328
+ _commandFinally(state, this);
1408
1329
  }
1409
1330
  }
1410
1331
  async getText(selectors, _params = null, options = {}, info = {}, world = null) {
1411
1332
  return await this._getText(selectors, 0, _params, options, info, world);
1412
1333
  }
1413
1334
  async _getText(selectors, climb, _params = null, options = {}, info = {}, world = null) {
1414
- this._validateSelectors(selectors);
1335
+ _validateSelectors(selectors);
1415
1336
  let screenshotId = null;
1416
1337
  let screenshotPath = null;
1417
1338
  if (!info.log) {
@@ -1455,166 +1376,124 @@ class StableBrowser {
1455
1376
  }
1456
1377
  }
1457
1378
  async containsPattern(selectors, pattern, text, _params = null, options = {}, world = null) {
1458
- var _a;
1459
- this._validateSelectors(selectors);
1460
1379
  if (!pattern) {
1461
1380
  throw new Error("pattern is null");
1462
1381
  }
1463
1382
  if (!text) {
1464
1383
  throw new Error("text is null");
1465
1384
  }
1385
+ const state = {
1386
+ selectors,
1387
+ _params,
1388
+ pattern,
1389
+ value: pattern,
1390
+ options,
1391
+ world,
1392
+ locate: false,
1393
+ scroll: false,
1394
+ screenshot: false,
1395
+ highlight: false,
1396
+ type: Types.VERIFY_ELEMENT_CONTAINS_TEXT,
1397
+ text: `Verify element contains pattern: ${pattern}`,
1398
+ operation: "containsPattern",
1399
+ log: "***** verify element " + selectors.element_name + " contains pattern " + pattern + " *****\n",
1400
+ };
1466
1401
  const newValue = await this._replaceWithLocalData(text, world);
1467
1402
  if (newValue !== text) {
1468
1403
  this.logger.info(text + "=" + newValue);
1469
1404
  text = newValue;
1470
1405
  }
1471
- const startTime = Date.now();
1472
- let error = null;
1473
- let screenshotId = null;
1474
- let screenshotPath = null;
1475
- const info = {};
1476
- info.log =
1477
- "***** verify element " + selectors.element_name + " contains pattern " + pattern + "/" + text + " *****\n";
1478
- info.operation = "containsPattern";
1479
- info.selectors = selectors;
1480
- info.value = text;
1481
- info.pattern = pattern;
1482
1406
  let foundObj = null;
1483
1407
  try {
1484
- foundObj = await this._getText(selectors, 0, _params, options, info, world);
1408
+ await _preCommand(state, this);
1409
+ state.info.pattern = pattern;
1410
+ foundObj = await this._getText(selectors, 0, _params, options, state.info, world);
1485
1411
  if (foundObj && foundObj.element) {
1486
- await this.scrollIfNeeded(foundObj.element, info);
1412
+ await this.scrollIfNeeded(foundObj.element, state.info);
1487
1413
  }
1488
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1414
+ await _screenshot(state, this);
1489
1415
  let escapedText = text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
1490
1416
  pattern = pattern.replace("{text}", escapedText);
1491
1417
  let regex = new RegExp(pattern, "im");
1492
- 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))) {
1493
- info.foundText = foundObj === null || foundObj === void 0 ? void 0 : foundObj.text;
1418
+ if (!regex.test(foundObj?.text) && !foundObj?.value?.includes(text)) {
1419
+ state.info.foundText = foundObj?.text;
1494
1420
  throw new Error("element doesn't contain text " + text);
1495
1421
  }
1496
- return info;
1422
+ return state.info;
1497
1423
  }
1498
1424
  catch (e) {
1499
- //await this.closeUnexpectedPopups();
1500
- this.logger.error("verify element contains text failed " + info.log);
1501
- this.logger.error("found text " + (foundObj === null || foundObj === void 0 ? void 0 : foundObj.text) + " pattern " + pattern);
1502
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1503
- info.screenshotPath = screenshotPath;
1504
- Object.assign(e, { info: info });
1505
- error = e;
1506
- throw e;
1425
+ this.logger.error("found text " + foundObj?.text + " pattern " + pattern);
1426
+ await _commandError(state, e, this);
1507
1427
  }
1508
1428
  finally {
1509
- const endTime = Date.now();
1510
- this._reportToWorld(world, {
1511
- element_name: selectors.element_name,
1512
- type: Types.VERIFY_ELEMENT_CONTAINS_TEXT,
1513
- value: pattern,
1514
- text: `Verify element contains pattern: ${pattern}`,
1515
- screenshotId: foundObj === null || foundObj === void 0 ? void 0 : foundObj.screenshotId,
1516
- result: error
1517
- ? {
1518
- status: "FAILED",
1519
- startTime,
1520
- endTime,
1521
- message: error === null || error === void 0 ? void 0 : error.message,
1522
- }
1523
- : {
1524
- status: "PASSED",
1525
- startTime,
1526
- endTime,
1527
- },
1528
- info: info,
1529
- });
1429
+ _commandFinally(state, this);
1530
1430
  }
1531
1431
  }
1532
1432
  async containsText(selectors, text, climb, _params = null, options = {}, world = null) {
1533
- var _a, _b, _c;
1534
- this._validateSelectors(selectors);
1535
- text = unEscapeString(text);
1433
+ const state = {
1434
+ selectors,
1435
+ _params,
1436
+ value: text,
1437
+ options,
1438
+ world,
1439
+ locate: false,
1440
+ scroll: false,
1441
+ screenshot: false,
1442
+ highlight: false,
1443
+ type: Types.VERIFY_ELEMENT_CONTAINS_TEXT,
1444
+ text: `Verify element contains text: ${text}`,
1445
+ operation: "containsText",
1446
+ log: "***** verify element " + selectors.element_name + " contains text " + text + " *****\n",
1447
+ };
1536
1448
  if (!text) {
1537
1449
  throw new Error("text is null");
1538
1450
  }
1539
- const startTime = Date.now();
1540
- let error = null;
1541
- let screenshotId = null;
1542
- let screenshotPath = null;
1543
- const info = {};
1544
- info.log = "***** verify element " + selectors.element_name + " contains text " + text + " *****\n";
1545
- info.operation = "containsText";
1546
- info.selectors = selectors;
1451
+ text = unEscapeString(text);
1547
1452
  const newValue = await this._replaceWithLocalData(text, world);
1548
1453
  if (newValue !== text) {
1549
1454
  this.logger.info(text + "=" + newValue);
1550
1455
  text = newValue;
1551
1456
  }
1552
- info.value = text;
1553
1457
  let foundObj = null;
1554
1458
  try {
1555
- foundObj = await this._getText(selectors, climb, _params, options, info, world);
1459
+ await _preCommand(state, this);
1460
+ foundObj = await this._getText(selectors, climb, _params, options, state.info, world);
1556
1461
  if (foundObj && foundObj.element) {
1557
- await this.scrollIfNeeded(foundObj.element, info);
1462
+ await this.scrollIfNeeded(foundObj.element, state.info);
1558
1463
  }
1559
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1464
+ await _screenshot(state, this);
1560
1465
  const dateAlternatives = findDateAlternatives(text);
1561
1466
  const numberAlternatives = findNumberAlternatives(text);
1562
1467
  if (dateAlternatives.date) {
1563
1468
  for (let i = 0; i < dateAlternatives.dates.length; i++) {
1564
- if ((foundObj === null || foundObj === void 0 ? void 0 : foundObj.text.includes(dateAlternatives.dates[i])) ||
1565
- ((_a = foundObj === null || foundObj === void 0 ? void 0 : foundObj.value) === null || _a === void 0 ? void 0 : _a.includes(dateAlternatives.dates[i]))) {
1566
- return info;
1469
+ if (foundObj?.text.includes(dateAlternatives.dates[i]) ||
1470
+ foundObj?.value?.includes(dateAlternatives.dates[i])) {
1471
+ return state.info;
1567
1472
  }
1568
1473
  }
1569
1474
  throw new Error("element doesn't contain text " + text);
1570
1475
  }
1571
1476
  else if (numberAlternatives.number) {
1572
1477
  for (let i = 0; i < numberAlternatives.numbers.length; i++) {
1573
- if ((foundObj === null || foundObj === void 0 ? void 0 : foundObj.text.includes(numberAlternatives.numbers[i])) ||
1574
- ((_b = foundObj === null || foundObj === void 0 ? void 0 : foundObj.value) === null || _b === void 0 ? void 0 : _b.includes(numberAlternatives.numbers[i]))) {
1575
- return info;
1478
+ if (foundObj?.text.includes(numberAlternatives.numbers[i]) ||
1479
+ foundObj?.value?.includes(numberAlternatives.numbers[i])) {
1480
+ return state.info;
1576
1481
  }
1577
1482
  }
1578
1483
  throw new Error("element doesn't contain text " + text);
1579
1484
  }
1580
- 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))) {
1581
- info.foundText = foundObj === null || foundObj === void 0 ? void 0 : foundObj.text;
1582
- info.value = foundObj === null || foundObj === void 0 ? void 0 : foundObj.value;
1485
+ else if (!foundObj?.text.includes(text) && !foundObj?.value?.includes(text)) {
1486
+ state.info.foundText = foundObj?.text;
1487
+ state.info.value = foundObj?.value;
1583
1488
  throw new Error("element doesn't contain text " + text);
1584
1489
  }
1585
- return info;
1490
+ return state.info;
1586
1491
  }
1587
1492
  catch (e) {
1588
- //await this.closeUnexpectedPopups();
1589
- this.logger.error("verify element contains text failed " + info.log);
1590
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1591
- info.screenshotPath = screenshotPath;
1592
- Object.assign(e, { info: info });
1593
- error = e;
1594
- throw e;
1493
+ await _commandError(state, e, this);
1595
1494
  }
1596
1495
  finally {
1597
- const endTime = Date.now();
1598
- this._reportToWorld(world, {
1599
- element_name: selectors.element_name,
1600
- type: Types.VERIFY_ELEMENT_CONTAINS_TEXT,
1601
- text: `Verify element contains text: ${text}`,
1602
- value: text,
1603
- screenshotId: foundObj === null || foundObj === void 0 ? void 0 : foundObj.screenshotId,
1604
- result: error
1605
- ? {
1606
- status: "FAILED",
1607
- startTime,
1608
- endTime,
1609
- message: error === null || error === void 0 ? void 0 : error.message,
1610
- }
1611
- : {
1612
- status: "PASSED",
1613
- startTime,
1614
- endTime,
1615
- },
1616
- info: info,
1617
- });
1496
+ _commandFinally(state, this);
1618
1497
  }
1619
1498
  }
1620
1499
  _getDataFile(world = null) {
@@ -1843,7 +1722,6 @@ class StableBrowser {
1843
1722
  }
1844
1723
  async takeScreenshot(screenshotPath) {
1845
1724
  const playContext = this.context.playContext;
1846
- const client = await playContext.newCDPSession(this.page);
1847
1725
  // Using CDP to capture the screenshot
1848
1726
  const viewportWidth = Math.max(...(await this.page.evaluate(() => [
1849
1727
  document.body.scrollWidth,
@@ -1853,163 +1731,105 @@ class StableBrowser {
1853
1731
  document.body.clientWidth,
1854
1732
  document.documentElement.clientWidth,
1855
1733
  ])));
1856
- const viewportHeight = Math.max(...(await this.page.evaluate(() => [
1857
- document.body.scrollHeight,
1858
- document.documentElement.scrollHeight,
1859
- document.body.offsetHeight,
1860
- document.documentElement.offsetHeight,
1861
- document.body.clientHeight,
1862
- document.documentElement.clientHeight,
1863
- ])));
1864
- const { data } = await client.send("Page.captureScreenshot", {
1865
- format: "png",
1866
- // clip: {
1867
- // x: 0,
1868
- // y: 0,
1869
- // width: viewportWidth,
1870
- // height: viewportHeight,
1871
- // scale: 1,
1872
- // },
1873
- });
1874
- if (!screenshotPath) {
1875
- return data;
1734
+ let screenshotBuffer = null;
1735
+ if (this.context.browserName === "chromium") {
1736
+ const client = await playContext.newCDPSession(this.page);
1737
+ const { data } = await client.send("Page.captureScreenshot", {
1738
+ format: "png",
1739
+ // clip: {
1740
+ // x: 0,
1741
+ // y: 0,
1742
+ // width: viewportWidth,
1743
+ // height: viewportHeight,
1744
+ // scale: 1,
1745
+ // },
1746
+ });
1747
+ await client.detach();
1748
+ if (!screenshotPath) {
1749
+ return data;
1750
+ }
1751
+ screenshotBuffer = Buffer.from(data, "base64");
1752
+ }
1753
+ else {
1754
+ screenshotBuffer = await this.page.screenshot();
1876
1755
  }
1877
- let screenshotBuffer = Buffer.from(data, "base64");
1878
1756
  let image = await Jimp.read(screenshotBuffer);
1879
1757
  // Get the image dimensions
1880
1758
  const { width, height } = image.bitmap;
1759
+ const resizeRatio = viewportWidth / width;
1881
1760
  // Resize the image to fit within the viewport dimensions without enlarging
1882
- if (width > viewportWidth || height > viewportHeight) {
1883
- image = image.resize({ w: viewportWidth, h: viewportHeight }); // Resize the image while maintaining aspect ratio
1761
+ if (width > viewportWidth) {
1762
+ image = image.resize({ w: viewportWidth, h: height * resizeRatio }); // Resize the image while maintaining aspect ratio
1884
1763
  await image.write(screenshotPath);
1885
1764
  }
1886
1765
  else {
1887
1766
  fs.writeFileSync(screenshotPath, screenshotBuffer);
1888
1767
  }
1889
- await client.detach();
1890
1768
  }
1891
1769
  async verifyElementExistInPage(selectors, _params = null, options = {}, world = null) {
1892
- this._validateSelectors(selectors);
1893
- const startTime = Date.now();
1894
- let error = null;
1895
- let screenshotId = null;
1896
- let screenshotPath = null;
1770
+ const state = {
1771
+ selectors,
1772
+ _params,
1773
+ options,
1774
+ world,
1775
+ type: Types.VERIFY_ELEMENT_CONTAINS_TEXT,
1776
+ text: `Verify element exists in page`,
1777
+ operation: "verifyElementExistInPage",
1778
+ log: "***** verify element " + selectors.element_name + " exists in page *****\n",
1779
+ };
1897
1780
  await new Promise((resolve) => setTimeout(resolve, 2000));
1898
- const info = {};
1899
- info.log = "***** verify element " + selectors.element_name + " exists in page *****\n";
1900
- info.operation = "verify";
1901
- info.selectors = selectors;
1902
1781
  try {
1903
- const element = await this._locate(selectors, info, _params);
1904
- if (element) {
1905
- await this.scrollIfNeeded(element, info);
1906
- }
1907
- await this._highlightElements(element);
1908
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1909
- await expect(element).toHaveCount(1, { timeout: 10000 });
1910
- return info;
1782
+ await _preCommand(state, this);
1783
+ await expect(state.element).toHaveCount(1, { timeout: 10000 });
1784
+ return state.info;
1911
1785
  }
1912
1786
  catch (e) {
1913
- //await this.closeUnexpectedPopups();
1914
- this.logger.error("verify failed " + info.log);
1915
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1916
- info.screenshotPath = screenshotPath;
1917
- Object.assign(e, { info: info });
1918
- error = e;
1919
- throw e;
1787
+ await _commandError(state, e, this);
1920
1788
  }
1921
1789
  finally {
1922
- const endTime = Date.now();
1923
- this._reportToWorld(world, {
1924
- element_name: selectors.element_name,
1925
- type: Types.VERIFY_ELEMENT_CONTAINS_TEXT,
1926
- text: "Verify element exists in page",
1927
- screenshotId,
1928
- result: error
1929
- ? {
1930
- status: "FAILED",
1931
- startTime,
1932
- endTime,
1933
- message: error === null || error === void 0 ? void 0 : error.message,
1934
- }
1935
- : {
1936
- status: "PASSED",
1937
- startTime,
1938
- endTime,
1939
- },
1940
- info: info,
1941
- });
1790
+ _commandFinally(state, this);
1942
1791
  }
1943
1792
  }
1944
1793
  async extractAttribute(selectors, attribute, variable, _params = null, options = {}, world = null) {
1945
- this._validateSelectors(selectors);
1946
- const startTime = Date.now();
1947
- let error = null;
1948
- let screenshotId = null;
1949
- let screenshotPath = null;
1794
+ const state = {
1795
+ selectors,
1796
+ _params,
1797
+ attribute,
1798
+ variable,
1799
+ options,
1800
+ world,
1801
+ type: Types.EXTRACT,
1802
+ text: `Extract attribute from element`,
1803
+ operation: "extractAttribute",
1804
+ log: "***** extract attribute " + attribute + " from " + selectors.element_name + " *****\n",
1805
+ };
1950
1806
  await new Promise((resolve) => setTimeout(resolve, 2000));
1951
- const info = {};
1952
- info.log = "***** extract attribute " + attribute + " from " + selectors.element_name + " *****\n";
1953
- info.operation = "extract";
1954
- info.selectors = selectors;
1955
1807
  try {
1956
- const element = await this._locate(selectors, info, _params);
1957
- await this._highlightElements(element);
1958
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1808
+ await _preCommand(state, this);
1959
1809
  switch (attribute) {
1960
1810
  case "inner_text":
1961
- info.value = await element.innerText();
1811
+ state.value = await state.element.innerText();
1962
1812
  break;
1963
1813
  case "href":
1964
- info.value = await element.getAttribute("href");
1814
+ state.value = await state.element.getAttribute("href");
1965
1815
  break;
1966
1816
  case "value":
1967
- info.value = await element.inputValue();
1817
+ state.value = await state.element.inputValue();
1968
1818
  break;
1969
1819
  default:
1970
- info.value = await element.getAttribute(attribute);
1820
+ state.value = await state.element.getAttribute(attribute);
1971
1821
  break;
1972
1822
  }
1973
- this[variable] = info.value;
1974
- if (world) {
1975
- world[variable] = info.value;
1976
- }
1977
- this.setTestData({ [variable]: info.value }, world);
1978
- this.logger.info("set test data: " + variable + "=" + info.value);
1979
- return info;
1823
+ state.info.value = state.value;
1824
+ this.setTestData({ [variable]: state.value }, world);
1825
+ this.logger.info("set test data: " + variable + "=" + state.value);
1826
+ return state.info;
1980
1827
  }
1981
1828
  catch (e) {
1982
- //await this.closeUnexpectedPopups();
1983
- this.logger.error("extract failed " + info.log);
1984
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1985
- info.screenshotPath = screenshotPath;
1986
- Object.assign(e, { info: info });
1987
- error = e;
1988
- throw e;
1829
+ await _commandError(state, e, this);
1989
1830
  }
1990
1831
  finally {
1991
- const endTime = Date.now();
1992
- this._reportToWorld(world, {
1993
- element_name: selectors.element_name,
1994
- type: Types.EXTRACT_ATTRIBUTE,
1995
- variable: variable,
1996
- value: info.value,
1997
- text: "Extract attribute from element",
1998
- screenshotId,
1999
- result: error
2000
- ? {
2001
- status: "FAILED",
2002
- startTime,
2003
- endTime,
2004
- message: error === null || error === void 0 ? void 0 : error.message,
2005
- }
2006
- : {
2007
- status: "PASSED",
2008
- startTime,
2009
- endTime,
2010
- },
2011
- info: info,
2012
- });
1832
+ _commandFinally(state, this);
2013
1833
  }
2014
1834
  }
2015
1835
  async extractEmailData(emailAddress, options, world) {
@@ -2086,7 +1906,8 @@ class StableBrowser {
2086
1906
  catch (e) {
2087
1907
  errorCount++;
2088
1908
  if (errorCount > 3) {
2089
- throw e;
1909
+ // throw e;
1910
+ await _commandError({ text: "extractEmailData", operation: "extractEmailData", emailAddress, info: {} }, e, this);
2090
1911
  }
2091
1912
  // ignore
2092
1913
  }
@@ -2197,7 +2018,8 @@ class StableBrowser {
2197
2018
  info.screenshotPath = screenshotPath;
2198
2019
  Object.assign(e, { info: info });
2199
2020
  error = e;
2200
- throw e;
2021
+ // throw e;
2022
+ await _commandError({ text: "verifyPagePath", operation: "verifyPagePath", pathPart, info }, e, this);
2201
2023
  }
2202
2024
  finally {
2203
2025
  const endTime = Date.now();
@@ -2210,7 +2032,7 @@ class StableBrowser {
2210
2032
  status: "FAILED",
2211
2033
  startTime,
2212
2034
  endTime,
2213
- message: error === null || error === void 0 ? void 0 : error.message,
2035
+ message: error?.message,
2214
2036
  }
2215
2037
  : {
2216
2038
  status: "PASSED",
@@ -2223,52 +2045,58 @@ class StableBrowser {
2223
2045
  }
2224
2046
  async verifyTextExistInPage(text, options = {}, world = null) {
2225
2047
  text = unEscapeString(text);
2226
- const startTime = Date.now();
2048
+ const state = {
2049
+ text_search: text,
2050
+ options,
2051
+ world,
2052
+ locate: false,
2053
+ scroll: false,
2054
+ highlight: false,
2055
+ type: Types.VERIFY_ELEMENT_CONTAINS_TEXT,
2056
+ text: `Verify text exists in page`,
2057
+ operation: "verifyTextExistInPage",
2058
+ log: "***** verify text " + text + " exists in page *****\n",
2059
+ };
2227
2060
  const timeout = this._getLoadTimeout(options);
2228
- let error = null;
2229
- let screenshotId = null;
2230
- let screenshotPath = null;
2231
2061
  await new Promise((resolve) => setTimeout(resolve, 2000));
2232
- const info = {};
2233
- info.log = "***** verify text " + text + " exists in page *****\n";
2234
- info.operation = "verifyTextExistInPage";
2235
2062
  const newValue = await this._replaceWithLocalData(text, world);
2236
2063
  if (newValue !== text) {
2237
2064
  this.logger.info(text + "=" + newValue);
2238
2065
  text = newValue;
2239
2066
  }
2240
- info.text = text;
2241
2067
  let dateAlternatives = findDateAlternatives(text);
2242
2068
  let numberAlternatives = findNumberAlternatives(text);
2243
2069
  try {
2070
+ await _preCommand(state, this);
2071
+ state.info.text = text;
2244
2072
  while (true) {
2245
2073
  const frames = this.page.frames();
2246
2074
  let results = [];
2247
2075
  for (let i = 0; i < frames.length; i++) {
2248
2076
  if (dateAlternatives.date) {
2249
2077
  for (let j = 0; j < dateAlternatives.dates.length; j++) {
2250
- const result = await this._locateElementByText(frames[i], dateAlternatives.dates[j], "*", true, {});
2078
+ const result = await this._locateElementByText(frames[i], dateAlternatives.dates[j], "*:not(script, style, head)", true, true, {});
2251
2079
  result.frame = frames[i];
2252
2080
  results.push(result);
2253
2081
  }
2254
2082
  }
2255
2083
  else if (numberAlternatives.number) {
2256
2084
  for (let j = 0; j < numberAlternatives.numbers.length; j++) {
2257
- const result = await this._locateElementByText(frames[i], numberAlternatives.numbers[j], "*", true, {});
2085
+ const result = await this._locateElementByText(frames[i], numberAlternatives.numbers[j], "*:not(script, style, head)", true, true, {});
2258
2086
  result.frame = frames[i];
2259
2087
  results.push(result);
2260
2088
  }
2261
2089
  }
2262
2090
  else {
2263
- const result = await this._locateElementByText(frames[i], text, "*", true, {});
2091
+ const result = await this._locateElementByText(frames[i], text, "*:not(script, style, head)", true, true, {});
2264
2092
  result.frame = frames[i];
2265
2093
  results.push(result);
2266
2094
  }
2267
2095
  }
2268
- info.results = results;
2096
+ state.info.results = results;
2269
2097
  const resultWithElementsFound = results.filter((result) => result.elementCount > 0);
2270
2098
  if (resultWithElementsFound.length === 0) {
2271
- if (Date.now() - startTime > timeout) {
2099
+ if (Date.now() - state.startTime > timeout) {
2272
2100
  throw new Error(`Text ${text} not found in page`);
2273
2101
  }
2274
2102
  await new Promise((resolve) => setTimeout(resolve, 1000));
@@ -2280,44 +2108,89 @@ class StableBrowser {
2280
2108
  await this._highlightElements(frame, dataAttribute);
2281
2109
  const element = await frame.$(dataAttribute);
2282
2110
  if (element) {
2283
- await this.scrollIfNeeded(element, info);
2111
+ await this.scrollIfNeeded(element, state.info);
2284
2112
  await element.dispatchEvent("bvt_verify_page_contains_text");
2285
2113
  }
2286
2114
  }
2287
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
2288
- return info;
2115
+ await _screenshot(state, this);
2116
+ return state.info;
2289
2117
  }
2290
2118
  // await expect(element).toHaveCount(1, { timeout: 10000 });
2291
2119
  }
2292
2120
  catch (e) {
2293
- //await this.closeUnexpectedPopups();
2294
- this.logger.error("verify text exist in page failed " + info.log);
2295
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
2296
- info.screenshotPath = screenshotPath;
2297
- Object.assign(e, { info: info });
2298
- error = e;
2299
- throw e;
2121
+ await _commandError(state, e, this);
2300
2122
  }
2301
2123
  finally {
2302
- const endTime = Date.now();
2303
- this._reportToWorld(world, {
2304
- type: Types.VERIFY_ELEMENT_CONTAINS_TEXT,
2305
- text: "Verify text exists in page",
2306
- screenshotId,
2307
- result: error
2308
- ? {
2309
- status: "FAILED",
2310
- startTime,
2311
- endTime,
2312
- message: error === null || error === void 0 ? void 0 : error.message,
2124
+ _commandFinally(state, this);
2125
+ }
2126
+ }
2127
+ async waitForTextToDisappear(text, options = {}, world = null) {
2128
+ text = unEscapeString(text);
2129
+ const state = {
2130
+ text_search: text,
2131
+ options,
2132
+ world,
2133
+ locate: false,
2134
+ scroll: false,
2135
+ highlight: false,
2136
+ type: Types.WAIT_FOR_TEXT_TO_DISAPPEAR,
2137
+ text: `Verify text does not exist in page`,
2138
+ operation: "verifyTextNotExistInPage",
2139
+ log: "***** verify text " + text + " does not exist in page *****\n",
2140
+ };
2141
+ const timeout = this._getLoadTimeout(options);
2142
+ await new Promise((resolve) => setTimeout(resolve, 2000));
2143
+ const newValue = await this._replaceWithLocalData(text, world);
2144
+ if (newValue !== text) {
2145
+ this.logger.info(text + "=" + newValue);
2146
+ text = newValue;
2147
+ }
2148
+ let dateAlternatives = findDateAlternatives(text);
2149
+ let numberAlternatives = findNumberAlternatives(text);
2150
+ try {
2151
+ await _preCommand(state, this);
2152
+ state.info.text = text;
2153
+ while (true) {
2154
+ const frames = this.page.frames();
2155
+ let results = [];
2156
+ for (let i = 0; i < frames.length; i++) {
2157
+ if (dateAlternatives.date) {
2158
+ for (let j = 0; j < dateAlternatives.dates.length; j++) {
2159
+ const result = await this._locateElementByText(frames[i], dateAlternatives.dates[j], "*:not(script, style, head)", true, true, {});
2160
+ result.frame = frames[i];
2161
+ results.push(result);
2162
+ }
2313
2163
  }
2314
- : {
2315
- status: "PASSED",
2316
- startTime,
2317
- endTime,
2318
- },
2319
- info: info,
2320
- });
2164
+ else if (numberAlternatives.number) {
2165
+ for (let j = 0; j < numberAlternatives.numbers.length; j++) {
2166
+ const result = await this._locateElementByText(frames[i], numberAlternatives.numbers[j], "*:not(script, style, head)", true, true, {});
2167
+ result.frame = frames[i];
2168
+ results.push(result);
2169
+ }
2170
+ }
2171
+ else {
2172
+ const result = await this._locateElementByText(frames[i], text, "*:not(script, style, head)", true, true, {});
2173
+ result.frame = frames[i];
2174
+ results.push(result);
2175
+ }
2176
+ }
2177
+ state.info.results = results;
2178
+ const resultWithElementsFound = results.filter((result) => result.elementCount > 0);
2179
+ if (resultWithElementsFound.length === 0) {
2180
+ await _screenshot(state, this);
2181
+ return state.info;
2182
+ }
2183
+ if (Date.now() - state.startTime > timeout) {
2184
+ throw new Error(`Text ${text} found in page`);
2185
+ }
2186
+ await new Promise((resolve) => setTimeout(resolve, 1000));
2187
+ }
2188
+ }
2189
+ catch (e) {
2190
+ await _commandError(state, e, this);
2191
+ }
2192
+ finally {
2193
+ _commandFinally(state, this);
2321
2194
  }
2322
2195
  }
2323
2196
  _getServerUrl() {
@@ -2380,7 +2253,8 @@ class StableBrowser {
2380
2253
  info.screenshotPath = screenshotPath;
2381
2254
  Object.assign(e, { info: info });
2382
2255
  error = e;
2383
- throw e;
2256
+ // throw e;
2257
+ await _commandError({ text: "visualVerification", operation: "visualVerification", text, info }, e, this);
2384
2258
  }
2385
2259
  finally {
2386
2260
  const endTime = Date.now();
@@ -2393,7 +2267,7 @@ class StableBrowser {
2393
2267
  status: "FAILED",
2394
2268
  startTime,
2395
2269
  endTime,
2396
- message: error === null || error === void 0 ? void 0 : error.message,
2270
+ message: error?.message,
2397
2271
  }
2398
2272
  : {
2399
2273
  status: "PASSED",
@@ -2425,7 +2299,7 @@ class StableBrowser {
2425
2299
  this.logger.info("Table data verified");
2426
2300
  }
2427
2301
  async getTableData(selectors, _params = null, options = {}, world = null) {
2428
- this._validateSelectors(selectors);
2302
+ _validateSelectors(selectors);
2429
2303
  const startTime = Date.now();
2430
2304
  let error = null;
2431
2305
  let screenshotId = null;
@@ -2447,7 +2321,8 @@ class StableBrowser {
2447
2321
  info.screenshotPath = screenshotPath;
2448
2322
  Object.assign(e, { info: info });
2449
2323
  error = e;
2450
- throw e;
2324
+ // throw e;
2325
+ await _commandError({ text: "getTableData", operation: "getTableData", selectors, info }, e, this);
2451
2326
  }
2452
2327
  finally {
2453
2328
  const endTime = Date.now();
@@ -2461,7 +2336,7 @@ class StableBrowser {
2461
2336
  status: "FAILED",
2462
2337
  startTime,
2463
2338
  endTime,
2464
- message: error === null || error === void 0 ? void 0 : error.message,
2339
+ message: error?.message,
2465
2340
  }
2466
2341
  : {
2467
2342
  status: "PASSED",
@@ -2473,7 +2348,7 @@ class StableBrowser {
2473
2348
  }
2474
2349
  }
2475
2350
  async analyzeTable(selectors, query, operator, value, _params = null, options = {}, world = null) {
2476
- this._validateSelectors(selectors);
2351
+ _validateSelectors(selectors);
2477
2352
  if (!query) {
2478
2353
  throw new Error("query is null");
2479
2354
  }
@@ -2612,7 +2487,8 @@ class StableBrowser {
2612
2487
  info.screenshotPath = screenshotPath;
2613
2488
  Object.assign(e, { info: info });
2614
2489
  error = e;
2615
- throw e;
2490
+ // throw e;
2491
+ await _commandError({ text: "analyzeTable", operation: "analyzeTable", selectors, query, operator, value }, e, this);
2616
2492
  }
2617
2493
  finally {
2618
2494
  const endTime = Date.now();
@@ -2626,7 +2502,7 @@ class StableBrowser {
2626
2502
  status: "FAILED",
2627
2503
  startTime,
2628
2504
  endTime,
2629
- message: error === null || error === void 0 ? void 0 : error.message,
2505
+ message: error?.message,
2630
2506
  }
2631
2507
  : {
2632
2508
  status: "PASSED",
@@ -2638,27 +2514,7 @@ class StableBrowser {
2638
2514
  }
2639
2515
  }
2640
2516
  async _replaceWithLocalData(value, world, _decrypt = true, totpWait = true) {
2641
- if (!value) {
2642
- return value;
2643
- }
2644
- // find all the accurance of {{(.*?)}} and replace with the value
2645
- let regex = /{{(.*?)}}/g;
2646
- let matches = value.match(regex);
2647
- if (matches) {
2648
- const testData = this.getTestData(world);
2649
- for (let i = 0; i < matches.length; i++) {
2650
- let match = matches[i];
2651
- let key = match.substring(2, match.length - 2);
2652
- let newValue = objectPath.get(testData, key, null);
2653
- if (newValue !== null) {
2654
- value = value.replace(match, newValue);
2655
- }
2656
- }
2657
- }
2658
- if ((value.startsWith("secret:") || value.startsWith("totp:")) && _decrypt) {
2659
- return await decrypt(value, null, totpWait);
2660
- }
2661
- return value;
2517
+ return await replaceWithLocalTestData(value, world, _decrypt, totpWait, this.context, this);
2662
2518
  }
2663
2519
  _getLoadTimeout(options) {
2664
2520
  let timeout = 15000;
@@ -2718,7 +2574,7 @@ class StableBrowser {
2718
2574
  status: "FAILED",
2719
2575
  startTime,
2720
2576
  endTime,
2721
- message: error === null || error === void 0 ? void 0 : error.message,
2577
+ message: error?.message,
2722
2578
  }
2723
2579
  : {
2724
2580
  status: "PASSED",
@@ -2729,39 +2585,28 @@ class StableBrowser {
2729
2585
  }
2730
2586
  }
2731
2587
  async closePage(options = {}, world = null) {
2732
- const startTime = Date.now();
2733
- let error = null;
2734
- let screenshotId = null;
2735
- let screenshotPath = null;
2736
- const info = {};
2588
+ const state = {
2589
+ options,
2590
+ world,
2591
+ locate: false,
2592
+ scroll: false,
2593
+ highlight: false,
2594
+ type: Types.CLOSE_PAGE,
2595
+ text: `Close page`,
2596
+ operation: "closePage",
2597
+ log: "***** close page *****\n",
2598
+ throwError: false,
2599
+ };
2737
2600
  try {
2601
+ await _preCommand(state, this);
2738
2602
  await this.page.close();
2739
2603
  }
2740
2604
  catch (e) {
2741
2605
  console.log(".");
2606
+ await _commandError(state, e, this);
2742
2607
  }
2743
2608
  finally {
2744
- await new Promise((resolve) => setTimeout(resolve, 2000));
2745
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world));
2746
- const endTime = Date.now();
2747
- this._reportToWorld(world, {
2748
- type: Types.CLOSE_PAGE,
2749
- text: "close page",
2750
- screenshotId,
2751
- result: error
2752
- ? {
2753
- status: "FAILED",
2754
- startTime,
2755
- endTime,
2756
- message: error === null || error === void 0 ? void 0 : error.message,
2757
- }
2758
- : {
2759
- status: "PASSED",
2760
- startTime,
2761
- endTime,
2762
- },
2763
- info: info,
2764
- });
2609
+ _commandFinally(state, this);
2765
2610
  }
2766
2611
  }
2767
2612
  async setViewportSize(width, hight, options = {}, world = null) {
@@ -2781,6 +2626,7 @@ class StableBrowser {
2781
2626
  }
2782
2627
  catch (e) {
2783
2628
  console.log(".");
2629
+ await _commandError({ text: "setViewportSize", operation: "setViewportSize", width, hight, info }, e, this);
2784
2630
  }
2785
2631
  finally {
2786
2632
  await new Promise((resolve) => setTimeout(resolve, 2000));
@@ -2795,7 +2641,7 @@ class StableBrowser {
2795
2641
  status: "FAILED",
2796
2642
  startTime,
2797
2643
  endTime,
2798
- message: error === null || error === void 0 ? void 0 : error.message,
2644
+ message: error?.message,
2799
2645
  }
2800
2646
  : {
2801
2647
  status: "PASSED",
@@ -2817,6 +2663,7 @@ class StableBrowser {
2817
2663
  }
2818
2664
  catch (e) {
2819
2665
  console.log(".");
2666
+ await _commandError({ text: "reloadPage", operation: "reloadPage", info }, e, this);
2820
2667
  }
2821
2668
  finally {
2822
2669
  await new Promise((resolve) => setTimeout(resolve, 2000));
@@ -2831,7 +2678,7 @@ class StableBrowser {
2831
2678
  status: "FAILED",
2832
2679
  startTime,
2833
2680
  endTime,
2834
- message: error === null || error === void 0 ? void 0 : error.message,
2681
+ message: error?.message,
2835
2682
  }
2836
2683
  : {
2837
2684
  status: "PASSED",