automation_model 1.0.446-dev → 1.0.446-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,15 +47,22 @@ const Types = {
45
47
  };
46
48
  export const apps = {};
47
49
  class StableBrowser {
48
- constructor(browser, page, logger = null, context = null) {
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";
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
- this.project_path = null;
54
- this.webLogFile = null;
55
- this.configuration = null;
56
- this.appName = "main";
65
+ this.world = world;
57
66
  if (!this.logger) {
58
67
  this.logger = console;
59
68
  }
@@ -78,20 +87,32 @@ class StableBrowser {
78
87
  catch (e) {
79
88
  this.logger.error("unable to read ai_config.json");
80
89
  }
81
- context.pageLoading = { status: false };
82
- context.pages = [this.page];
83
90
  const logFolder = path.join(this.project_path, "logs", "web");
84
- this.webLogFile = this.getWebLogFile(logFolder);
85
- this.registerEventListeners(context);
91
+ this.world = world;
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);
86
97
  }
87
98
  registerEventListeners(context) {
88
- this.registerConsoleLogListener(this.page, context, this.webLogFile);
89
- this.registerRequestListener();
99
+ this.registerConsoleLogListener(this.page, context);
100
+ this.registerRequestListener(this.page, context, this.webLogFile);
101
+ if (!context.pageLoading) {
102
+ context.pageLoading = { status: false };
103
+ }
90
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
+ }
91
110
  context.pageLoading.status = true;
92
111
  this.page = page;
93
112
  context.page = page;
94
113
  context.pages.push(page);
114
+ registerNetworkEvents(this.world, this, context, this.page);
115
+ registerDownloadEvent(this.page, this.world, context);
95
116
  page.on("close", async () => {
96
117
  if (this.context && this.context.pages && this.context.pages.length > 1) {
97
118
  this.context.pages.pop();
@@ -121,10 +142,10 @@ class StableBrowser {
121
142
  if (this.appName === appName) {
122
143
  return;
123
144
  }
124
- let newContextCreated = false;
145
+ let navigate = false;
125
146
  if (!apps[appName]) {
126
147
  let newContext = await getContext(null, false, this.logger, appName, false, this);
127
- newContextCreated = true;
148
+ navigate = true;
128
149
  apps[appName] = {
129
150
  context: newContext,
130
151
  browser: newContext.browser,
@@ -136,8 +157,7 @@ class StableBrowser {
136
157
  this._copyContext(apps[appName], this);
137
158
  apps[this.appName] = tempContext;
138
159
  this.appName = appName;
139
- if (newContextCreated) {
140
- this.registerEventListeners(this.context);
160
+ if (navigate) {
141
161
  await this.goto(this.context.environment.baseUrl);
142
162
  await this.waitForPageLoad();
143
163
  }
@@ -158,37 +178,63 @@ class StableBrowser {
158
178
  const fileName = nextIndex + ".json";
159
179
  return path.join(logFolder, fileName);
160
180
  }
161
- registerConsoleLogListener(page, context, logFile) {
181
+ registerConsoleLogListener(page, context) {
162
182
  if (!this.context.webLogger) {
163
183
  this.context.webLogger = [];
164
184
  }
165
185
  page.on("console", async (msg) => {
166
- this.context.webLogger.push({
186
+ const obj = {
167
187
  type: msg.type(),
168
188
  text: msg.text(),
169
189
  location: msg.location(),
170
190
  time: new Date().toISOString(),
171
- });
172
- await fs.promises.writeFile(logFile, JSON.stringify(this.context.webLogger, null, 2));
191
+ };
192
+ this.context.webLogger.push(obj);
193
+ if (msg.type() === "error") {
194
+ this.world?.attach(JSON.stringify(obj), { mediaType: "application/json+log" });
195
+ }
173
196
  });
174
197
  }
175
- registerRequestListener() {
176
- this.page.on("request", async (data) => {
198
+ registerRequestListener(page, context, logFile) {
199
+ if (!this.context.networkLogger) {
200
+ this.context.networkLogger = [];
201
+ }
202
+ page.on("request", async (data) => {
203
+ const startTime = new Date().getTime();
177
204
  try {
178
- const pageUrl = new URL(this.page.url());
205
+ const pageUrl = new URL(page.url());
179
206
  const requestUrl = new URL(data.url());
180
207
  if (pageUrl.hostname === requestUrl.hostname) {
181
208
  const method = data.method();
182
- if (method === "POST" || method === "GET" || method === "PUT" || method === "DELETE" || method === "PATCH") {
209
+ if (["POST", "GET", "PUT", "DELETE", "PATCH"].includes(method)) {
183
210
  const token = await data.headerValue("Authorization");
184
211
  if (token) {
185
- this.context.authtoken = token;
212
+ context.authtoken = token;
186
213
  }
187
214
  }
188
215
  }
216
+ const response = await data.response();
217
+ const endTime = new Date().getTime();
218
+ const obj = {
219
+ url: data.url(),
220
+ method: data.method(),
221
+ postData: data.postData(),
222
+ error: data.failure() ? data.failure().errorText : null,
223
+ duration: endTime - startTime,
224
+ startTime,
225
+ };
226
+ context.networkLogger.push(obj);
227
+ this.world?.attach(JSON.stringify(obj), { mediaType: "application/json+network" });
189
228
  }
190
229
  catch (error) {
191
230
  console.error("Error in request listener", error);
231
+ context.networkLogger.push({
232
+ error: "not able to listen",
233
+ message: error.message,
234
+ stack: error.stack,
235
+ time: new Date().toISOString(),
236
+ });
237
+ // await fs.promises.writeFile(logFile, JSON.stringify(context.networkLogger, null, 2));
192
238
  }
193
239
  });
194
240
  }
@@ -203,20 +249,6 @@ class StableBrowser {
203
249
  timeout: 60000,
204
250
  });
205
251
  }
206
- _validateSelectors(selectors) {
207
- if (!selectors) {
208
- throw new Error("selectors is null");
209
- }
210
- if (!selectors.locators) {
211
- throw new Error("selectors.locators is null");
212
- }
213
- if (!Array.isArray(selectors.locators)) {
214
- throw new Error("selectors.locators expected to be array");
215
- }
216
- if (selectors.locators.length === 0) {
217
- throw new Error("selectors.locators expected to be non empty array");
218
- }
219
- }
220
252
  _fixUsingParams(text, _params) {
221
253
  if (!_params || typeof text !== "string") {
222
254
  return text;
@@ -284,7 +316,7 @@ class StableBrowser {
284
316
  locatorReturn = scope.getByRole(role, { name }, { exact: flags === "i" });
285
317
  }
286
318
  }
287
- if (locator === null || locator === void 0 ? void 0 : locator.engine) {
319
+ if (locator?.engine) {
288
320
  if (locator.engine === "css") {
289
321
  locatorReturn = scope.locator(locator.selector);
290
322
  }
@@ -305,7 +337,10 @@ class StableBrowser {
305
337
  return locatorReturn;
306
338
  }
307
339
  async _locateElmentByTextClimbCss(scope, text, climb, css, _params) {
308
- 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);
309
344
  if (result.elementCount === 0) {
310
345
  return;
311
346
  }
@@ -320,7 +355,7 @@ class StableBrowser {
320
355
  }
321
356
  async _locateElementByText(scope, text1, tag1, regex1 = false, partial1, _params) {
322
357
  //const stringifyText = JSON.stringify(text);
323
- return await scope.evaluate(([text, tag, regex, partial]) => {
358
+ return await scope.locator(":root").evaluate((_node, [text, tag, regex, partial]) => {
324
359
  function isParent(parent, child) {
325
360
  let currentNode = child.parentNode;
326
361
  while (currentNode !== null) {
@@ -332,6 +367,15 @@ class StableBrowser {
332
367
  return false;
333
368
  }
334
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;
335
379
  function collectAllShadowDomElements(element, result = []) {
336
380
  // Check and add the element if it has a shadow root
337
381
  if (element.shadowRoot) {
@@ -348,7 +392,11 @@ class StableBrowser {
348
392
  }
349
393
  document.collectAllShadowDomElements = collectAllShadowDomElements;
350
394
  if (!tag) {
351
- tag = "*";
395
+ tag = "*:not(script, style, head)";
396
+ }
397
+ let regexpSearch = document.getRegex(text);
398
+ if (regexpSearch) {
399
+ regex = true;
352
400
  }
353
401
  let elements = Array.from(document.querySelectorAll(tag));
354
402
  let shadowHosts = [];
@@ -365,7 +413,9 @@ class StableBrowser {
365
413
  let randomToken = null;
366
414
  const foundElements = [];
367
415
  if (regex) {
368
- let regexpSearch = new RegExp(text, "im");
416
+ if (!regexpSearch) {
417
+ regexpSearch = new RegExp(text, "im");
418
+ }
369
419
  for (let i = 0; i < elements.length; i++) {
370
420
  const element = elements[i];
371
421
  if ((element.innerText && regexpSearch.test(element.innerText)) ||
@@ -379,8 +429,8 @@ class StableBrowser {
379
429
  for (let i = 0; i < elements.length; i++) {
380
430
  const element = elements[i];
381
431
  if (partial) {
382
- if ((element.innerText && element.innerText.trim().includes(text)) ||
383
- (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()))) {
384
434
  foundElements.push(element);
385
435
  }
386
436
  }
@@ -425,18 +475,29 @@ class StableBrowser {
425
475
  }
426
476
  async _collectLocatorInformation(selectorHierarchy, index = 0, scope, foundLocators, _params, info, visibleOnly = true) {
427
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
+ }
428
484
  //info.log += "searching for locator " + JSON.stringify(locatorSearch) + "\n";
429
485
  let locator = null;
430
486
  if (locatorSearch.climb && locatorSearch.climb >= 0) {
431
487
  let locatorString = await this._locateElmentByTextClimbCss(scope, locatorSearch.text, locatorSearch.climb, locatorSearch.css, _params);
432
488
  if (!locatorString) {
489
+ info.failCause.textNotFound = true;
490
+ info.failCause.lastError = "failed to locate element by text: " + locatorSearch.text;
433
491
  return;
434
492
  }
435
493
  locator = this._getLocator({ css: locatorString }, scope, _params);
436
494
  }
437
495
  else if (locatorSearch.text) {
438
- 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);
439
498
  if (result.elementCount === 0) {
499
+ info.failCause.textNotFound = true;
500
+ info.failCause.lastError = "failed to locate element by text: " + text;
440
501
  return;
441
502
  }
442
503
  locatorSearch.css = "[data-blinq-id='blinq-id-" + result.randomToken + "']";
@@ -453,6 +514,9 @@ class StableBrowser {
453
514
  // cssHref = true;
454
515
  // }
455
516
  let count = await locator.count();
517
+ if (count > 0 && !info.failCause.count) {
518
+ info.failCause.count = count;
519
+ }
456
520
  //info.log += "total elements found " + count + "\n";
457
521
  //let visibleCount = 0;
458
522
  let visibleLocator = null;
@@ -470,6 +534,8 @@ class StableBrowser {
470
534
  foundLocators.push(locator.nth(j));
471
535
  }
472
536
  else {
537
+ info.failCause.visible = visible;
538
+ info.failCause.enabled = enabled;
473
539
  if (!info.printMessages) {
474
540
  info.printMessages = {};
475
541
  }
@@ -481,6 +547,11 @@ class StableBrowser {
481
547
  }
482
548
  }
483
549
  async closeUnexpectedPopups(info, _params) {
550
+ if (!info) {
551
+ info = {};
552
+ info.failCause = {};
553
+ info.log = "";
554
+ }
484
555
  if (this.configuration.popupHandlers && this.configuration.popupHandlers.length > 0) {
485
556
  if (!info) {
486
557
  info = {};
@@ -521,7 +592,10 @@ class StableBrowser {
521
592
  }
522
593
  return { rerun: false };
523
594
  }
524
- async _locate(selectors, info, _params, timeout = 30000) {
595
+ async _locate(selectors, info, _params, timeout) {
596
+ if (!timeout) {
597
+ timeout = 30000;
598
+ }
525
599
  for (let i = 0; i < 3; i++) {
526
600
  info.log += "attempt " + i + ": total locators " + selectors.locators.length + "\n";
527
601
  for (let j = 0; j < selectors.locators.length; j++) {
@@ -535,32 +609,46 @@ class StableBrowser {
535
609
  }
536
610
  throw new Error("unable to locate element " + JSON.stringify(selectors));
537
611
  }
538
- async _locate_internal(selectors, info, _params, timeout = 30000) {
539
- let highPriorityTimeout = 5000;
540
- let visibleOnlyTimeout = 6000;
541
- let startTime = performance.now();
542
- let locatorsCount = 0;
543
- //let arrayMode = Array.isArray(selectors);
612
+ async _findFrameScope(selectors, timeout = 30000, info) {
613
+ if (!info) {
614
+ info = {};
615
+ info.failCause = {};
616
+ info.log = "";
617
+ }
544
618
  let scope = this.page;
619
+ if (selectors.frame) {
620
+ return selectors.frame;
621
+ }
545
622
  if (selectors.iframe_src || selectors.frameLocators) {
546
- const findFrame = (frame, framescope) => {
623
+ const findFrame = async (frame, framescope) => {
547
624
  for (let i = 0; i < frame.selectors.length; i++) {
548
625
  let frameLocator = frame.selectors[i];
549
626
  if (frameLocator.css) {
550
- framescope = framescope.frameLocator(frameLocator.css);
551
- 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
+ }
552
641
  }
553
642
  }
554
643
  if (frame.children) {
555
- return findFrame(frame.children, framescope);
644
+ return await findFrame(frame.children, framescope);
556
645
  }
557
646
  return framescope;
558
647
  };
559
- info.log += "searching for iframe " + selectors.iframe_src + "/" + selectors.frameLocators + "\n";
560
648
  while (true) {
561
649
  let frameFound = false;
562
650
  if (selectors.nestFrmLoc) {
563
- scope = findFrame(selectors.nestFrmLoc, scope);
651
+ scope = await findFrame(selectors.nestFrmLoc, scope);
564
652
  frameFound = true;
565
653
  break;
566
654
  }
@@ -580,6 +668,8 @@ class StableBrowser {
580
668
  if (!scope) {
581
669
  info.log += "unable to locate iframe " + selectors.iframe_src + "\n";
582
670
  if (performance.now() - startTime > timeout) {
671
+ info.failCause.iframeNotFound = true;
672
+ info.failCause.lastError = "unable to locate iframe " + selectors.iframe_src;
583
673
  throw new Error("unable to locate iframe " + selectors.iframe_src);
584
674
  }
585
675
  await new Promise((resolve) => setTimeout(resolve, 1000));
@@ -589,6 +679,30 @@ class StableBrowser {
589
679
  }
590
680
  }
591
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);
592
706
  let selectorsLocators = null;
593
707
  selectorsLocators = selectors.locators;
594
708
  // group selectors by priority
@@ -690,6 +804,8 @@ class StableBrowser {
690
804
  }
691
805
  this.logger.debug("unable to locate unique element, total elements found " + locatorsCount);
692
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";
693
809
  throw new Error("failed to locate first element no elements found, " + info.log);
694
810
  }
695
811
  async _scanLocatorsGroup(locatorsGroup, scope, _params, info, visibleOnly) {
@@ -721,89 +837,129 @@ class StableBrowser {
721
837
  });
722
838
  result.locatorIndex = i;
723
839
  }
840
+ if (foundLocators.length > 1) {
841
+ info.failCause.foundMultiple = true;
842
+ }
724
843
  }
725
844
  return result;
726
845
  }
727
- async click(selectors, _params, options = {}, world = null) {
728
- this._validateSelectors(selectors);
846
+ async simpleClick(elementDescription, _params, options = {}, world = null) {
729
847
  const startTime = Date.now();
730
- if (options && options.context) {
731
- selectors.locators[0].text = options.context;
848
+ let timeout = 30000;
849
+ if (options && options.timeout) {
850
+ timeout = options.timeout;
732
851
  }
733
- const info = {};
734
- info.log = "***** click on " + selectors.element_name + " *****\n";
735
- info.operation = "click";
736
- info.selectors = selectors;
737
- let error = null;
738
- let screenshotId = null;
739
- 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
+ };
740
919
  try {
741
- let element = await this._locate(selectors, info, _params);
742
- await this.scrollIfNeeded(element, info);
743
- ({ 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
+ }
744
924
  try {
745
- await this._highlightElements(element);
746
- await element.click();
925
+ await state.element.click();
747
926
  await new Promise((resolve) => setTimeout(resolve, 1000));
748
927
  }
749
928
  catch (e) {
750
929
  // await this.closeUnexpectedPopups();
751
- info.log += "click failed, will try again" + "\n";
752
- element = await this._locate(selectors, info, _params);
753
- await element.dispatchEvent("click");
930
+ state.element = await this._locate(selectors, state.info, _params);
931
+ await state.element.dispatchEvent("click");
754
932
  await new Promise((resolve) => setTimeout(resolve, 1000));
755
933
  }
756
934
  await this.waitForPageLoad();
757
- return info;
935
+ return state.info;
758
936
  }
759
937
  catch (e) {
760
- this.logger.error("click failed " + info.log);
761
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
762
- info.screenshotPath = screenshotPath;
763
- Object.assign(e, { info: info });
764
- error = e;
765
- throw e;
938
+ await _commandError(state, e, this);
766
939
  }
767
940
  finally {
768
- const endTime = Date.now();
769
- this._reportToWorld(world, {
770
- element_name: selectors.element_name,
771
- type: Types.CLICK,
772
- text: `Click element`,
773
- screenshotId,
774
- result: error
775
- ? {
776
- status: "FAILED",
777
- startTime,
778
- endTime,
779
- message: error === null || error === void 0 ? void 0 : error.message,
780
- }
781
- : {
782
- status: "PASSED",
783
- startTime,
784
- endTime,
785
- },
786
- info: info,
787
- });
941
+ _commandFinally(state, this);
788
942
  }
789
943
  }
790
944
  async setCheck(selectors, checked = true, _params, options = {}, world = null) {
791
- this._validateSelectors(selectors);
792
- const startTime = Date.now();
793
- const info = {};
794
- info.log = "";
795
- info.operation = "setCheck";
796
- info.checked = checked;
797
- info.selectors = selectors;
798
- let error = null;
799
- let screenshotId = null;
800
- 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
+ };
801
955
  try {
802
- let element = await this._locate(selectors, info, _params);
803
- ({ 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));
804
960
  try {
805
- await this._highlightElements(element);
806
- await element.setChecked(checked);
961
+ // await this._highlightElements(element);
962
+ await state.element.setChecked(checked);
807
963
  await new Promise((resolve) => setTimeout(resolve, 1000));
808
964
  }
809
965
  catch (e) {
@@ -812,179 +968,108 @@ class StableBrowser {
812
968
  }
813
969
  else {
814
970
  //await this.closeUnexpectedPopups();
815
- info.log += "setCheck failed, will try again" + "\n";
816
- element = await this._locate(selectors, info, _params);
817
- 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 });
818
974
  await new Promise((resolve) => setTimeout(resolve, 1000));
819
975
  }
820
976
  }
821
977
  await this.waitForPageLoad();
822
- return info;
978
+ return state.info;
823
979
  }
824
980
  catch (e) {
825
- this.logger.error("setCheck failed " + info.log);
826
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
827
- info.screenshotPath = screenshotPath;
828
- Object.assign(e, { info: info });
829
- error = e;
830
- throw e;
981
+ await _commandError(state, e, this);
831
982
  }
832
983
  finally {
833
- const endTime = Date.now();
834
- this._reportToWorld(world, {
835
- element_name: selectors.element_name,
836
- type: checked ? Types.CHECK : Types.UNCHECK,
837
- text: checked ? `Check element` : `Uncheck element`,
838
- screenshotId,
839
- result: error
840
- ? {
841
- status: "FAILED",
842
- startTime,
843
- endTime,
844
- message: error === null || error === void 0 ? void 0 : error.message,
845
- }
846
- : {
847
- status: "PASSED",
848
- startTime,
849
- endTime,
850
- },
851
- info: info,
852
- });
984
+ _commandFinally(state, this);
853
985
  }
854
986
  }
855
987
  async hover(selectors, _params, options = {}, world = null) {
856
- this._validateSelectors(selectors);
857
- const startTime = Date.now();
858
- const info = {};
859
- info.log = "";
860
- info.operation = "hover";
861
- info.selectors = selectors;
862
- let error = null;
863
- let screenshotId = null;
864
- 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
+ };
865
998
  try {
866
- let element = await this._locate(selectors, info, _params);
867
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
999
+ await _preCommand(state, this);
868
1000
  try {
869
- await this._highlightElements(element);
870
- await element.hover();
1001
+ await state.element.hover();
871
1002
  await new Promise((resolve) => setTimeout(resolve, 1000));
872
1003
  }
873
1004
  catch (e) {
874
1005
  //await this.closeUnexpectedPopups();
875
- info.log += "hover failed, will try again" + "\n";
876
- element = await this._locate(selectors, info, _params);
877
- 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 });
878
1009
  await new Promise((resolve) => setTimeout(resolve, 1000));
879
1010
  }
880
1011
  await this.waitForPageLoad();
881
- return info;
1012
+ return state.info;
882
1013
  }
883
1014
  catch (e) {
884
- this.logger.error("hover failed " + info.log);
885
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
886
- info.screenshotPath = screenshotPath;
887
- Object.assign(e, { info: info });
888
- error = e;
889
- throw e;
1015
+ await _commandError(state, e, this);
890
1016
  }
891
1017
  finally {
892
- const endTime = Date.now();
893
- this._reportToWorld(world, {
894
- element_name: selectors.element_name,
895
- type: Types.HOVER,
896
- text: `Hover element`,
897
- screenshotId,
898
- result: error
899
- ? {
900
- status: "FAILED",
901
- startTime,
902
- endTime,
903
- message: error === null || error === void 0 ? void 0 : error.message,
904
- }
905
- : {
906
- status: "PASSED",
907
- startTime,
908
- endTime,
909
- },
910
- info: info,
911
- });
1018
+ _commandFinally(state, this);
912
1019
  }
913
1020
  }
914
1021
  async selectOption(selectors, values, _params = null, options = {}, world = null) {
915
- this._validateSelectors(selectors);
916
1022
  if (!values) {
917
1023
  throw new Error("values is null");
918
1024
  }
919
- const startTime = Date.now();
920
- let error = null;
921
- let screenshotId = null;
922
- let screenshotPath = null;
923
- const info = {};
924
- info.log = "";
925
- info.operation = "selectOptions";
926
- 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
+ };
927
1036
  try {
928
- let element = await this._locate(selectors, info, _params);
929
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1037
+ await _preCommand(state, this);
930
1038
  try {
931
- await this._highlightElements(element);
932
- await element.selectOption(values);
1039
+ await state.element.selectOption(values);
933
1040
  }
934
1041
  catch (e) {
935
1042
  //await this.closeUnexpectedPopups();
936
- info.log += "selectOption failed, will try force" + "\n";
937
- 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 });
938
1045
  }
939
1046
  await this.waitForPageLoad();
940
- return info;
1047
+ return state.info;
941
1048
  }
942
1049
  catch (e) {
943
- this.logger.error("selectOption failed " + info.log);
944
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
945
- info.screenshotPath = screenshotPath;
946
- Object.assign(e, { info: info });
947
- this.logger.info("click failed, will try next selector");
948
- error = e;
949
- throw e;
1050
+ await _commandError(state, e, this);
950
1051
  }
951
1052
  finally {
952
- const endTime = Date.now();
953
- this._reportToWorld(world, {
954
- element_name: selectors.element_name,
955
- type: Types.SELECT,
956
- text: `Select option: ${values}`,
957
- value: values.toString(),
958
- screenshotId,
959
- result: error
960
- ? {
961
- status: "FAILED",
962
- startTime,
963
- endTime,
964
- message: error === null || error === void 0 ? void 0 : error.message,
965
- }
966
- : {
967
- status: "PASSED",
968
- startTime,
969
- endTime,
970
- },
971
- info: info,
972
- });
1053
+ _commandFinally(state, this);
973
1054
  }
974
1055
  }
975
1056
  async type(_value, _params = null, options = {}, world = null) {
976
- const startTime = Date.now();
977
- let error = null;
978
- let screenshotId = null;
979
- let screenshotPath = null;
980
- const info = {};
981
- info.log = "";
982
- info.operation = "type";
983
- _value = this._fixUsingParams(_value, _params);
984
- 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
+ };
985
1070
  try {
986
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
987
- const valueSegment = _value.split("&&");
1071
+ await _preCommand(state, this);
1072
+ const valueSegment = state.value.split("&&");
988
1073
  for (let i = 0; i < valueSegment.length; i++) {
989
1074
  if (i > 0) {
990
1075
  await new Promise((resolve) => setTimeout(resolve, 1000));
@@ -1004,108 +1089,53 @@ class StableBrowser {
1004
1089
  await this.page.keyboard.type(value);
1005
1090
  }
1006
1091
  }
1007
- return info;
1092
+ return state.info;
1008
1093
  }
1009
1094
  catch (e) {
1010
- //await this.closeUnexpectedPopups();
1011
- this.logger.error("type failed " + info.log);
1012
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1013
- info.screenshotPath = screenshotPath;
1014
- Object.assign(e, { info: info });
1015
- error = e;
1016
- throw e;
1095
+ await _commandError(state, e, this);
1017
1096
  }
1018
1097
  finally {
1019
- const endTime = Date.now();
1020
- this._reportToWorld(world, {
1021
- type: Types.TYPE_PRESS,
1022
- screenshotId,
1023
- value: _value,
1024
- text: `type value: ${_value}`,
1025
- result: error
1026
- ? {
1027
- status: "FAILED",
1028
- startTime,
1029
- endTime,
1030
- message: error === null || error === void 0 ? void 0 : error.message,
1031
- }
1032
- : {
1033
- status: "PASSED",
1034
- startTime,
1035
- endTime,
1036
- },
1037
- info: info,
1038
- });
1098
+ _commandFinally(state, this);
1039
1099
  }
1040
1100
  }
1041
1101
  async setInputValue(selectors, value, _params = null, options = {}, world = null) {
1042
- // set input value for non fillable inputs like date, time, range, color, etc.
1043
- this._validateSelectors(selectors);
1044
- const startTime = Date.now();
1045
- const info = {};
1046
- info.log = "***** set input value " + selectors.element_name + " *****\n";
1047
- info.operation = "setInputValue";
1048
- info.selectors = selectors;
1049
- value = this._fixUsingParams(value, _params);
1050
- info.value = value;
1051
- let error = null;
1052
- let screenshotId = null;
1053
- 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
+ };
1054
1113
  try {
1055
- value = await this._replaceWithLocalData(value, this);
1056
- let element = await this._locate(selectors, info, _params);
1057
- await this.scrollIfNeeded(element, info);
1058
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1059
- await this._highlightElements(element);
1114
+ await _preCommand(state, this);
1115
+ let value = await this._replaceWithLocalData(state.value, this);
1060
1116
  try {
1061
- await element.evaluateHandle((el, value) => {
1117
+ await state.element.evaluateHandle((el, value) => {
1062
1118
  el.value = value;
1063
1119
  }, value);
1064
1120
  }
1065
1121
  catch (error) {
1066
1122
  this.logger.error("setInputValue failed, will try again");
1067
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1068
- info.screenshotPath = screenshotPath;
1069
- Object.assign(error, { info: info });
1070
- await element.evaluateHandle((el, value) => {
1123
+ await _screenshot(state, this);
1124
+ Object.assign(error, { info: state.info });
1125
+ await state.element.evaluateHandle((el, value) => {
1071
1126
  el.value = value;
1072
1127
  });
1073
1128
  }
1074
1129
  }
1075
1130
  catch (e) {
1076
- this.logger.error("setInputValue failed " + info.log);
1077
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1078
- info.screenshotPath = screenshotPath;
1079
- Object.assign(e, { info: info });
1080
- error = e;
1081
- throw e;
1131
+ await _commandError(state, e, this);
1082
1132
  }
1083
1133
  finally {
1084
- const endTime = Date.now();
1085
- this._reportToWorld(world, {
1086
- element_name: selectors.element_name,
1087
- type: Types.SET_INPUT,
1088
- text: `Set input value`,
1089
- value: value,
1090
- screenshotId,
1091
- result: error
1092
- ? {
1093
- status: "FAILED",
1094
- startTime,
1095
- endTime,
1096
- message: error === null || error === void 0 ? void 0 : error.message,
1097
- }
1098
- : {
1099
- status: "PASSED",
1100
- startTime,
1101
- endTime,
1102
- },
1103
- info: info,
1104
- });
1134
+ _commandFinally(state, this);
1105
1135
  }
1106
1136
  }
1107
1137
  async setDateTime(selectors, value, format = null, enter = false, _params = null, options = {}, world = null) {
1108
- this._validateSelectors(selectors);
1138
+ _validateSelectors(selectors);
1109
1139
  const startTime = Date.now();
1110
1140
  let error = null;
1111
1141
  let screenshotId = null;
@@ -1171,7 +1201,8 @@ class StableBrowser {
1171
1201
  }
1172
1202
  catch (e) {
1173
1203
  error = e;
1174
- throw e;
1204
+ // throw e;
1205
+ await _commandError({ text: "setDateTime", operation: "setDateTime", selectors, value, info }, e, this);
1175
1206
  }
1176
1207
  finally {
1177
1208
  const endTime = Date.now();
@@ -1198,32 +1229,32 @@ class StableBrowser {
1198
1229
  }
1199
1230
  }
1200
1231
  async clickType(selectors, _value, enter = false, _params = null, options = {}, world = null) {
1201
- this._validateSelectors(selectors);
1202
- const startTime = Date.now();
1203
- let error = null;
1204
- let screenshotId = null;
1205
- let screenshotPath = null;
1206
- const info = {};
1207
- info.log = "***** clickType on " + selectors.element_name + " with value " + _value + "*****\n";
1208
- info.operation = "clickType";
1209
- info.selectors = selectors;
1232
+ _value = unEscapeString(_value);
1210
1233
  const newValue = await this._replaceWithLocalData(_value, world);
1234
+ const state = {
1235
+ selectors,
1236
+ _params,
1237
+ value: newValue,
1238
+ originalValue: _value,
1239
+ options,
1240
+ world,
1241
+ type: Types.FILL,
1242
+ text: `Click type input with value: ${_value}`,
1243
+ operation: "clickType",
1244
+ log: "***** clickType on " + selectors.element_name + " with value " + maskValue(_value) + "*****\n",
1245
+ };
1211
1246
  if (newValue !== _value) {
1212
1247
  //this.logger.info(_value + "=" + newValue);
1213
1248
  _value = newValue;
1214
1249
  }
1215
- info.value = _value;
1216
1250
  try {
1217
- let element = await this._locate(selectors, info, _params);
1218
- //insert red border around the element
1219
- await this.scrollIfNeeded(element, info);
1220
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1221
- await this._highlightElements(element);
1251
+ await _preCommand(state, this);
1252
+ state.info.value = _value;
1222
1253
  if (options === null || options === undefined || !options.press) {
1223
1254
  try {
1224
- let currentValue = await element.inputValue();
1255
+ let currentValue = await state.element.inputValue();
1225
1256
  if (currentValue) {
1226
- await element.fill("");
1257
+ await state.element.fill("");
1227
1258
  }
1228
1259
  }
1229
1260
  catch (e) {
@@ -1232,22 +1263,22 @@ class StableBrowser {
1232
1263
  }
1233
1264
  if (options === null || options === undefined || options.press) {
1234
1265
  try {
1235
- await element.click({ timeout: 5000 });
1266
+ await state.element.click({ timeout: 5000 });
1236
1267
  }
1237
1268
  catch (e) {
1238
- await element.dispatchEvent("click");
1269
+ await state.element.dispatchEvent("click");
1239
1270
  }
1240
1271
  }
1241
1272
  else {
1242
1273
  try {
1243
- await element.focus();
1274
+ await state.element.focus();
1244
1275
  }
1245
1276
  catch (e) {
1246
- await element.dispatchEvent("focus");
1277
+ await state.element.dispatchEvent("focus");
1247
1278
  }
1248
1279
  }
1249
1280
  await new Promise((resolve) => setTimeout(resolve, 500));
1250
- const valueSegment = _value.split("&&");
1281
+ const valueSegment = state.value.split("&&");
1251
1282
  for (let i = 0; i < valueSegment.length; i++) {
1252
1283
  if (i > 0) {
1253
1284
  await new Promise((resolve) => setTimeout(resolve, 1000));
@@ -1267,13 +1298,14 @@ class StableBrowser {
1267
1298
  await new Promise((resolve) => setTimeout(resolve, 500));
1268
1299
  }
1269
1300
  }
1301
+ await _screenshot(state, this);
1270
1302
  if (enter === true) {
1271
1303
  await new Promise((resolve) => setTimeout(resolve, 2000));
1272
1304
  await this.page.keyboard.press("Enter");
1273
1305
  await this.waitForPageLoad();
1274
1306
  }
1275
1307
  else if (enter === false) {
1276
- await element.dispatchEvent("change");
1308
+ await state.element.dispatchEvent("change");
1277
1309
  //await this.page.keyboard.press("Tab");
1278
1310
  }
1279
1311
  else {
@@ -1282,103 +1314,50 @@ class StableBrowser {
1282
1314
  await this.waitForPageLoad();
1283
1315
  }
1284
1316
  }
1285
- return info;
1317
+ return state.info;
1286
1318
  }
1287
1319
  catch (e) {
1288
- //await this.closeUnexpectedPopups();
1289
- this.logger.error("fill failed " + JSON.stringify(info));
1290
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1291
- info.screenshotPath = screenshotPath;
1292
- Object.assign(e, { info: info });
1293
- error = e;
1294
- throw e;
1320
+ await _commandError(state, e, this);
1295
1321
  }
1296
1322
  finally {
1297
- const endTime = Date.now();
1298
- this._reportToWorld(world, {
1299
- element_name: selectors.element_name,
1300
- type: Types.FILL,
1301
- screenshotId,
1302
- value: _value,
1303
- text: `clickType input with value: ${_value}`,
1304
- result: error
1305
- ? {
1306
- status: "FAILED",
1307
- startTime,
1308
- endTime,
1309
- message: error === null || error === void 0 ? void 0 : error.message,
1310
- }
1311
- : {
1312
- status: "PASSED",
1313
- startTime,
1314
- endTime,
1315
- },
1316
- info: info,
1317
- });
1323
+ _commandFinally(state, this);
1318
1324
  }
1319
1325
  }
1320
1326
  async fill(selectors, value, enter = false, _params = null, options = {}, world = null) {
1321
- this._validateSelectors(selectors);
1322
- const startTime = Date.now();
1323
- let error = null;
1324
- let screenshotId = null;
1325
- let screenshotPath = null;
1326
- const info = {};
1327
- info.log = "***** fill on " + selectors.element_name + " with value " + value + "*****\n";
1328
- info.operation = "fill";
1329
- info.selectors = selectors;
1330
- info.value = value;
1327
+ const state = {
1328
+ selectors,
1329
+ _params,
1330
+ value: unEscapeString(value),
1331
+ options,
1332
+ world,
1333
+ type: Types.FILL,
1334
+ text: `Fill input with value: ${value}`,
1335
+ operation: "fill",
1336
+ log: "***** fill on " + selectors.element_name + " with value " + value + "*****\n",
1337
+ };
1331
1338
  try {
1332
- let element = await this._locate(selectors, info, _params);
1333
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1334
- await this._highlightElements(element);
1335
- await element.fill(value);
1336
- await element.dispatchEvent("change");
1339
+ await _preCommand(state, this);
1340
+ await state.element.fill(value);
1341
+ await state.element.dispatchEvent("change");
1337
1342
  if (enter) {
1338
1343
  await new Promise((resolve) => setTimeout(resolve, 2000));
1339
1344
  await this.page.keyboard.press("Enter");
1340
1345
  }
1341
1346
  await this.waitForPageLoad();
1342
- return info;
1347
+ return state.info;
1343
1348
  }
1344
1349
  catch (e) {
1345
- //await this.closeUnexpectedPopups();
1346
- this.logger.error("fill failed " + info.log);
1347
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1348
- info.screenshotPath = screenshotPath;
1349
- Object.assign(e, { info: info });
1350
- error = e;
1351
- throw e;
1350
+ await _commandError(state, e, this);
1352
1351
  }
1353
1352
  finally {
1354
- const endTime = Date.now();
1355
- this._reportToWorld(world, {
1356
- element_name: selectors.element_name,
1357
- type: Types.FILL,
1358
- screenshotId,
1359
- value,
1360
- text: `Fill input with value: ${value}`,
1361
- result: error
1362
- ? {
1363
- status: "FAILED",
1364
- startTime,
1365
- endTime,
1366
- message: error === null || error === void 0 ? void 0 : error.message,
1367
- }
1368
- : {
1369
- status: "PASSED",
1370
- startTime,
1371
- endTime,
1372
- },
1373
- info: info,
1374
- });
1353
+ _commandFinally(state, this);
1375
1354
  }
1376
1355
  }
1377
1356
  async getText(selectors, _params = null, options = {}, info = {}, world = null) {
1378
1357
  return await this._getText(selectors, 0, _params, options, info, world);
1379
1358
  }
1380
1359
  async _getText(selectors, climb, _params = null, options = {}, info = {}, world = null) {
1381
- this._validateSelectors(selectors);
1360
+ _validateSelectors(selectors);
1382
1361
  let screenshotId = null;
1383
1362
  let screenshotPath = null;
1384
1363
  if (!info.log) {
@@ -1422,165 +1401,124 @@ class StableBrowser {
1422
1401
  }
1423
1402
  }
1424
1403
  async containsPattern(selectors, pattern, text, _params = null, options = {}, world = null) {
1425
- var _a;
1426
- this._validateSelectors(selectors);
1427
1404
  if (!pattern) {
1428
1405
  throw new Error("pattern is null");
1429
1406
  }
1430
1407
  if (!text) {
1431
1408
  throw new Error("text is null");
1432
1409
  }
1410
+ const state = {
1411
+ selectors,
1412
+ _params,
1413
+ pattern,
1414
+ value: pattern,
1415
+ options,
1416
+ world,
1417
+ locate: false,
1418
+ scroll: false,
1419
+ screenshot: false,
1420
+ highlight: false,
1421
+ type: Types.VERIFY_ELEMENT_CONTAINS_TEXT,
1422
+ text: `Verify element contains pattern: ${pattern}`,
1423
+ operation: "containsPattern",
1424
+ log: "***** verify element " + selectors.element_name + " contains pattern " + pattern + " *****\n",
1425
+ };
1433
1426
  const newValue = await this._replaceWithLocalData(text, world);
1434
1427
  if (newValue !== text) {
1435
1428
  this.logger.info(text + "=" + newValue);
1436
1429
  text = newValue;
1437
1430
  }
1438
- const startTime = Date.now();
1439
- let error = null;
1440
- let screenshotId = null;
1441
- let screenshotPath = null;
1442
- const info = {};
1443
- info.log =
1444
- "***** verify element " + selectors.element_name + " contains pattern " + pattern + "/" + text + " *****\n";
1445
- info.operation = "containsPattern";
1446
- info.selectors = selectors;
1447
- info.value = text;
1448
- info.pattern = pattern;
1449
1431
  let foundObj = null;
1450
1432
  try {
1451
- foundObj = await this._getText(selectors, 0, _params, options, info, world);
1433
+ await _preCommand(state, this);
1434
+ state.info.pattern = pattern;
1435
+ foundObj = await this._getText(selectors, 0, _params, options, state.info, world);
1452
1436
  if (foundObj && foundObj.element) {
1453
- await this.scrollIfNeeded(foundObj.element, info);
1437
+ await this.scrollIfNeeded(foundObj.element, state.info);
1454
1438
  }
1455
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1439
+ await _screenshot(state, this);
1456
1440
  let escapedText = text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
1457
1441
  pattern = pattern.replace("{text}", escapedText);
1458
1442
  let regex = new RegExp(pattern, "im");
1459
- 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))) {
1460
- info.foundText = foundObj === null || foundObj === void 0 ? void 0 : foundObj.text;
1443
+ if (!regex.test(foundObj?.text) && !foundObj?.value?.includes(text)) {
1444
+ state.info.foundText = foundObj?.text;
1461
1445
  throw new Error("element doesn't contain text " + text);
1462
1446
  }
1463
- return info;
1447
+ return state.info;
1464
1448
  }
1465
1449
  catch (e) {
1466
- //await this.closeUnexpectedPopups();
1467
- this.logger.error("verify element contains text failed " + info.log);
1468
- this.logger.error("found text " + (foundObj === null || foundObj === void 0 ? void 0 : foundObj.text) + " pattern " + pattern);
1469
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1470
- info.screenshotPath = screenshotPath;
1471
- Object.assign(e, { info: info });
1472
- error = e;
1473
- throw e;
1450
+ this.logger.error("found text " + foundObj?.text + " pattern " + pattern);
1451
+ await _commandError(state, e, this);
1474
1452
  }
1475
1453
  finally {
1476
- const endTime = Date.now();
1477
- this._reportToWorld(world, {
1478
- element_name: selectors.element_name,
1479
- type: Types.VERIFY_ELEMENT_CONTAINS_TEXT,
1480
- value: pattern,
1481
- text: `Verify element contains pattern: ${pattern}`,
1482
- screenshotId: foundObj === null || foundObj === void 0 ? void 0 : foundObj.screenshotId,
1483
- result: error
1484
- ? {
1485
- status: "FAILED",
1486
- startTime,
1487
- endTime,
1488
- message: error === null || error === void 0 ? void 0 : error.message,
1489
- }
1490
- : {
1491
- status: "PASSED",
1492
- startTime,
1493
- endTime,
1494
- },
1495
- info: info,
1496
- });
1454
+ _commandFinally(state, this);
1497
1455
  }
1498
1456
  }
1499
1457
  async containsText(selectors, text, climb, _params = null, options = {}, world = null) {
1500
- var _a, _b, _c;
1501
- this._validateSelectors(selectors);
1458
+ const state = {
1459
+ selectors,
1460
+ _params,
1461
+ value: text,
1462
+ options,
1463
+ world,
1464
+ locate: false,
1465
+ scroll: false,
1466
+ screenshot: false,
1467
+ highlight: false,
1468
+ type: Types.VERIFY_ELEMENT_CONTAINS_TEXT,
1469
+ text: `Verify element contains text: ${text}`,
1470
+ operation: "containsText",
1471
+ log: "***** verify element " + selectors.element_name + " contains text " + text + " *****\n",
1472
+ };
1502
1473
  if (!text) {
1503
1474
  throw new Error("text is null");
1504
1475
  }
1505
- const startTime = Date.now();
1506
- let error = null;
1507
- let screenshotId = null;
1508
- let screenshotPath = null;
1509
- const info = {};
1510
- info.log = "***** verify element " + selectors.element_name + " contains text " + text + " *****\n";
1511
- info.operation = "containsText";
1512
- info.selectors = selectors;
1476
+ text = unEscapeString(text);
1513
1477
  const newValue = await this._replaceWithLocalData(text, world);
1514
1478
  if (newValue !== text) {
1515
1479
  this.logger.info(text + "=" + newValue);
1516
1480
  text = newValue;
1517
1481
  }
1518
- info.value = text;
1519
1482
  let foundObj = null;
1520
1483
  try {
1521
- foundObj = await this._getText(selectors, climb, _params, options, info, world);
1484
+ await _preCommand(state, this);
1485
+ foundObj = await this._getText(selectors, climb, _params, options, state.info, world);
1522
1486
  if (foundObj && foundObj.element) {
1523
- await this.scrollIfNeeded(foundObj.element, info);
1487
+ await this.scrollIfNeeded(foundObj.element, state.info);
1524
1488
  }
1525
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1489
+ await _screenshot(state, this);
1526
1490
  const dateAlternatives = findDateAlternatives(text);
1527
1491
  const numberAlternatives = findNumberAlternatives(text);
1528
1492
  if (dateAlternatives.date) {
1529
1493
  for (let i = 0; i < dateAlternatives.dates.length; i++) {
1530
- if ((foundObj === null || foundObj === void 0 ? void 0 : foundObj.text.includes(dateAlternatives.dates[i])) ||
1531
- ((_a = foundObj === null || foundObj === void 0 ? void 0 : foundObj.value) === null || _a === void 0 ? void 0 : _a.includes(dateAlternatives.dates[i]))) {
1532
- return info;
1494
+ if (foundObj?.text.includes(dateAlternatives.dates[i]) ||
1495
+ foundObj?.value?.includes(dateAlternatives.dates[i])) {
1496
+ return state.info;
1533
1497
  }
1534
1498
  }
1535
1499
  throw new Error("element doesn't contain text " + text);
1536
1500
  }
1537
1501
  else if (numberAlternatives.number) {
1538
1502
  for (let i = 0; i < numberAlternatives.numbers.length; i++) {
1539
- if ((foundObj === null || foundObj === void 0 ? void 0 : foundObj.text.includes(numberAlternatives.numbers[i])) ||
1540
- ((_b = foundObj === null || foundObj === void 0 ? void 0 : foundObj.value) === null || _b === void 0 ? void 0 : _b.includes(numberAlternatives.numbers[i]))) {
1541
- return info;
1503
+ if (foundObj?.text.includes(numberAlternatives.numbers[i]) ||
1504
+ foundObj?.value?.includes(numberAlternatives.numbers[i])) {
1505
+ return state.info;
1542
1506
  }
1543
1507
  }
1544
1508
  throw new Error("element doesn't contain text " + text);
1545
1509
  }
1546
- 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))) {
1547
- info.foundText = foundObj === null || foundObj === void 0 ? void 0 : foundObj.text;
1548
- info.value = foundObj === null || foundObj === void 0 ? void 0 : foundObj.value;
1510
+ else if (!foundObj?.text.includes(text) && !foundObj?.value?.includes(text)) {
1511
+ state.info.foundText = foundObj?.text;
1512
+ state.info.value = foundObj?.value;
1549
1513
  throw new Error("element doesn't contain text " + text);
1550
1514
  }
1551
- return info;
1515
+ return state.info;
1552
1516
  }
1553
1517
  catch (e) {
1554
- //await this.closeUnexpectedPopups();
1555
- this.logger.error("verify element contains text failed " + info.log);
1556
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1557
- info.screenshotPath = screenshotPath;
1558
- Object.assign(e, { info: info });
1559
- error = e;
1560
- throw e;
1518
+ await _commandError(state, e, this);
1561
1519
  }
1562
1520
  finally {
1563
- const endTime = Date.now();
1564
- this._reportToWorld(world, {
1565
- element_name: selectors.element_name,
1566
- type: Types.VERIFY_ELEMENT_CONTAINS_TEXT,
1567
- text: `Verify element contains text: ${text}`,
1568
- value: text,
1569
- screenshotId: foundObj === null || foundObj === void 0 ? void 0 : foundObj.screenshotId,
1570
- result: error
1571
- ? {
1572
- status: "FAILED",
1573
- startTime,
1574
- endTime,
1575
- message: error === null || error === void 0 ? void 0 : error.message,
1576
- }
1577
- : {
1578
- status: "PASSED",
1579
- startTime,
1580
- endTime,
1581
- },
1582
- info: info,
1583
- });
1521
+ _commandFinally(state, this);
1584
1522
  }
1585
1523
  }
1586
1524
  _getDataFile(world = null) {
@@ -1809,7 +1747,6 @@ class StableBrowser {
1809
1747
  }
1810
1748
  async takeScreenshot(screenshotPath) {
1811
1749
  const playContext = this.context.playContext;
1812
- const client = await playContext.newCDPSession(this.page);
1813
1750
  // Using CDP to capture the screenshot
1814
1751
  const viewportWidth = Math.max(...(await this.page.evaluate(() => [
1815
1752
  document.body.scrollWidth,
@@ -1819,164 +1756,109 @@ class StableBrowser {
1819
1756
  document.body.clientWidth,
1820
1757
  document.documentElement.clientWidth,
1821
1758
  ])));
1822
- const viewportHeight = Math.max(...(await this.page.evaluate(() => [
1823
- document.body.scrollHeight,
1824
- document.documentElement.scrollHeight,
1825
- document.body.offsetHeight,
1826
- document.documentElement.offsetHeight,
1827
- document.body.clientHeight,
1828
- document.documentElement.clientHeight,
1829
- ])));
1830
- const { data } = await client.send("Page.captureScreenshot", {
1831
- format: "png",
1832
- // clip: {
1833
- // x: 0,
1834
- // y: 0,
1835
- // width: viewportWidth,
1836
- // height: viewportHeight,
1837
- // scale: 1,
1838
- // },
1839
- });
1840
- if (!screenshotPath) {
1841
- return data;
1842
- }
1843
- let screenshotBuffer = Buffer.from(data, "base64");
1844
- const sharpBuffer = sharp(screenshotBuffer);
1845
- const metadata = await sharpBuffer.metadata();
1846
- //check if you are on retina display and reduce the quality of the image
1847
- if (metadata.width > viewportWidth || metadata.height > viewportHeight) {
1848
- screenshotBuffer = await sharpBuffer
1849
- .resize(viewportWidth, viewportHeight, {
1850
- fit: sharp.fit.inside,
1851
- withoutEnlargement: true,
1852
- })
1853
- .toBuffer();
1854
- }
1855
- fs.writeFileSync(screenshotPath, screenshotBuffer);
1856
- await client.detach();
1759
+ let screenshotBuffer = null;
1760
+ if (this.context.browserName === "chromium") {
1761
+ const client = await playContext.newCDPSession(this.page);
1762
+ const { data } = await client.send("Page.captureScreenshot", {
1763
+ format: "png",
1764
+ // clip: {
1765
+ // x: 0,
1766
+ // y: 0,
1767
+ // width: viewportWidth,
1768
+ // height: viewportHeight,
1769
+ // scale: 1,
1770
+ // },
1771
+ });
1772
+ await client.detach();
1773
+ if (!screenshotPath) {
1774
+ return data;
1775
+ }
1776
+ screenshotBuffer = Buffer.from(data, "base64");
1777
+ }
1778
+ else {
1779
+ screenshotBuffer = await this.page.screenshot();
1780
+ }
1781
+ let image = await Jimp.read(screenshotBuffer);
1782
+ // Get the image dimensions
1783
+ const { width, height } = image.bitmap;
1784
+ const resizeRatio = viewportWidth / width;
1785
+ // Resize the image to fit within the viewport dimensions without enlarging
1786
+ if (width > viewportWidth) {
1787
+ image = image.resize({ w: viewportWidth, h: height * resizeRatio }); // Resize the image while maintaining aspect ratio
1788
+ await image.write(screenshotPath);
1789
+ }
1790
+ else {
1791
+ fs.writeFileSync(screenshotPath, screenshotBuffer);
1792
+ }
1857
1793
  }
1858
1794
  async verifyElementExistInPage(selectors, _params = null, options = {}, world = null) {
1859
- this._validateSelectors(selectors);
1860
- const startTime = Date.now();
1861
- let error = null;
1862
- let screenshotId = null;
1863
- let screenshotPath = null;
1795
+ const state = {
1796
+ selectors,
1797
+ _params,
1798
+ options,
1799
+ world,
1800
+ type: Types.VERIFY_ELEMENT_CONTAINS_TEXT,
1801
+ text: `Verify element exists in page`,
1802
+ operation: "verifyElementExistInPage",
1803
+ log: "***** verify element " + selectors.element_name + " exists in page *****\n",
1804
+ };
1864
1805
  await new Promise((resolve) => setTimeout(resolve, 2000));
1865
- const info = {};
1866
- info.log = "***** verify element " + selectors.element_name + " exists in page *****\n";
1867
- info.operation = "verify";
1868
- info.selectors = selectors;
1869
1806
  try {
1870
- const element = await this._locate(selectors, info, _params);
1871
- if (element) {
1872
- await this.scrollIfNeeded(element, info);
1873
- }
1874
- await this._highlightElements(element);
1875
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1876
- await expect(element).toHaveCount(1, { timeout: 10000 });
1877
- return info;
1807
+ await _preCommand(state, this);
1808
+ await expect(state.element).toHaveCount(1, { timeout: 10000 });
1809
+ return state.info;
1878
1810
  }
1879
1811
  catch (e) {
1880
- //await this.closeUnexpectedPopups();
1881
- this.logger.error("verify failed " + info.log);
1882
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1883
- info.screenshotPath = screenshotPath;
1884
- Object.assign(e, { info: info });
1885
- error = e;
1886
- throw e;
1812
+ await _commandError(state, e, this);
1887
1813
  }
1888
1814
  finally {
1889
- const endTime = Date.now();
1890
- this._reportToWorld(world, {
1891
- element_name: selectors.element_name,
1892
- type: Types.VERIFY_ELEMENT_CONTAINS_TEXT,
1893
- text: "Verify element exists in page",
1894
- screenshotId,
1895
- result: error
1896
- ? {
1897
- status: "FAILED",
1898
- startTime,
1899
- endTime,
1900
- message: error === null || error === void 0 ? void 0 : error.message,
1901
- }
1902
- : {
1903
- status: "PASSED",
1904
- startTime,
1905
- endTime,
1906
- },
1907
- info: info,
1908
- });
1815
+ _commandFinally(state, this);
1909
1816
  }
1910
1817
  }
1911
1818
  async extractAttribute(selectors, attribute, variable, _params = null, options = {}, world = null) {
1912
- this._validateSelectors(selectors);
1913
- const startTime = Date.now();
1914
- let error = null;
1915
- let screenshotId = null;
1916
- let screenshotPath = null;
1819
+ const state = {
1820
+ selectors,
1821
+ _params,
1822
+ attribute,
1823
+ variable,
1824
+ options,
1825
+ world,
1826
+ type: Types.EXTRACT,
1827
+ text: `Extract attribute from element`,
1828
+ operation: "extractAttribute",
1829
+ log: "***** extract attribute " + attribute + " from " + selectors.element_name + " *****\n",
1830
+ };
1917
1831
  await new Promise((resolve) => setTimeout(resolve, 2000));
1918
- const info = {};
1919
- info.log = "***** extract attribute " + attribute + " from " + selectors.element_name + " *****\n";
1920
- info.operation = "extract";
1921
- info.selectors = selectors;
1922
1832
  try {
1923
- const element = await this._locate(selectors, info, _params);
1924
- await this._highlightElements(element);
1925
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1833
+ await _preCommand(state, this);
1926
1834
  switch (attribute) {
1927
1835
  case "inner_text":
1928
- info.value = await element.innerText();
1836
+ state.value = await state.element.innerText();
1929
1837
  break;
1930
1838
  case "href":
1931
- info.value = await element.getAttribute("href");
1839
+ state.value = await state.element.getAttribute("href");
1932
1840
  break;
1933
1841
  case "value":
1934
- info.value = await element.inputValue();
1842
+ state.value = await state.element.inputValue();
1935
1843
  break;
1936
1844
  default:
1937
- info.value = await element.getAttribute(attribute);
1845
+ state.value = await state.element.getAttribute(attribute);
1938
1846
  break;
1939
1847
  }
1940
- this[variable] = info.value;
1848
+ state.info.value = state.value;
1849
+ this[variable] = state.value;
1941
1850
  if (world) {
1942
- world[variable] = info.value;
1851
+ world[variable] = state.value;
1943
1852
  }
1944
- this.setTestData({ [variable]: info.value }, world);
1945
- this.logger.info("set test data: " + variable + "=" + info.value);
1946
- return info;
1853
+ this.setTestData({ [variable]: state.value }, world);
1854
+ this.logger.info("set test data: " + variable + "=" + state.value);
1855
+ return state.info;
1947
1856
  }
1948
1857
  catch (e) {
1949
- //await this.closeUnexpectedPopups();
1950
- this.logger.error("extract failed " + info.log);
1951
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1952
- info.screenshotPath = screenshotPath;
1953
- Object.assign(e, { info: info });
1954
- error = e;
1955
- throw e;
1858
+ await _commandError(state, e, this);
1956
1859
  }
1957
1860
  finally {
1958
- const endTime = Date.now();
1959
- this._reportToWorld(world, {
1960
- element_name: selectors.element_name,
1961
- type: Types.EXTRACT_ATTRIBUTE,
1962
- variable: variable,
1963
- value: info.value,
1964
- text: "Extract attribute from element",
1965
- screenshotId,
1966
- result: error
1967
- ? {
1968
- status: "FAILED",
1969
- startTime,
1970
- endTime,
1971
- message: error === null || error === void 0 ? void 0 : error.message,
1972
- }
1973
- : {
1974
- status: "PASSED",
1975
- startTime,
1976
- endTime,
1977
- },
1978
- info: info,
1979
- });
1861
+ _commandFinally(state, this);
1980
1862
  }
1981
1863
  }
1982
1864
  async extractEmailData(emailAddress, options, world) {
@@ -2053,7 +1935,8 @@ class StableBrowser {
2053
1935
  catch (e) {
2054
1936
  errorCount++;
2055
1937
  if (errorCount > 3) {
2056
- throw e;
1938
+ // throw e;
1939
+ await _commandError({ text: "extractEmailData", operation: "extractEmailData", emailAddress, info: {} }, e, this);
2057
1940
  }
2058
1941
  // ignore
2059
1942
  }
@@ -2164,7 +2047,8 @@ class StableBrowser {
2164
2047
  info.screenshotPath = screenshotPath;
2165
2048
  Object.assign(e, { info: info });
2166
2049
  error = e;
2167
- throw e;
2050
+ // throw e;
2051
+ await _commandError({ text: "verifyPagePath", operation: "verifyPagePath", pathPart, info }, e, this);
2168
2052
  }
2169
2053
  finally {
2170
2054
  const endTime = Date.now();
@@ -2177,7 +2061,7 @@ class StableBrowser {
2177
2061
  status: "FAILED",
2178
2062
  startTime,
2179
2063
  endTime,
2180
- message: error === null || error === void 0 ? void 0 : error.message,
2064
+ message: error?.message,
2181
2065
  }
2182
2066
  : {
2183
2067
  status: "PASSED",
@@ -2213,20 +2097,20 @@ class StableBrowser {
2213
2097
  for (let i = 0; i < frames.length; i++) {
2214
2098
  if (dateAlternatives.date) {
2215
2099
  for (let j = 0; j < dateAlternatives.dates.length; j++) {
2216
- const result = await this._locateElementByText(frames[i], dateAlternatives.dates[j], "*", true, {});
2100
+ const result = await this._locateElementByText(frames[i], dateAlternatives.dates[j], "*:not(script, style, head)", true, true, {});
2217
2101
  result.frame = frames[i];
2218
2102
  results.push(result);
2219
2103
  }
2220
2104
  }
2221
2105
  else if (numberAlternatives.number) {
2222
2106
  for (let j = 0; j < numberAlternatives.numbers.length; j++) {
2223
- const result = await this._locateElementByText(frames[i], numberAlternatives.numbers[j], "*", true, {});
2107
+ const result = await this._locateElementByText(frames[i], numberAlternatives.numbers[j], "*:not(script, style, head)", true, true, {});
2224
2108
  result.frame = frames[i];
2225
2109
  results.push(result);
2226
2110
  }
2227
2111
  }
2228
2112
  else {
2229
- const result = await this._locateElementByText(frames[i], text, "*", true, {});
2113
+ const result = await this._locateElementByText(frames[i], text, "*:not(script, style, head)", true, true, {});
2230
2114
  result.frame = frames[i];
2231
2115
  results.push(result);
2232
2116
  }
@@ -2262,7 +2146,8 @@ class StableBrowser {
2262
2146
  info.screenshotPath = screenshotPath;
2263
2147
  Object.assign(e, { info: info });
2264
2148
  error = e;
2265
- throw e;
2149
+ // throw e;
2150
+ await _commandError({ text: "verifyTextExistInPage", operation: "verifyTextExistInPage", text, info }, e, this);
2266
2151
  }
2267
2152
  finally {
2268
2153
  const endTime = Date.now();
@@ -2275,7 +2160,7 @@ class StableBrowser {
2275
2160
  status: "FAILED",
2276
2161
  startTime,
2277
2162
  endTime,
2278
- message: error === null || error === void 0 ? void 0 : error.message,
2163
+ message: error?.message,
2279
2164
  }
2280
2165
  : {
2281
2166
  status: "PASSED",
@@ -2346,7 +2231,8 @@ class StableBrowser {
2346
2231
  info.screenshotPath = screenshotPath;
2347
2232
  Object.assign(e, { info: info });
2348
2233
  error = e;
2349
- throw e;
2234
+ // throw e;
2235
+ await _commandError({ text: "visualVerification", operation: "visualVerification", text, info }, e, this);
2350
2236
  }
2351
2237
  finally {
2352
2238
  const endTime = Date.now();
@@ -2359,7 +2245,7 @@ class StableBrowser {
2359
2245
  status: "FAILED",
2360
2246
  startTime,
2361
2247
  endTime,
2362
- message: error === null || error === void 0 ? void 0 : error.message,
2248
+ message: error?.message,
2363
2249
  }
2364
2250
  : {
2365
2251
  status: "PASSED",
@@ -2391,7 +2277,7 @@ class StableBrowser {
2391
2277
  this.logger.info("Table data verified");
2392
2278
  }
2393
2279
  async getTableData(selectors, _params = null, options = {}, world = null) {
2394
- this._validateSelectors(selectors);
2280
+ _validateSelectors(selectors);
2395
2281
  const startTime = Date.now();
2396
2282
  let error = null;
2397
2283
  let screenshotId = null;
@@ -2413,7 +2299,8 @@ class StableBrowser {
2413
2299
  info.screenshotPath = screenshotPath;
2414
2300
  Object.assign(e, { info: info });
2415
2301
  error = e;
2416
- throw e;
2302
+ // throw e;
2303
+ await _commandError({ text: "getTableData", operation: "getTableData", selectors, info }, e, this);
2417
2304
  }
2418
2305
  finally {
2419
2306
  const endTime = Date.now();
@@ -2427,7 +2314,7 @@ class StableBrowser {
2427
2314
  status: "FAILED",
2428
2315
  startTime,
2429
2316
  endTime,
2430
- message: error === null || error === void 0 ? void 0 : error.message,
2317
+ message: error?.message,
2431
2318
  }
2432
2319
  : {
2433
2320
  status: "PASSED",
@@ -2439,7 +2326,7 @@ class StableBrowser {
2439
2326
  }
2440
2327
  }
2441
2328
  async analyzeTable(selectors, query, operator, value, _params = null, options = {}, world = null) {
2442
- this._validateSelectors(selectors);
2329
+ _validateSelectors(selectors);
2443
2330
  if (!query) {
2444
2331
  throw new Error("query is null");
2445
2332
  }
@@ -2578,7 +2465,8 @@ class StableBrowser {
2578
2465
  info.screenshotPath = screenshotPath;
2579
2466
  Object.assign(e, { info: info });
2580
2467
  error = e;
2581
- throw e;
2468
+ // throw e;
2469
+ await _commandError({ text: "analyzeTable", operation: "analyzeTable", selectors, query, operator, value }, e, this);
2582
2470
  }
2583
2471
  finally {
2584
2472
  const endTime = Date.now();
@@ -2592,7 +2480,7 @@ class StableBrowser {
2592
2480
  status: "FAILED",
2593
2481
  startTime,
2594
2482
  endTime,
2595
- message: error === null || error === void 0 ? void 0 : error.message,
2483
+ message: error?.message,
2596
2484
  }
2597
2485
  : {
2598
2486
  status: "PASSED",
@@ -2604,27 +2492,7 @@ class StableBrowser {
2604
2492
  }
2605
2493
  }
2606
2494
  async _replaceWithLocalData(value, world, _decrypt = true, totpWait = true) {
2607
- if (!value) {
2608
- return value;
2609
- }
2610
- // find all the accurance of {{(.*?)}} and replace with the value
2611
- let regex = /{{(.*?)}}/g;
2612
- let matches = value.match(regex);
2613
- if (matches) {
2614
- const testData = this.getTestData(world);
2615
- for (let i = 0; i < matches.length; i++) {
2616
- let match = matches[i];
2617
- let key = match.substring(2, match.length - 2);
2618
- let newValue = objectPath.get(testData, key, null);
2619
- if (newValue !== null) {
2620
- value = value.replace(match, newValue);
2621
- }
2622
- }
2623
- }
2624
- if ((value.startsWith("secret:") || value.startsWith("totp:")) && _decrypt) {
2625
- return await decrypt(value, null, totpWait);
2626
- }
2627
- return value;
2495
+ return await replaceWithLocalTestData(value, world, _decrypt, totpWait, this.context, this);
2628
2496
  }
2629
2497
  _getLoadTimeout(options) {
2630
2498
  let timeout = 15000;
@@ -2684,7 +2552,7 @@ class StableBrowser {
2684
2552
  status: "FAILED",
2685
2553
  startTime,
2686
2554
  endTime,
2687
- message: error === null || error === void 0 ? void 0 : error.message,
2555
+ message: error?.message,
2688
2556
  }
2689
2557
  : {
2690
2558
  status: "PASSED",
@@ -2705,6 +2573,7 @@ class StableBrowser {
2705
2573
  }
2706
2574
  catch (e) {
2707
2575
  console.log(".");
2576
+ await _commandError({ text: "closePage", operation: "closePage", info }, e, this);
2708
2577
  }
2709
2578
  finally {
2710
2579
  await new Promise((resolve) => setTimeout(resolve, 2000));
@@ -2719,7 +2588,7 @@ class StableBrowser {
2719
2588
  status: "FAILED",
2720
2589
  startTime,
2721
2590
  endTime,
2722
- message: error === null || error === void 0 ? void 0 : error.message,
2591
+ message: error?.message,
2723
2592
  }
2724
2593
  : {
2725
2594
  status: "PASSED",
@@ -2747,6 +2616,7 @@ class StableBrowser {
2747
2616
  }
2748
2617
  catch (e) {
2749
2618
  console.log(".");
2619
+ await _commandError({ text: "setViewportSize", operation: "setViewportSize", width, hight, info }, e, this);
2750
2620
  }
2751
2621
  finally {
2752
2622
  await new Promise((resolve) => setTimeout(resolve, 2000));
@@ -2761,7 +2631,7 @@ class StableBrowser {
2761
2631
  status: "FAILED",
2762
2632
  startTime,
2763
2633
  endTime,
2764
- message: error === null || error === void 0 ? void 0 : error.message,
2634
+ message: error?.message,
2765
2635
  }
2766
2636
  : {
2767
2637
  status: "PASSED",
@@ -2783,6 +2653,7 @@ class StableBrowser {
2783
2653
  }
2784
2654
  catch (e) {
2785
2655
  console.log(".");
2656
+ await _commandError({ text: "reloadPage", operation: "reloadPage", info }, e, this);
2786
2657
  }
2787
2658
  finally {
2788
2659
  await new Promise((resolve) => setTimeout(resolve, 2000));
@@ -2797,7 +2668,7 @@ class StableBrowser {
2797
2668
  status: "FAILED",
2798
2669
  startTime,
2799
2670
  endTime,
2800
- message: error === null || error === void 0 ? void 0 : error.message,
2671
+ message: error?.message,
2801
2672
  }
2802
2673
  : {
2803
2674
  status: "PASSED",
@@ -2982,5 +2853,10 @@ const KEYBOARD_EVENTS = [
2982
2853
  "TVAntennaCable",
2983
2854
  "TVAudioDescription",
2984
2855
  ];
2856
+ function unEscapeString(str) {
2857
+ const placeholder = "__NEWLINE__";
2858
+ str = str.replace(new RegExp(placeholder, "g"), "\n");
2859
+ return str;
2860
+ }
2985
2861
  export { StableBrowser };
2986
2862
  //# sourceMappingURL=stable_browser.js.map