automation_model 1.0.445-dev → 1.0.445-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,19 +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";
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";
18
21
  const Types = {
19
22
  CLICK: "click_element",
20
23
  NAVIGATE: "navigate",
@@ -42,15 +45,24 @@ const Types = {
42
45
  LOAD_DATA: "load_data",
43
46
  SET_INPUT: "set_input",
44
47
  };
48
+ export const apps = {};
45
49
  class StableBrowser {
46
- 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) {
47
61
  this.browser = browser;
48
62
  this.page = page;
49
63
  this.logger = logger;
50
64
  this.context = context;
51
- this.project_path = null;
52
- this.webLogFile = null;
53
- this.configuration = null;
65
+ this.world = world;
54
66
  if (!this.logger) {
55
67
  this.logger = console;
56
68
  }
@@ -76,16 +88,31 @@ class StableBrowser {
76
88
  this.logger.error("unable to read ai_config.json");
77
89
  }
78
90
  const logFolder = path.join(this.project_path, "logs", "web");
79
- this.webLogFile = this.getWebLogFile(logFolder);
80
- this.registerConsoleLogListener(page, context, this.webLogFile);
81
- this.registerRequestListener();
91
+ this.world = world;
82
92
  context.pages = [this.page];
83
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);
97
+ }
98
+ registerEventListeners(context) {
99
+ this.registerConsoleLogListener(this.page, context);
100
+ this.registerRequestListener(this.page, context, this.webLogFile);
101
+ if (!context.pageLoading) {
102
+ context.pageLoading = { status: false };
103
+ }
84
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
+ }
85
110
  context.pageLoading.status = true;
86
111
  this.page = page;
87
112
  context.page = page;
88
113
  context.pages.push(page);
114
+ registerNetworkEvents(this.world, this, context, this.page);
115
+ registerDownloadEvent(this.page, this.world, context);
89
116
  page.on("close", async () => {
90
117
  if (this.context && this.context.pages && this.context.pages.length > 1) {
91
118
  this.context.pages.pop();
@@ -110,6 +137,36 @@ class StableBrowser {
110
137
  context.pageLoading.status = false;
111
138
  }.bind(this));
112
139
  }
140
+ async switchApp(appName) {
141
+ // check if the current app (this.appName) is the same as the new app
142
+ if (this.appName === appName) {
143
+ return;
144
+ }
145
+ let navigate = false;
146
+ if (!apps[appName]) {
147
+ let newContext = await getContext(null, false, this.logger, appName, false, this);
148
+ navigate = true;
149
+ apps[appName] = {
150
+ context: newContext,
151
+ browser: newContext.browser,
152
+ page: newContext.page,
153
+ };
154
+ }
155
+ const tempContext = {};
156
+ this._copyContext(this, tempContext);
157
+ this._copyContext(apps[appName], this);
158
+ apps[this.appName] = tempContext;
159
+ this.appName = appName;
160
+ if (navigate) {
161
+ await this.goto(this.context.environment.baseUrl);
162
+ await this.waitForPageLoad();
163
+ }
164
+ }
165
+ _copyContext(from, to) {
166
+ to.browser = from.browser;
167
+ to.page = from.page;
168
+ to.context = from.context;
169
+ }
113
170
  getWebLogFile(logFolder) {
114
171
  if (!fs.existsSync(logFolder)) {
115
172
  fs.mkdirSync(logFolder, { recursive: true });
@@ -121,37 +178,63 @@ class StableBrowser {
121
178
  const fileName = nextIndex + ".json";
122
179
  return path.join(logFolder, fileName);
123
180
  }
124
- registerConsoleLogListener(page, context, logFile) {
181
+ registerConsoleLogListener(page, context) {
125
182
  if (!this.context.webLogger) {
126
183
  this.context.webLogger = [];
127
184
  }
128
185
  page.on("console", async (msg) => {
129
- this.context.webLogger.push({
186
+ const obj = {
130
187
  type: msg.type(),
131
188
  text: msg.text(),
132
189
  location: msg.location(),
133
190
  time: new Date().toISOString(),
134
- });
135
- 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
+ }
136
196
  });
137
197
  }
138
- registerRequestListener() {
139
- 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();
140
204
  try {
141
- const pageUrl = new URL(this.page.url());
205
+ const pageUrl = new URL(page.url());
142
206
  const requestUrl = new URL(data.url());
143
207
  if (pageUrl.hostname === requestUrl.hostname) {
144
208
  const method = data.method();
145
- if (method === "POST" || method === "GET" || method === "PUT" || method === "DELETE" || method === "PATCH") {
209
+ if (["POST", "GET", "PUT", "DELETE", "PATCH"].includes(method)) {
146
210
  const token = await data.headerValue("Authorization");
147
211
  if (token) {
148
- this.context.authtoken = token;
212
+ context.authtoken = token;
149
213
  }
150
214
  }
151
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" });
152
228
  }
153
229
  catch (error) {
154
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));
155
238
  }
156
239
  });
157
240
  }
@@ -166,20 +249,6 @@ class StableBrowser {
166
249
  timeout: 60000,
167
250
  });
168
251
  }
