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