169
- _validateSelectors(selectors) {
170
- if (!selectors) {
171
- throw new Error("selectors is null");
172
- }
173
- if (!selectors.locators) {
174
- throw new Error("selectors.locators is null");
175
- }
176
- if (!Array.isArray(selectors.locators)) {
177
- throw new Error("selectors.locators expected to be array");
178
- }
179
- if (selectors.locators.length === 0) {
180
- throw new Error("selectors.locators expected to be non empty array");
181
- }
182
- }
183
252
  _fixUsingParams(text, _params) {
184
253
  if (!_params || typeof text !== "string") {
185
254
  return text;
@@ -247,7 +316,7 @@ class StableBrowser {
247
316
  locatorReturn = scope.getByRole(role, { name }, { exact: flags === "i" });
248
317
  }
249
318
  }
250
- if (locator === null || locator === void 0 ? void 0 : locator.engine) {
319
+ if (locator?.engine) {
251
320
  if (locator.engine === "css") {
252
321
  locatorReturn = scope.locator(locator.selector);
253
322
  }
@@ -268,7 +337,10 @@ class StableBrowser {
268
337
  return locatorReturn;
269
338
  }
270
339
  async _locateElmentByTextClimbCss(scope, text, climb, css, _params) {
271
- 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);
272
344
  if (result.elementCount === 0) {
273
345
  return;
274
346
  }
@@ -283,7 +355,7 @@ class StableBrowser {
283
355
  }
284
356
  async _locateElementByText(scope, text1, tag1, regex1 = false, partial1, _params) {
285
357
  //const stringifyText = JSON.stringify(text);
286
- return await scope.evaluate(([text, tag, regex, partial]) => {
358
+ return await scope.locator(":root").evaluate((_node, [text, tag, regex, partial]) => {
287
359
  function isParent(parent, child) {
288
360
  let currentNode = child.parentNode;
289
361
  while (currentNode !== null) {
@@ -295,6 +367,15 @@ class StableBrowser {
295
367
  return false;
296
368
  }
297
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;
298
379
  function collectAllShadowDomElements(element, result = []) {
299
380
  // Check and add the element if it has a shadow root
300
381
  if (element.shadowRoot) {
@@ -311,7 +392,11 @@ class StableBrowser {
311
392
  }
312
393
  document.collectAllShadowDomElements = collectAllShadowDomElements;
313
394
  if (!tag) {
314
- tag = "*";
395
+ tag = "*:not(script, style, head)";
396
+ }
397
+ let regexpSearch = document.getRegex(text);
398
+ if (regexpSearch) {
399
+ regex = true;
315
400
  }
316
401
  let elements = Array.from(document.querySelectorAll(tag));
317
402
  let shadowHosts = [];
@@ -328,7 +413,9 @@ class StableBrowser {
328
413
  let randomToken = null;
329
414
  const foundElements = [];
330
415
  if (regex) {
331
- let regexpSearch = new RegExp(text, "im");
416
+ if (!regexpSearch) {
417
+ regexpSearch = new RegExp(text, "im");
418
+ }
332
419
  for (let i = 0; i < elements.length; i++) {
333
420
  const element = elements[i];
334
421
  if ((element.innerText && regexpSearch.test(element.innerText)) ||
@@ -342,8 +429,8 @@ class StableBrowser {
342
429
  for (let i = 0; i < elements.length; i++) {
343
430
  const element = elements[i];
344
431
  if (partial) {
345
- if ((element.innerText && element.innerText.trim().includes(text)) ||
346
- (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()))) {
347
434
  foundElements.push(element);
348
435
  }
349
436
  }
@@ -388,18 +475,29 @@ class StableBrowser {
388
475
  }
389
476
  async _collectLocatorInformation(selectorHierarchy, index = 0, scope, foundLocators, _params, info, visibleOnly = true) {
390
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
+ }
391
484
  //info.log += "searching for locator " + JSON.stringify(locatorSearch) + "\n";
392
485
  let locator = null;
393
486
  if (locatorSearch.climb && locatorSearch.climb >= 0) {
394
487
  let locatorString = await this._locateElmentByTextClimbCss(scope, locatorSearch.text, locatorSearch.climb, locatorSearch.css, _params);
395
488
  if (!locatorString) {
489
+ info.failCause.textNotFound = true;
490
+ info.failCause.lastError = "failed to locate element by text: " + locatorSearch.text;
396
491
  return;
397
492
  }
398
493
  locator = this._getLocator({ css: locatorString }, scope, _params);
399
494
  }
400
495
  else if (locatorSearch.text) {
401
- 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);
402
498
  if (result.elementCount === 0) {
499
+ info.failCause.textNotFound = true;
500
+ info.failCause.lastError = "failed to locate element by text: " + text;
403
501
  return;
404
502
  }
405
503
  locatorSearch.css = "[data-blinq-id='blinq-id-" + result.randomToken + "']";
@@ -416,6 +514,9 @@ class StableBrowser {
416
514
  // cssHref = true;
417
515
  // }
418
516
  let count = await locator.count();
517
+ if (count > 0 && !info.failCause.count) {
518
+ info.failCause.count = count;
519
+ }
419
520
  //info.log += "total elements found " + count + "\n";
420
521
  //let visibleCount = 0;
421
522
  let visibleLocator = null;
@@ -433,6 +534,8 @@ class StableBrowser {
433
534
  foundLocators.push(locator.nth(j));
434
535
  }
435
536
  else {
537
+ info.failCause.visible = visible;
538
+ info.failCause.enabled = enabled;
436
539
  if (!info.printMessages) {
437
540
  info.printMessages = {};
438
541
  }
@@ -444,6 +547,11 @@ class StableBrowser {
444
547
  }
445
548
  }
446
549
  async closeUnexpectedPopups(info, _params) {
550
+ if (!info) {
551
+ info = {};
552
+ info.failCause = {};
553
+ info.log = "";
554
+ }
447
555
  if (this.configuration.popupHandlers && this.configuration.popupHandlers.length > 0) {
448
556
  if (!info) {
449
557
  info = {};
@@ -484,7 +592,10 @@ class StableBrowser {
484
592
  }
485
593
  return { rerun: false };
486
594
  }
487
- async _locate(selectors, info, _params, timeout = 30000) {
595
+ async _locate(selectors, info, _params, timeout) {
596
+ if (!timeout) {
597
+ timeout = 30000;
598
+ }
488
599
  for (let i = 0; i < 3; i++) {
489
600
  info.log += "attempt " + i + ": total locators " + selectors.locators.length + "\n";
490
601
  for (let j = 0; j < selectors.locators.length; j++) {
@@ -498,32 +609,46 @@ class StableBrowser {
498
609
  }
499
610
  throw new Error("unable to locate element " + JSON.stringify(selectors));
500
611
  }
501
- async _locate_internal(selectors, info, _params, timeout = 30000) {
502
- let highPriorityTimeout = 5000;
503
- let visibleOnlyTimeout = 6000;
504
- let startTime = performance.now();
505
- let locatorsCount = 0;
506
- //let arrayMode = Array.isArray(selectors);
612
+ async _findFrameScope(selectors, timeout = 30000, info) {
613
+ if (!info) {
614
+ info = {};
615
+ info.failCause = {};
616
+ info.log = "";
617
+ }
507
618
  let scope = this.page;
619
+ if (selectors.frame) {
620
+ return selectors.frame;
621
+ }
508
622
  if (selectors.iframe_src || selectors.frameLocators) {
509
- const findFrame = (frame, framescope) => {
623
+ const findFrame = async (frame, framescope) => {
510
624
  for (let i = 0; i < frame.selectors.length; i++) {
511
625
  let frameLocator = frame.selectors[i];
512
626
  if (frameLocator.css) {
513
- framescope = framescope.frameLocator(frameLocator.css);
514
- 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
+ }
515
641
  }
516
642
  }
517
643
  if (frame.children) {
518
- return findFrame(frame.children, framescope);
644
+ return await findFrame(frame.children, framescope);
519
645
  }
520
646
  return framescope;
521
647
  };
522
- info.log += "searching for iframe " + selectors.iframe_src + "/" + selectors.frameLocators + "\n";
523
648
  while (true) {
524
649
  let frameFound = false;
525
650
  if (selectors.nestFrmLoc) {
526
- scope = findFrame(selectors.nestFrmLoc, scope);
651
+ scope = await findFrame(selectors.nestFrmLoc, scope);
527
652
  frameFound = true;
528
653
  break;
529
654
  }
@@ -543,6 +668,8 @@ class StableBrowser {
543
668
  if (!scope) {
544
669
  info.log += "unable to locate iframe " + selectors.iframe_src + "\n";
545
670
  if (performance.now() - startTime > timeout) {
671
+ info.failCause.iframeNotFound = true;
672
+ info.failCause.lastError = "unable to locate iframe " + selectors.iframe_src;
546
673
  throw new Error("unable to locate iframe " + selectors.iframe_src);
547
674
  }
548
675
  await new Promise((resolve) => setTimeout(resolve, 1000));
@@ -552,6 +679,30 @@ class StableBrowser {
552
679
  }
553
680
  }
554
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);
555
706
  let selectorsLocators = null;
556
707
  selectorsLocators = selectors.locators;
557
708
  // group selectors by priority
@@ -653,6 +804,8 @@ class StableBrowser {
653
804
  }
654
805
  this.logger.debug("unable to locate unique element, total elements found " + locatorsCount);
655
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";
656
809
  throw new Error("failed to locate first element no elements found, " + info.log);
657
810
  }
658
811
  async _scanLocatorsGroup(locatorsGroup, scope, _params, info, visibleOnly) {
@@ -684,89 +837,129 @@ class StableBrowser {
684
837
  });
685
838
  result.locatorIndex = i;
686
839
  }
840
+ if (foundLocators.length > 1) {
841
+ info.failCause.foundMultiple = true;
842
+ }
687
843
  }
688
844
  return result;
689
845
  }
690
- async click(selectors, _params, options = {}, world = null) {
691
- this._validateSelectors(selectors);
846
+ async simpleClick(elementDescription, _params, options = {}, world = null) {
692
847
  const startTime = Date.now();
693
- if (options && options.context) {
694
- selectors.locators[0].text = options.context;
848
+ let timeout = 30000;
849
+ if (options && options.timeout) {
850
+ timeout = options.timeout;
695
851
  }
696
- const info = {};
697
- info.log = "***** click on " + selectors.element_name + " *****\n";
698
- info.operation = "click";
699
- info.selectors = selectors;
700
- let error = null;
701
- let screenshotId = null;
702
- 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
+ };
703
919
  try {
704
- let element = await this._locate(selectors, info, _params);
705
- await this.scrollIfNeeded(element, info);
706
- ({ 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
+ }
707
924
  try {
708
- await this._highlightElements(element);
709
- await element.click();
925
+ await state.element.click();
710
926
  await new Promise((resolve) => setTimeout(resolve, 1000));
711
927
  }
712
928
  catch (e) {
713
929
  // await this.closeUnexpectedPopups();
714
- info.log += "click failed, will try again" + "\n";
715
- element = await this._locate(selectors, info, _params);
716
- await element.dispatchEvent("click");
930
+ state.element = await this._locate(selectors, state.info, _params);
931
+ await state.element.dispatchEvent("click");
717
932
  await new Promise((resolve) => setTimeout(resolve, 1000));
718
933
  }
719
934
  await this.waitForPageLoad();
720
- return info;
935
+ return state.info;
721
936
  }
722
937
  catch (e) {
723
- this.logger.error("click failed " + info.log);
724
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
725
- info.screenshotPath = screenshotPath;
726
- Object.assign(e, { info: info });
727
- error = e;
728
- throw e;
938
+ await _commandError(state, e, this);
729
939
  }
730
940
  finally {
731
- const endTime = Date.now();
732
- this._reportToWorld(world, {
733
- element_name: selectors.element_name,
734
- type: Types.CLICK,
735
- text: `Click element`,
736
- screenshotId,
737
- result: error
738
- ? {
739
- status: "FAILED",
740
- startTime,
741
- endTime,
742
- message: error === null || error === void 0 ? void 0 : error.message,
743
- }
744
- : {
745
- status: "PASSED",
746
- startTime,
747
- endTime,
748
- },
749
- info: info,
750
- });
941
+ _commandFinally(state, this);
751
942
  }
752
943
  }
753
944
  async setCheck(selectors, checked = true, _params, options = {}, world = null) {
754
- this._validateSelectors(selectors);
755
- const startTime = Date.now();
756
- const info = {};
757
- info.log = "";
758
- info.operation = "setCheck";
759
- info.checked = checked;
760
- info.selectors = selectors;
761
- let error = null;
762
- let screenshotId = null;
763
- 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
+ };
764
955
  try {
765
- let element = await this._locate(selectors, info, _params);
766
- ({ 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));
767
960
  try {
768
- await this._highlightElements(element);
769
- await element.setChecked(checked);
961
+ // await this._highlightElements(element);
962
+ await state.element.setChecked(checked);
770
963
  await new Promise((resolve) => setTimeout(resolve, 1000));
771
964
  }
772
965
  catch (e) {
@@ -775,179 +968,108 @@ class StableBrowser {
775
968
  }
776
969
  else {
777
970
  //await this.closeUnexpectedPopups();
778
- info.log += "setCheck failed, will try again" + "\n";
779
- element = await this._locate(selectors, info, _params);
780
- 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 });
781
974
  await new Promise((resolve) => setTimeout(resolve, 1000));
782
975
  }
783
976
  }
784
977
  await this.waitForPageLoad();
785
- return info;
978
+ return state.info;
786
979
  }
787
980
  catch (e) {
788
- this.logger.error("setCheck 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;
981
+ await _commandError(state, e, this);
794
982
  }
795
983
  finally {
796
- const endTime = Date.now();
797
- this._reportToWorld(world, {
798
- element_name: selectors.element_name,
799
- type: checked ? Types.CHECK : Types.UNCHECK,
800
- text: checked ? `Check element` : `Uncheck 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
- });
984
+ _commandFinally(state, this);
816
985
  }
817
986
  }
818
987
  async hover(selectors, _params, options = {}, world = null) {
819
- this._validateSelectors(selectors);
820
- const startTime = Date.now();
821
- const info = {};
822
- info.log = "";
823
- info.operation = "hover";
824
- info.selectors = selectors;
825
- let error = null;
826
- let screenshotId = null;
827
- 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
+ };
828
998
  try {
829
- let element = await this._locate(selectors, info, _params);
830
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
999
+ await _preCommand(state, this);
831
1000
  try {
832
- await this._highlightElements(element);
833
- await element.hover();
1001
+ await state.element.hover();
834
1002
  await new Promise((resolve) => setTimeout(resolve, 1000));
835
1003
  }
836
1004
  catch (e) {
837
1005
  //await this.closeUnexpectedPopups();
838
- info.log += "hover failed, will try again" + "\n";
839
- element = await this._locate(selectors, info, _params);
840
- 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 });
841
1009
  await new Promise((resolve) => setTimeout(resolve, 1000));
842
1010
  }
843
1011
  await this.waitForPageLoad();
844
- return info;
1012
+ return state.info;
845
1013
  }
846
1014
  catch (e) {
847
- this.logger.error("hover failed " + info.log);
848
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
849
- info.screenshotPath = screenshotPath;
850
- Object.assign(e, { info: info });
851
- error = e;
852
- throw e;
1015
+ await _commandError(state, e, this);
853
1016
  }
854
1017
  finally {
855
- const endTime = Date.now();
856
- this._reportToWorld(world, {
857
- element_name: selectors.element_name,
858
- type: Types.HOVER,
859
- text: `Hover element`,
860
- screenshotId,
861
- result: error
862
- ? {
863
- status: "FAILED",
864
- startTime,
865
- endTime,
866
- message: error === null || error === void 0 ? void 0 : error.message,
867
- }
868
- : {
869
- status: "PASSED",
870
- startTime,
871
- endTime,
872
- },
873
- info: info,
874
- });
1018
+ _commandFinally(state, this);
875
1019
  }
876
1020
  }
877
1021
  async selectOption(selectors, values, _params = null, options = {}, world = null) {
878
- this._validateSelectors(selectors);
879
1022
  if (!values) {
880
1023
  throw new Error("values is null");
881
1024
  }
882
- const startTime = Date.now();
883
- let error = null;
884
- let screenshotId = null;
885
- let screenshotPath = null;
886
- const info = {};
887
- info.log = "";
888
- info.operation = "selectOptions";
889
- 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
+ };
890
1036
  try {
891
- let element = await this._locate(selectors, info, _params);
892
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1037
+ await _preCommand(state, this);
893
1038
  try {
894
- await this._highlightElements(element);
895
- await element.selectOption(values);
1039
+ await state.element.selectOption(values);
896
1040
  }
897
1041
  catch (e) {
898
1042
  //await this.closeUnexpectedPopups();
899
- info.log += "selectOption failed, will try force" + "\n";
900
- 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 });
901
1045
  }
902
1046
  await this.waitForPageLoad();
903
- return info;
1047
+ return state.info;
904
1048
  }
905
1049
  catch (e) {
906
- this.logger.error("selectOption failed " + info.log);
907
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
908
- info.screenshotPath = screenshotPath;
909
- Object.assign(e, { info: info });
910
- this.logger.info("click failed, will try next selector");
911
- error = e;
912
- throw e;
1050
+ await _commandError(state, e, this);
913
1051
  }
914
1052
  finally {
915
- const endTime = Date.now();
916
- this._reportToWorld(world, {
917
- element_name: selectors.element_name,
918
- type: Types.SELECT,
919
- text: `Select option: ${values}`,
920
- value: values.toString(),
921
- screenshotId,
922
- result: error
923
- ? {
924
- status: "FAILED",
925
- startTime,
926
- endTime,
927
- message: error === null || error === void 0 ? void 0 : error.message,
928
- }
929
- : {
930
- status: "PASSED",
931
- startTime,
932
- endTime,
933
- },
934
- info: info,
935
- });
1053
+ _commandFinally(state, this);
936
1054
  }
937
1055
  }
938
1056
  async type(_value, _params = null, options = {}, world = null) {
939
- const startTime = Date.now();
940
- let error = null;
941
- let screenshotId = null;
942
- let screenshotPath = null;
943
- const info = {};
944
- info.log = "";
945
- info.operation = "type";
946
- _value = this._fixUsingParams(_value, _params);
947
- 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
+ };
948
1070
  try {
949
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
950
- const valueSegment = _value.split("&&");
1071
+ await _preCommand(state, this);
1072
+ const valueSegment = state.value.split("&&");
951
1073
  for (let i = 0; i < valueSegment.length; i++) {
952
1074
  if (i > 0) {
953
1075
  await new Promise((resolve) => setTimeout(resolve, 1000));
@@ -967,108 +1089,53 @@ class StableBrowser {
967
1089
  await this.page.keyboard.type(value);
968
1090
  }
969
1091
  }
970
- return info;
1092
+ return state.info;
971
1093
  }
972
1094
  catch (e) {
973
- //await this.closeUnexpectedPopups();
974
- this.logger.error("type failed " + info.log);
975
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
976
- info.screenshotPath = screenshotPath;
977
- Object.assign(e, { info: info });
978
- error = e;
979
- throw e;
1095
+ await _commandError(state, e, this);
980
1096
  }
981
1097
  finally {
982
- const endTime = Date.now();
983
- this._reportToWorld(world, {
984
- type: Types.TYPE_PRESS,
985
- screenshotId,
986
- value: _value,
987
- text: `type value: ${_value}`,
988
- result: error
989
- ? {
990
- status: "FAILED",
991
- startTime,
992
- endTime,
993
- message: error === null || error === void 0 ? void 0 : error.message,
994
- }
995
- : {
996
- status: "PASSED",
997
- startTime,
998
- endTime,
999
- },
1000
- info: info,
1001
- });
1098
+ _commandFinally(state, this);
1002
1099
  }
1003
1100
  }
1004
1101
  async setInputValue(selectors, value, _params = null, options = {}, world = null) {
1005
- // set input value for non fillable inputs like date, time, range, color, etc.
1006
- this._validateSelectors(selectors);
1007
- const startTime = Date.now();
1008
- const info = {};
1009
- info.log = "***** set input value " + selectors.element_name + " *****\n";
1010
- info.operation = "setInputValue";
1011
- info.selectors = selectors;
1012
- value = this._fixUsingParams(value, _params);
1013
- info.value = value;
1014
- let error = null;
1015
- let screenshotId = null;
1016
- 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
+ };
1017
1113
  try {
1018
- value = await this._replaceWithLocalData(value, this);
1019
- let element = await this._locate(selectors, info, _params);
1020
- await this.scrollIfNeeded(element, info);
1021
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1022
- await this._highlightElements(element);
1114
+ await _preCommand(state, this);
1115
+ let value = await this._replaceWithLocalData(state.value, this);
1023
1116
  try {
1024
- await element.evaluateHandle((el, value) => {
1117
+ await state.element.evaluateHandle((el, value) => {
1025
1118
  el.value = value;
1026
1119
  }, value);
1027
1120
  }
1028
1121
  catch (error) {
1029
1122
  this.logger.error("setInputValue failed, will try again");
1030
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1031
- info.screenshotPath = screenshotPath;
1032
- Object.assign(error, { info: info });
1033
- await element.evaluateHandle((el, value) => {
1123
+ await _screenshot(state, this);
1124
+ Object.assign(error, { info: state.info });
1125
+ await state.element.evaluateHandle((el, value) => {
1034
1126
  el.value = value;
1035
1127
  });
1036
1128
  }
1037
1129
  }
1038
1130
  catch (e) {
1039
- this.logger.error("setInputValue 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;
1131
+ await _commandError(state, e, this);
1045
1132
  }
1046
1133
  finally {
1047
- const endTime = Date.now();
1048
- this._reportToWorld(world, {
1049
- element_name: selectors.element_name,
1050
- type: Types.SET_INPUT,
1051
- text: `Set input value`,
1052
- value: value,
1053
- screenshotId,
1054
- result: error
1055
- ? {
1056
- status: "FAILED",
1057
- startTime,
1058
- endTime,
1059
- message: error === null || error === void 0 ? void 0 : error.message,
1060
- }
1061
- : {
1062
- status: "PASSED",
1063
- startTime,
1064
- endTime,
1065
- },
1066
- info: info,
1067
- });
1134
+ _commandFinally(state, this);
1068
1135
  }
1069
1136
  }
1070
1137
  async setDateTime(selectors, value, format = null, enter = false, _params = null, options = {}, world = null) {
1071
- this._validateSelectors(selectors);
1138
+ _validateSelectors(selectors);
1072
1139
  const startTime = Date.now();
1073
1140
  let error = null;
1074
1141
  let screenshotId = null;
@@ -1134,7 +1201,8 @@ class StableBrowser {
1134
1201
  }
1135
1202
  catch (e) {
1136
1203
  error = e;
1137
- throw e;
1204
+ // throw e;
1205
+ await _commandError({ text: "setDateTime", operation: "setDateTime", selectors, value, info }, e, this);
1138
1206
  }
1139
1207
  finally {
1140
1208
  const endTime = Date.now();
@@ -1161,32 +1229,32 @@ class StableBrowser {
1161
1229
  }
1162
1230
  }
1163
1231
  async clickType(selectors, _value, enter = false, _params = null, options = {}, world = null) {
1164
- this._validateSelectors(selectors);
1165
- const startTime = Date.now();
1166
- let error = null;
1167
- let screenshotId = null;
1168
- let screenshotPath = null;
1169
- const info = {};
1170
- info.log = "***** clickType on " + selectors.element_name + " with value " + _value + "*****\n";
1171
- info.operation = "clickType";
1172
- info.selectors = selectors;
1232
+ _value = unEscapeString(_value);
1173
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
+ };
1174
1246
  if (newValue !== _value) {
1175
1247
  //this.logger.info(_value + "=" + newValue);
1176
1248
  _value = newValue;
1177
1249
  }
1178
- info.value = _value;
1179
1250
  try {
1180
- let element = await this._locate(selectors, info, _params);
1181
- //insert red border around the element
1182
- await this.scrollIfNeeded(element, info);
1183
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1184
- await this._highlightElements(element);
1251
+ await _preCommand(state, this);
1252
+ state.info.value = _value;
1185
1253
  if (options === null || options === undefined || !options.press) {
1186
1254
  try {
1187
- let currentValue = await element.inputValue();
1255
+ let currentValue = await state.element.inputValue();
1188
1256
  if (currentValue) {
1189
- await element.fill("");
1257
+ await state.element.fill("");
1190
1258
  }
1191
1259
  }
1192
1260
  catch (e) {
@@ -1195,22 +1263,22 @@ class StableBrowser {
1195
1263
  }
1196
1264
  if (options === null || options === undefined || options.press) {
1197
1265
  try {
1198
- await element.click({ timeout: 5000 });
1266
+ await state.element.click({ timeout: 5000 });
1199
1267
  }
1200
1268
  catch (e) {
1201
- await element.dispatchEvent("click");
1269
+ await state.element.dispatchEvent("click");
1202
1270
  }
1203
1271
  }
1204
1272
  else {
1205
1273
  try {
1206
- await element.focus();
1274
+ await state.element.focus();
1207
1275
  }
1208
1276
  catch (e) {
1209
- await element.dispatchEvent("focus");
1277
+ await state.element.dispatchEvent("focus");
1210
1278
  }
1211
1279
  }
1212
1280
  await new Promise((resolve) => setTimeout(resolve, 500));
1213
- const valueSegment = _value.split("&&");
1281
+ const valueSegment = state.value.split("&&");
1214
1282
  for (let i = 0; i < valueSegment.length; i++) {
1215
1283
  if (i > 0) {
1216
1284
  await new Promise((resolve) => setTimeout(resolve, 1000));
@@ -1230,13 +1298,14 @@ class StableBrowser {
1230
1298
  await new Promise((resolve) => setTimeout(resolve, 500));
1231
1299
  }
1232
1300
  }
1301
+ await _screenshot(state, this);
1233
1302
  if (enter === true) {
1234
1303
  await new Promise((resolve) => setTimeout(resolve, 2000));
1235
1304
  await this.page.keyboard.press("Enter");
1236
1305
  await this.waitForPageLoad();
1237
1306
  }
1238
1307
  else if (enter === false) {
1239
- await element.dispatchEvent("change");
1308
+ await state.element.dispatchEvent("change");
1240
1309
  //await this.page.keyboard.press("Tab");
1241
1310
  }
1242
1311
  else {
@@ -1245,103 +1314,50 @@ class StableBrowser {
1245
1314
  await this.waitForPageLoad();
1246
1315
  }
1247
1316
  }
1248
- return info;
1317
+ return state.info;
1249
1318
  }
1250
1319
  catch (e) {
1251
- //await this.closeUnexpectedPopups();
1252
- this.logger.error("fill failed " + JSON.stringify(info));
1253
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1254
- info.screenshotPath = screenshotPath;
1255
- Object.assign(e, { info: info });
1256
- error = e;
1257
- throw e;
1320
+ await _commandError(state, e, this);
1258
1321
  }
1259
1322
  finally {
1260
- const endTime = Date.now();
1261
- this._reportToWorld(world, {
1262
- element_name: selectors.element_name,
1263
- type: Types.FILL,
1264
- screenshotId,
1265
- value: _value,
1266
- text: `clickType input with value: ${_value}`,
1267
- result: error
1268
- ? {
1269
- status: "FAILED",
1270
- startTime,
1271
- endTime,
1272
- message: error === null || error === void 0 ? void 0 : error.message,
1273
- }
1274
- : {
1275
- status: "PASSED",
1276
- startTime,
1277
- endTime,
1278
- },
1279
- info: info,
1280
- });
1323
+ _commandFinally(state, this);
1281
1324
  }
1282
1325
  }
1283
1326
  async fill(selectors, value, enter = false, _params = null, options = {}, world = null) {
1284
- this._validateSelectors(selectors);
1285
- const startTime = Date.now();
1286
- let error = null;
1287
- let screenshotId = null;
1288
- let screenshotPath = null;
1289
- const info = {};
1290
- info.log = "***** fill on " + selectors.element_name + " with value " + value + "*****\n";
1291
- info.operation = "fill";
1292
- info.selectors = selectors;
1293
- 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
+ };
1294
1338
  try {
1295
- let element = await this._locate(selectors, info, _params);
1296
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1297
- await this._highlightElements(element);
1298
- await element.fill(value);
1299
- await element.dispatchEvent("change");
1339
+ await _preCommand(state, this);
1340
+ await state.element.fill(value);
1341
+ await state.element.dispatchEvent("change");
1300
1342
  if (enter) {
1301
1343
  await new Promise((resolve) => setTimeout(resolve, 2000));
1302
1344
  await this.page.keyboard.press("Enter");
1303
1345
  }
1304
1346
  await this.waitForPageLoad();
1305
- return info;
1347
+ return state.info;
1306
1348
  }
1307
1349
  catch (e) {
1308
- //await this.closeUnexpectedPopups();
1309
- this.logger.error("fill failed " + info.log);
1310
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1311
- info.screenshotPath = screenshotPath;
1312
- Object.assign(e, { info: info });
1313
- error = e;
1314
- throw e;
1350
+ await _commandError(state, e, this);
1315
1351
  }
1316
1352
  finally {
1317
- const endTime = Date.now();
1318
- this._reportToWorld(world, {
1319
- element_name: selectors.element_name,
1320
- type: Types.FILL,
1321
- screenshotId,
1322
- value,
1323
- text: `Fill input with value: ${value}`,
1324
- result: error
1325
- ? {
1326
- status: "FAILED",
1327
- startTime,
1328
- endTime,
1329
- message: error === null || error === void 0 ? void 0 : error.message,
1330
- }
1331
- : {
1332
- status: "PASSED",
1333
- startTime,
1334
- endTime,
1335
- },
1336
- info: info,
1337
- });
1353
+ _commandFinally(state, this);
1338
1354
  }
1339
1355
  }
1340
1356
  async getText(selectors, _params = null, options = {}, info = {}, world = null) {
1341
1357
  return await this._getText(selectors, 0, _params, options, info, world);
1342
1358
  }
1343
1359
  async _getText(selectors, climb, _params = null, options = {}, info = {}, world = null) {
1344
- this._validateSelectors(selectors);
1360
+ _validateSelectors(selectors);
1345
1361
  let screenshotId = null;
1346
1362
  let screenshotPath = null;
1347
1363
  if (!info.log) {
@@ -1385,165 +1401,124 @@ class StableBrowser {
1385
1401
  }
1386
1402
  }
1387
1403
  async containsPattern(selectors, pattern, text, _params = null, options = {}, world = null) {
1388
- var _a;
1389
- this._validateSelectors(selectors);
1390
1404
  if (!pattern) {
1391
1405
  throw new Error("pattern is null");
1392
1406
  }
1393
1407
  if (!text) {
1394
1408
  throw new Error("text is null");
1395
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
+ };
1396
1426
  const newValue = await this._replaceWithLocalData(text, world);
1397
1427
  if (newValue !== text) {
1398
1428
  this.logger.info(text + "=" + newValue);
1399
1429
  text = newValue;
1400
1430
  }
1401
- const startTime = Date.now();
1402
- let error = null;
1403
- let screenshotId = null;
1404
- let screenshotPath = null;
1405
- const info = {};
1406
- info.log =
1407
- "***** verify element " + selectors.element_name + " contains pattern " + pattern + "/" + text + " *****\n";
1408
- info.operation = "containsPattern";
1409
- info.selectors = selectors;
1410
- info.value = text;
1411
- info.pattern = pattern;
1412
1431
  let foundObj = null;
1413
1432
  try {
1414
- 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);
1415
1436
  if (foundObj && foundObj.element) {
1416
- await this.scrollIfNeeded(foundObj.element, info);
1437
+ await this.scrollIfNeeded(foundObj.element, state.info);
1417
1438
  }
1418
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1439
+ await _screenshot(state, this);
1419
1440
  let escapedText = text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
1420
1441
  pattern = pattern.replace("{text}", escapedText);
1421
1442
  let regex = new RegExp(pattern, "im");
1422
- 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))) {
1423
- 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;
1424
1445
  throw new Error("element doesn't contain text " + text);
1425
1446
  }
1426
- return info;
1447
+ return state.info;
1427
1448
  }
1428
1449
  catch (e) {
1429
- //await this.closeUnexpectedPopups();
1430
- this.logger.error("verify element contains text failed " + info.log);
1431
- this.logger.error("found text " + (foundObj === null || foundObj === void 0 ? void 0 : foundObj.text) + " pattern " + pattern);
1432
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1433
- info.screenshotPath = screenshotPath;
1434
- Object.assign(e, { info: info });
1435
- error = e;
1436
- throw e;
1450
+ this.logger.error("found text " + foundObj?.text + " pattern " + pattern);
1451
+ await _commandError(state, e, this);
1437
1452
  }
1438
1453
  finally {
1439
- const endTime = Date.now();
1440
- this._reportToWorld(world, {
1441
- element_name: selectors.element_name,
1442
- type: Types.VERIFY_ELEMENT_CONTAINS_TEXT,
1443
- value: pattern,
1444
- text: `Verify element contains pattern: ${pattern}`,
1445
- screenshotId: foundObj === null || foundObj === void 0 ? void 0 : foundObj.screenshotId,
1446
- result: error
1447
- ? {
1448
- status: "FAILED",
1449
- startTime,
1450
- endTime,
1451
- message: error === null || error === void 0 ? void 0 : error.message,
1452
- }
1453
- : {
1454
- status: "PASSED",
1455
- startTime,
1456
- endTime,
1457
- },
1458
- info: info,
1459
- });
1454
+ _commandFinally(state, this);
1460
1455
  }
1461
1456
  }
1462
1457
  async containsText(selectors, text, climb, _params = null, options = {}, world = null) {
1463
- var _a, _b, _c;
1464
- 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
+ };
1465
1473
  if (!text) {
1466
1474
  throw new Error("text is null");
1467
1475
  }
1468
- const startTime = Date.now();
1469
- let error = null;
1470
- let screenshotId = null;
1471
- let screenshotPath = null;
1472
- const info = {};
1473
- info.log = "***** verify element " + selectors.element_name + " contains text " + text + " *****\n";
1474
- info.operation = "containsText";
1475
- info.selectors = selectors;
1476
+ text = unEscapeString(text);
1476
1477
  const newValue = await this._replaceWithLocalData(text, world);
1477
1478
  if (newValue !== text) {
1478
1479
  this.logger.info(text + "=" + newValue);
1479
1480
  text = newValue;
1480
1481
  }
1481
- info.value = text;
1482
1482
  let foundObj = null;
1483
1483
  try {
1484
- 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);
1485
1486
  if (foundObj && foundObj.element) {
1486
- await this.scrollIfNeeded(foundObj.element, info);
1487
+ await this.scrollIfNeeded(foundObj.element, state.info);
1487
1488
  }
1488
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1489
+ await _screenshot(state, this);
1489
1490
  const dateAlternatives = findDateAlternatives(text);
1490
1491
  const numberAlternatives = findNumberAlternatives(text);
1491
1492
  if (dateAlternatives.date) {
1492
1493
  for (let i = 0; i < dateAlternatives.dates.length; i++) {
1493
- if ((foundObj === null || foundObj === void 0 ? void 0 : foundObj.text.includes(dateAlternatives.dates[i])) ||
1494
- ((_a = foundObj === null || foundObj === void 0 ? void 0 : foundObj.value) === null || _a === void 0 ? void 0 : _a.includes(dateAlternatives.dates[i]))) {
1495
- return info;
1494
+ if (foundObj?.text.includes(dateAlternatives.dates[i]) ||
1495
+ foundObj?.value?.includes(dateAlternatives.dates[i])) {
1496
+ return state.info;
1496
1497
  }
1497
1498
  }
1498
1499
  throw new Error("element doesn't contain text " + text);
1499
1500
  }
1500
1501
  else if (numberAlternatives.number) {
1501
1502
  for (let i = 0; i < numberAlternatives.numbers.length; i++) {
1502
- if ((foundObj === null || foundObj === void 0 ? void 0 : foundObj.text.includes(numberAlternatives.numbers[i])) ||
1503
- ((_b = foundObj === null || foundObj === void 0 ? void 0 : foundObj.value) === null || _b === void 0 ? void 0 : _b.includes(numberAlternatives.numbers[i]))) {
1504
- return info;
1503
+ if (foundObj?.text.includes(numberAlternatives.numbers[i]) ||
1504
+ foundObj?.value?.includes(numberAlternatives.numbers[i])) {
1505
+ return state.info;
1505
1506
  }
1506
1507
  }
1507
1508
  throw new Error("element doesn't contain text " + text);
1508
1509
  }
1509
- 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))) {
1510
- info.foundText = foundObj === null || foundObj === void 0 ? void 0 : foundObj.text;
1511
- 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;
1512
1513
  throw new Error("element doesn't contain text " + text);
1513
1514
  }
1514
- return info;
1515
+ return state.info;
1515
1516
  }
1516
1517
  catch (e) {
1517
- //await this.closeUnexpectedPopups();
1518
- this.logger.error("verify element contains text failed " + info.log);
1519
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1520
- info.screenshotPath = screenshotPath;
1521
- Object.assign(e, { info: info });
1522
- error = e;
1523
- throw e;
1518
+ await _commandError(state, e, this);
1524
1519
  }
1525
1520
  finally {
1526
- const endTime = Date.now();
1527
- this._reportToWorld(world, {
1528
- element_name: selectors.element_name,
1529
- type: Types.VERIFY_ELEMENT_CONTAINS_TEXT,
1530
- text: `Verify element contains text: ${text}`,
1531
- value: text,
1532
- screenshotId: foundObj === null || foundObj === void 0 ? void 0 : foundObj.screenshotId,
1533
- result: error
1534
- ? {
1535
- status: "FAILED",
1536
- startTime,
1537
- endTime,
1538
- message: error === null || error === void 0 ? void 0 : error.message,
1539
- }
1540
- : {
1541
- status: "PASSED",
1542
- startTime,
1543
- endTime,
1544
- },
1545
- info: info,
1546
- });
1521
+ _commandFinally(state, this);
1547
1522
  }
1548
1523
  }
1549
1524
  _getDataFile(world = null) {
@@ -1772,7 +1747,6 @@ class StableBrowser {
1772
1747
  }
1773
1748
  async takeScreenshot(screenshotPath) {
1774
1749
  const playContext = this.context.playContext;
1775
- const client = await playContext.newCDPSession(this.page);
1776
1750
  // Using CDP to capture the screenshot
1777
1751
  const viewportWidth = Math.max(...(await this.page.evaluate(() => [
1778
1752
  document.body.scrollWidth,
@@ -1782,97 +1756,67 @@ class StableBrowser {
1782
1756
  document.body.clientWidth,
1783
1757
  document.documentElement.clientWidth,
1784
1758
  ])));
1785
- const viewportHeight = Math.max(...(await this.page.evaluate(() => [
1786
- document.body.scrollHeight,
1787
- document.documentElement.scrollHeight,
1788
- document.body.offsetHeight,
1789
- document.documentElement.offsetHeight,
1790
- document.body.clientHeight,
1791
- document.documentElement.clientHeight,
1792
- ])));
1793
- const { data } = await client.send("Page.captureScreenshot", {
1794
- format: "png",
1795
- // clip: {
1796
- // x: 0,
1797
- // y: 0,
1798
- // width: viewportWidth,
1799
- // height: viewportHeight,
1800
- // scale: 1,
1801
- // },
1802
- });
1803
- if (!screenshotPath) {
1804
- return data;
1805
- }
1806
- let screenshotBuffer = Buffer.from(data, "base64");
1807
- const sharpBuffer = sharp(screenshotBuffer);
1808
- const metadata = await sharpBuffer.metadata();
1809
- //check if you are on retina display and reduce the quality of the image
1810
- if (metadata.width > viewportWidth || metadata.height > viewportHeight) {
1811
- screenshotBuffer = await sharpBuffer
1812
- .resize(viewportWidth, viewportHeight, {
1813
- fit: sharp.fit.inside,
1814
- withoutEnlargement: true,
1815
- })
1816
- .toBuffer();
1817
- }
1818
- fs.writeFileSync(screenshotPath, screenshotBuffer);
1819
- 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
+ }
1820
1793
  }
1821
1794
  async verifyElementExistInPage(selectors, _params = null, options = {}, world = null) {
1822
- this._validateSelectors(selectors);
1823
- const startTime = Date.now();
1824
- let error = null;
1825
- let screenshotId = null;
1826
- 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
+ };
1827
1805
  await new Promise((resolve) => setTimeout(resolve, 2000));
1828
- const info = {};
1829
- info.log = "***** verify element " + selectors.element_name + " exists in page *****\n";
1830
- info.operation = "verify";
1831
- info.selectors = selectors;
1832
1806
  try {
1833
- const element = await this._locate(selectors, info, _params);
1834
- if (element) {
1835
- await this.scrollIfNeeded(element, info);
1836
- }
1837
- await this._highlightElements(element);
1838
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1839
- await expect(element).toHaveCount(1, { timeout: 10000 });
1840
- return info;
1807
+ await _preCommand(state, this);
1808
+ await expect(state.element).toHaveCount(1, { timeout: 10000 });
1809
+ return state.info;
1841
1810
  }
1842
1811
  catch (e) {
1843
- //await this.closeUnexpectedPopups();
1844
- this.logger.error("verify failed " + info.log);
1845
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1846
- info.screenshotPath = screenshotPath;
1847
- Object.assign(e, { info: info });
1848
- error = e;
1849
- throw e;
1812
+ await _commandError(state, e, this);
1850
1813
  }
1851
1814
  finally {
1852
- const endTime = Date.now();
1853
- this._reportToWorld(world, {
1854
- element_name: selectors.element_name,
1855
- type: Types.VERIFY_ELEMENT_CONTAINS_TEXT,
1856
- text: "Verify element exists in page",
1857
- screenshotId,
1858
- result: error
1859
- ? {
1860
- status: "FAILED",
1861
- startTime,
1862
- endTime,
1863
- message: error === null || error === void 0 ? void 0 : error.message,
1864
- }
1865
- : {
1866
- status: "PASSED",
1867
- startTime,
1868
- endTime,
1869
- },
1870
- info: info,
1871
- });
1815
+ _commandFinally(state, this);
1872
1816
  }
1873
1817
  }
1874
1818
  async extractAttribute(selectors, attribute, variable, _params = null, options = {}, world = null) {
1875
- this._validateSelectors(selectors);
1819
+ _validateSelectors(selectors);
1876
1820
  const startTime = Date.now();
1877
1821
  let error = null;
1878
1822
  let screenshotId = null;
@@ -1915,7 +1859,8 @@ class StableBrowser {
1915
1859
  info.screenshotPath = screenshotPath;
1916
1860
  Object.assign(e, { info: info });
1917
1861
  error = e;
1918
- throw e;
1862
+ // throw e;
1863
+ await _commandError({ text: "extractAttribute", operation: "extractAttribute", selectors, attribute, variable }, e, this);
1919
1864
  }
1920
1865
  finally {
1921
1866
  const endTime = Date.now();
@@ -1931,7 +1876,7 @@ class StableBrowser {
1931
1876
  status: "FAILED",
1932
1877
  startTime,
1933
1878
  endTime,
1934
- message: error === null || error === void 0 ? void 0 : error.message,
1879
+ message: error?.message,
1935
1880
  }
1936
1881
  : {
1937
1882
  status: "PASSED",
@@ -2016,7 +1961,8 @@ class StableBrowser {
2016
1961
  catch (e) {
2017
1962
  errorCount++;
2018
1963
  if (errorCount > 3) {
2019
- throw e;
1964
+ // throw e;
1965
+ await _commandError({ text: "extractEmailData", operation: "extractEmailData", emailAddress, info: {} }, e, this);
2020
1966
  }
2021
1967
  // ignore
2022
1968
  }
@@ -2127,7 +2073,8 @@ class StableBrowser {
2127
2073
  info.screenshotPath = screenshotPath;
2128
2074
  Object.assign(e, { info: info });
2129
2075
  error = e;
2130
- throw e;
2076
+ // throw e;
2077
+ await _commandError({ text: "verifyPagePath", operation: "verifyPagePath", pathPart, info }, e, this);
2131
2078
  }
2132
2079
  finally {
2133
2080
  const endTime = Date.now();
@@ -2140,7 +2087,7 @@ class StableBrowser {
2140
2087
  status: "FAILED",
2141
2088
  startTime,
2142
2089
  endTime,
2143
- message: error === null || error === void 0 ? void 0 : error.message,
2090
+ message: error?.message,
2144
2091
  }
2145
2092
  : {
2146
2093
  status: "PASSED",
@@ -2176,20 +2123,20 @@ class StableBrowser {
2176
2123
  for (let i = 0; i < frames.length; i++) {
2177
2124
  if (dateAlternatives.date) {
2178
2125
  for (let j = 0; j < dateAlternatives.dates.length; j++) {
2179
- const result = await this._locateElementByText(frames[i], dateAlternatives.dates[j], "*", true, {});
2126
+ const result = await this._locateElementByText(frames[i], dateAlternatives.dates[j], "*:not(script, style, head)", true, true, {});
2180
2127
  result.frame = frames[i];
2181
2128
  results.push(result);
2182
2129
  }
2183
2130
  }
2184
2131
  else if (numberAlternatives.number) {
2185
2132
  for (let j = 0; j < numberAlternatives.numbers.length; j++) {
2186
- const result = await this._locateElementByText(frames[i], numberAlternatives.numbers[j], "*", true, {});
2133
+ const result = await this._locateElementByText(frames[i], numberAlternatives.numbers[j], "*:not(script, style, head)", true, true, {});
2187
2134
  result.frame = frames[i];
2188
2135
  results.push(result);
2189
2136
  }
2190
2137
  }
2191
2138
  else {
2192
- const result = await this._locateElementByText(frames[i], text, "*", true, {});
2139
+ const result = await this._locateElementByText(frames[i], text, "*:not(script, style, head)", true, true, {});
2193
2140
  result.frame = frames[i];
2194
2141
  results.push(result);
2195
2142
  }
@@ -2225,7 +2172,8 @@ class StableBrowser {
2225
2172
  info.screenshotPath = screenshotPath;
2226
2173
  Object.assign(e, { info: info });
2227
2174
  error = e;
2228
- throw e;
2175
+ // throw e;
2176
+ await _commandError({ text: "verifyTextExistInPage", operation: "verifyTextExistInPage", text, info }, e, this);
2229
2177
  }
2230
2178
  finally {
2231
2179
  const endTime = Date.now();
@@ -2238,7 +2186,7 @@ class StableBrowser {
2238
2186
  status: "FAILED",
2239
2187
  startTime,
2240
2188
  endTime,
2241
- message: error === null || error === void 0 ? void 0 : error.message,
2189
+ message: error?.message,
2242
2190
  }
2243
2191
  : {
2244
2192
  status: "PASSED",
@@ -2309,7 +2257,8 @@ class StableBrowser {
2309
2257
  info.screenshotPath = screenshotPath;
2310
2258
  Object.assign(e, { info: info });
2311
2259
  error = e;
2312
- throw e;
2260
+ // throw e;
2261
+ await _commandError({ text: "visualVerification", operation: "visualVerification", text, info }, e, this);
2313
2262
  }
2314
2263
  finally {
2315
2264
  const endTime = Date.now();
@@ -2322,7 +2271,7 @@ class StableBrowser {
2322
2271
  status: "FAILED",
2323
2272
  startTime,
2324
2273
  endTime,
2325
- message: error === null || error === void 0 ? void 0 : error.message,
2274
+ message: error?.message,
2326
2275
  }
2327
2276
  : {
2328
2277
  status: "PASSED",
@@ -2354,7 +2303,7 @@ class StableBrowser {
2354
2303
  this.logger.info("Table data verified");
2355
2304
  }
2356
2305
  async getTableData(selectors, _params = null, options = {}, world = null) {
2357
- this._validateSelectors(selectors);
2306
+ _validateSelectors(selectors);
2358
2307
  const startTime = Date.now();
2359
2308
  let error = null;
2360
2309
  let screenshotId = null;
@@ -2376,7 +2325,8 @@ class StableBrowser {
2376
2325
  info.screenshotPath = screenshotPath;
2377
2326
  Object.assign(e, { info: info });
2378
2327
  error = e;
2379
- throw e;
2328
+ // throw e;
2329
+ await _commandError({ text: "getTableData", operation: "getTableData", selectors, info }, e, this);
2380
2330
  }
2381
2331
  finally {
2382
2332
  const endTime = Date.now();
@@ -2390,7 +2340,7 @@ class StableBrowser {
2390
2340
  status: "FAILED",
2391
2341
  startTime,
2392
2342
  endTime,
2393
- message: error === null || error === void 0 ? void 0 : error.message,
2343
+ message: error?.message,
2394
2344
  }
2395
2345
  : {
2396
2346
  status: "PASSED",
@@ -2402,7 +2352,7 @@ class StableBrowser {
2402
2352
  }
2403
2353
  }
2404
2354
  async analyzeTable(selectors, query, operator, value, _params = null, options = {}, world = null) {
2405
- this._validateSelectors(selectors);
2355
+ _validateSelectors(selectors);
2406
2356
  if (!query) {
2407
2357
  throw new Error("query is null");
2408
2358
  }
@@ -2541,7 +2491,8 @@ class StableBrowser {
2541
2491
  info.screenshotPath = screenshotPath;
2542
2492
  Object.assign(e, { info: info });
2543
2493
  error = e;
2544
- throw e;
2494
+ // throw e;
2495
+ await _commandError({ text: "analyzeTable", operation: "analyzeTable", selectors, query, operator, value }, e, this);
2545
2496
  }
2546
2497
  finally {
2547
2498
  const endTime = Date.now();
@@ -2555,7 +2506,7 @@ class StableBrowser {
2555
2506
  status: "FAILED",
2556
2507
  startTime,
2557
2508
  endTime,
2558
- message: error === null || error === void 0 ? void 0 : error.message,
2509
+ message: error?.message,
2559
2510
  }
2560
2511
  : {
2561
2512
  status: "PASSED",
@@ -2567,27 +2518,7 @@ class StableBrowser {
2567
2518
  }
2568
2519
  }
2569
2520
  async _replaceWithLocalData(value, world, _decrypt = true, totpWait = true) {
2570
- if (!value) {
2571
- return value;
2572
- }
2573
- // find all the accurance of {{(.*?)}} and replace with the value
2574
- let regex = /{{(.*?)}}/g;
2575
- let matches = value.match(regex);
2576
- if (matches) {
2577
- const testData = this.getTestData(world);
2578
- for (let i = 0; i < matches.length; i++) {
2579
- let match = matches[i];
2580
- let key = match.substring(2, match.length - 2);
2581
- let newValue = objectPath.get(testData, key, null);
2582
- if (newValue !== null) {
2583
- value = value.replace(match, newValue);
2584
- }
2585
- }
2586
- }
2587
- if ((value.startsWith("secret:") || value.startsWith("totp:")) && _decrypt) {
2588
- return await decrypt(value, null, totpWait);
2589
- }
2590
- return value;
2521
+ return await replaceWithLocalTestData(value, world, _decrypt, totpWait, this.context, this);
2591
2522
  }
2592
2523
  _getLoadTimeout(options) {
2593
2524
  let timeout = 15000;
@@ -2647,7 +2578,7 @@ class StableBrowser {
2647
2578
  status: "FAILED",
2648
2579
  startTime,
2649
2580
  endTime,
2650
- message: error === null || error === void 0 ? void 0 : error.message,
2581
+ message: error?.message,
2651
2582
  }
2652
2583
  : {
2653
2584
  status: "PASSED",
@@ -2668,6 +2599,7 @@ class StableBrowser {
2668
2599
  }
2669
2600
  catch (e) {
2670
2601
  console.log(".");
2602
+ await _commandError({ text: "closePage", operation: "closePage", info }, e, this);
2671
2603
  }
2672
2604
  finally {
2673
2605
  await new Promise((resolve) => setTimeout(resolve, 2000));
@@ -2682,7 +2614,7 @@ class StableBrowser {
2682
2614
  status: "FAILED",
2683
2615
  startTime,
2684
2616
  endTime,
2685
- message: error === null || error === void 0 ? void 0 : error.message,
2617
+ message: error?.message,
2686
2618
  }
2687
2619
  : {
2688
2620
  status: "PASSED",
@@ -2710,6 +2642,7 @@ class StableBrowser {
2710
2642
  }
2711
2643
  catch (e) {
2712
2644
  console.log(".");
2645
+ await _commandError({ text: "setViewportSize", operation: "setViewportSize", width, hight, info }, e, this);
2713
2646
  }
2714
2647
  finally {
2715
2648
  await new Promise((resolve) => setTimeout(resolve, 2000));
@@ -2724,7 +2657,7 @@ class StableBrowser {
2724
2657
  status: "FAILED",
2725
2658
  startTime,
2726
2659
  endTime,
2727
- message: error === null || error === void 0 ? void 0 : error.message,
2660
+ message: error?.message,
2728
2661
  }
2729
2662
  : {
2730
2663
  status: "PASSED",
@@ -2746,6 +2679,7 @@ class StableBrowser {
2746
2679
  }
2747
2680
  catch (e) {
2748
2681
  console.log(".");
2682
+ await _commandError({ text: "reloadPage", operation: "reloadPage", info }, e, this);
2749
2683
  }
2750
2684
  finally {
2751
2685
  await new Promise((resolve) => setTimeout(resolve, 2000));
@@ -2760,7 +2694,7 @@ class StableBrowser {
2760
2694
  status: "FAILED",
2761
2695
  startTime,
2762
2696
  endTime,
2763
- message: error === null || error === void 0 ? void 0 : error.message,
2697
+ message: error?.message,
2764
2698
  }
2765
2699
  : {
2766
2700
  status: "PASSED",
@@ -2945,5 +2879,10 @@ const KEYBOARD_EVENTS = [
2945
2879
  "TVAntennaCable",
2946
2880
  "TVAudioDescription",
2947
2881
  ];
2882
+ function unEscapeString(str) {
2883
+ const placeholder = "__NEWLINE__";
2884
+ str = str.replace(new RegExp(placeholder, "g"), "\n");
2885
+ return str;
2886
+ }
2948
2887
  export { StableBrowser };
2949
2888
  //# sourceMappingURL=stable_browser.js.map