automation_model 1.0.421-dev → 1.0.421-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,9 +2,9 @@
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";
@@ -14,6 +14,9 @@ import objectPath from "object-path";
14
14
  import { decrypt } from "./utils.js";
15
15
  import csv from "csv-parser";
16
16
  import { Readable } from "node:stream";
17
+ import readline from "readline";
18
+ import { getContext } from "./init_browser.js";
19
+ import { locate_element } from "./locate_element.js";
17
20
  const Types = {
18
21
  CLICK: "click_element",
19
22
  NAVIGATE: "navigate",
@@ -41,15 +44,19 @@ const Types = {
41
44
  LOAD_DATA: "load_data",
42
45
  SET_INPUT: "set_input",
43
46
  };
47
+ export const apps = {};
44
48
  class StableBrowser {
45
- constructor(browser, page, logger = null, context = null) {
49
+ constructor(browser, page, logger = null, context = null, world = null) {
46
50
  this.browser = browser;
47
51
  this.page = page;
48
52
  this.logger = logger;
49
53
  this.context = context;
54
+ this.world = world;
50
55
  this.project_path = null;
51
56
  this.webLogFile = null;
57
+ this.networkLogger = null;
52
58
  this.configuration = null;
59
+ this.appName = "main";
53
60
  if (!this.logger) {
54
61
  this.logger = console;
55
62
  }
@@ -75,23 +82,34 @@ class StableBrowser {
75
82
  this.logger.error("unable to read ai_config.json");
76
83
  }
77
84
  const logFolder = path.join(this.project_path, "logs", "web");
78
- this.webLogFile = this.getWebLogFile(logFolder);
79
- this.registerConsoleLogListener(page, context, this.webLogFile);
80
- this.registerRequestListener();
85
+ this.world = world;
81
86
  context.pages = [this.page];
82
87
  context.pageLoading = { status: false };
88
+ this.registerEventListeners(this.context);
89
+ }
90
+ registerEventListeners(context) {
91
+ this.registerConsoleLogListener(this.page, context);
92
+ this.registerRequestListener(this.page, context, this.webLogFile);
93
+ if (!context.pageLoading) {
94
+ context.pageLoading = { status: false };
95
+ }
83
96
  context.playContext.on("page", async function (page) {
84
97
  context.pageLoading.status = true;
85
98
  this.page = page;
86
99
  context.page = page;
87
100
  context.pages.push(page);
88
101
  page.on("close", async () => {
89
- if (this.context && this.context.pages && this.context.pages.length > 0) {
102
+ if (this.context && this.context.pages && this.context.pages.length > 1) {
90
103
  this.context.pages.pop();
91
104
  this.page = this.context.pages[this.context.pages.length - 1];
92
105
  this.context.page = this.page;
93
- let title = await this.page.title();
94
- console.log("Switched to page " + title);
106
+ try {
107
+ let title = await this.page.title();
108
+ console.log("Switched to page " + title);
109
+ }
110
+ catch (error) {
111
+ console.error("Error on page close", error);
112
+ }
95
113
  }
96
114
  });
97
115
  try {
@@ -104,6 +122,36 @@ class StableBrowser {
104
122
  context.pageLoading.status = false;
105
123
  }.bind(this));
106
124
  }
125
+ async switchApp(appName) {
126
+ // check if the current app (this.appName) is the same as the new app
127
+ if (this.appName === appName) {
128
+ return;
129
+ }
130
+ let navigate = false;
131
+ if (!apps[appName]) {
132
+ let newContext = await getContext(null, false, this.logger, appName, false, this);
133
+ navigate = true;
134
+ apps[appName] = {
135
+ context: newContext,
136
+ browser: newContext.browser,
137
+ page: newContext.page,
138
+ };
139
+ }
140
+ const tempContext = {};
141
+ this._copyContext(this, tempContext);
142
+ this._copyContext(apps[appName], this);
143
+ apps[this.appName] = tempContext;
144
+ this.appName = appName;
145
+ if (navigate) {
146
+ await this.goto(this.context.environment.baseUrl);
147
+ await this.waitForPageLoad();
148
+ }
149
+ }
150
+ _copyContext(from, to) {
151
+ to.browser = from.browser;
152
+ to.page = from.page;
153
+ to.context = from.context;
154
+ }
107
155
  getWebLogFile(logFolder) {
108
156
  if (!fs.existsSync(logFolder)) {
109
157
  fs.mkdirSync(logFolder, { recursive: true });
@@ -115,37 +163,65 @@ class StableBrowser {
115
163
  const fileName = nextIndex + ".json";
116
164
  return path.join(logFolder, fileName);
117
165
  }
118
- registerConsoleLogListener(page, context, logFile) {
166
+ registerConsoleLogListener(page, context) {
119
167
  if (!this.context.webLogger) {
120
168
  this.context.webLogger = [];
121
169
  }
122
170
  page.on("console", async (msg) => {
123
- this.context.webLogger.push({
171
+ var _a;
172
+ const obj = {
124
173
  type: msg.type(),
125
174
  text: msg.text(),
126
175
  location: msg.location(),
127
176
  time: new Date().toISOString(),
128
- });
129
- await fs.promises.writeFile(logFile, JSON.stringify(this.context.webLogger, null, 2));
177
+ };
178
+ this.context.webLogger.push(obj);
179
+ if (msg.type() === "error") {
180
+ (_a = this.world) === null || _a === void 0 ? void 0 : _a.attach(JSON.stringify(obj), { mediaType: "application/json+log" });
181
+ }
130
182
  });
131
183
  }
132
- registerRequestListener() {
133
- this.page.on("request", async (data) => {
184
+ registerRequestListener(page, context, logFile) {
185
+ if (!this.context.networkLogger) {
186
+ this.context.networkLogger = [];
187
+ }
188
+ page.on("request", async (data) => {
189
+ var _a;
190
+ const startTime = new Date().getTime();
134
191
  try {
135
- const pageUrl = new URL(this.page.url());
192
+ const pageUrl = new URL(page.url());
136
193
  const requestUrl = new URL(data.url());
137
194
  if (pageUrl.hostname === requestUrl.hostname) {
138
195
  const method = data.method();
139
- if (method === "POST" || method === "GET" || method === "PUT" || method === "DELETE" || method === "PATCH") {
196
+ if (["POST", "GET", "PUT", "DELETE", "PATCH"].includes(method)) {
140
197
  const token = await data.headerValue("Authorization");
141
198
  if (token) {
142
- this.context.authtoken = token;
199
+ context.authtoken = token;
143
200
  }
144
201
  }
145
202
  }
203
+ const response = await data.response();
204
+ const endTime = new Date().getTime();
205
+ const obj = {
206
+ url: data.url(),
207
+ method: data.method(),
208
+ postData: data.postData(),
209
+ error: data.failure() ? data.failure().errorText : null,
210
+ duration: endTime - startTime,
211
+ startTime,
212
+ };
213
+ context.networkLogger.push(obj);
214
+ (_a = this.world) === null || _a === void 0 ? void 0 : _a.attach(JSON.stringify(obj), { mediaType: "application/json+network" });
146
215
  }
147
216
  catch (error) {
148
217
  console.error("Error in request listener", error);
218
+ context.networkLogger.push({
219
+ error: "not able to listen",
220
+ message: error.message,
221
+ stack: error.stack,
222
+ time: new Date().toISOString(),
223
+ });
224
+ // await fs.promises.writeFile(logFile, JSON.stringify(context.networkLogger, null, 2));
149
225
  }
150
226
  });
151
227
  }
@@ -262,7 +338,10 @@ class StableBrowser {
262
338
  return locatorReturn;
263
339
  }
264
340
  async _locateElmentByTextClimbCss(scope, text, climb, css, _params) {
265
- let result = await this._locateElementByText(scope, this._fixUsingParams(text, _params), "*", false, true, _params);
341
+ if (css && css.locator) {
342
+ css = css.locator;
343
+ }
344
+ let result = await this._locateElementByText(scope, this._fixUsingParams(text, _params), "*", false, false, _params);
266
345
  if (result.elementCount === 0) {
267
346
  return;
268
347
  }
@@ -289,6 +368,15 @@ class StableBrowser {
289
368
  return false;
290
369
  }
291
370
  document.isParent = isParent;
371
+ function getRegex(str) {
372
+ const match = str.match(/^\/(.*?)\/([gimuy]*)$/);
373
+ if (!match) {
374
+ return null;
375
+ }
376
+ let [_, pattern, flags] = match;
377
+ return new RegExp(pattern, flags);
378
+ }
379
+ document.getRegex = getRegex;
292
380
  function collectAllShadowDomElements(element, result = []) {
293
381
  // Check and add the element if it has a shadow root
294
382
  if (element.shadowRoot) {
@@ -307,6 +395,10 @@ class StableBrowser {
307
395
  if (!tag) {
308
396
  tag = "*";
309
397
  }
398
+ let regexpSearch = document.getRegex(text);
399
+ if (regexpSearch) {
400
+ regex = true;
401
+ }
310
402
  let elements = Array.from(document.querySelectorAll(tag));
311
403
  let shadowHosts = [];
312
404
  document.collectAllShadowDomElements(document, shadowHosts);
@@ -322,7 +414,9 @@ class StableBrowser {
322
414
  let randomToken = null;
323
415
  const foundElements = [];
324
416
  if (regex) {
325
- let regexpSearch = new RegExp(text, "im");
417
+ if (!regexpSearch) {
418
+ regexpSearch = new RegExp(text, "im");
419
+ }
326
420
  for (let i = 0; i < elements.length; i++) {
327
421
  const element = elements[i];
328
422
  if ((element.innerText && regexpSearch.test(element.innerText)) ||
@@ -336,8 +430,8 @@ class StableBrowser {
336
430
  for (let i = 0; i < elements.length; i++) {
337
431
  const element = elements[i];
338
432
  if (partial) {
339
- if ((element.innerText && element.innerText.trim().includes(text)) ||
340
- (element.value && element.value.includes(text))) {
433
+ if ((element.innerText && element.innerText.toLowerCase().trim().includes(text.toLowerCase())) ||
434
+ (element.value && element.value.toLowerCase().includes(text.toLowerCase()))) {
341
435
  foundElements.push(element);
342
436
  }
343
437
  }
@@ -382,6 +476,12 @@ class StableBrowser {
382
476
  }
383
477
  async _collectLocatorInformation(selectorHierarchy, index = 0, scope, foundLocators, _params, info, visibleOnly = true) {
384
478
  let locatorSearch = selectorHierarchy[index];
479
+ try {
480
+ locatorSearch = JSON.parse(this._fixUsingParams(JSON.stringify(locatorSearch), _params));
481
+ }
482
+ catch (e) {
483
+ console.error(e);
484
+ }
385
485
  //info.log += "searching for locator " + JSON.stringify(locatorSearch) + "\n";
386
486
  let locator = null;
387
487
  if (locatorSearch.climb && locatorSearch.climb >= 0) {
@@ -470,6 +570,8 @@ class StableBrowser {
470
570
  if (result.foundElements.length > 0) {
471
571
  let dialogCloseLocator = result.foundElements[0].locator;
472
572
  await dialogCloseLocator.click();
573
+ // wait for the dialog to close
574
+ await dialogCloseLocator.waitFor({ state: "hidden" });
473
575
  return { rerun: true };
474
576
  }
475
577
  }
@@ -478,7 +580,7 @@ class StableBrowser {
478
580
  }
479
581
  async _locate(selectors, info, _params, timeout = 30000) {
480
582
  for (let i = 0; i < 3; i++) {
481
- info.log += "attempt " + i + ": totoal locators " + selectors.locators.length + "\n";
583
+ info.log += "attempt " + i + ": total locators " + selectors.locators.length + "\n";
482
584
  for (let j = 0; j < selectors.locators.length; j++) {
483
585
  let selector = selectors.locators[j];
484
586
  info.log += "searching for locator " + j + ":" + JSON.stringify(selector) + "\n";
@@ -497,10 +599,44 @@ class StableBrowser {
497
599
  let locatorsCount = 0;
498
600
  //let arrayMode = Array.isArray(selectors);
499
601
  let scope = this.page;
602
+ // for the simple click usecase
603
+ if (selectors.frame) {
604
+ scope = selectors.frame;
605
+ }
500
606
  if (selectors.iframe_src || selectors.frameLocators) {
607
+ const findFrame = async (frame, framescope) => {
608
+ for (let i = 0; i < frame.selectors.length; i++) {
609
+ let frameLocator = frame.selectors[i];
610
+ if (frameLocator.css) {
611
+ let testframescope = framescope.frameLocator(frameLocator.css);
612
+ if (frameLocator.index) {
613
+ testframescope = framescope.nth(frameLocator.index);
614
+ }
615
+ try {
616
+ await testframescope.owner().evaluateHandle(() => true, null, {
617
+ timeout: 5000,
618
+ });
619
+ framescope = testframescope;
620
+ break;
621
+ }
622
+ catch (error) {
623
+ console.error("frame not found " + frameLocator.css);
624
+ }
625
+ }
626
+ }
627
+ if (frame.children) {
628
+ return await findFrame(frame.children, framescope);
629
+ }
630
+ return framescope;
631
+ };
501
632
  info.log += "searching for iframe " + selectors.iframe_src + "/" + selectors.frameLocators + "\n";
502
633
  while (true) {
503
634
  let frameFound = false;
635
+ if (selectors.nestFrmLoc) {
636
+ scope = await findFrame(selectors.nestFrmLoc, scope);
637
+ frameFound = true;
638
+ break;
639
+ }
504
640
  if (selectors.frameLocators) {
505
641
  for (let i = 0; i < selectors.frameLocators.length; i++) {
506
642
  let frameLocator = selectors.frameLocators[i];
@@ -661,6 +797,66 @@ class StableBrowser {
661
797
  }
662
798
  return result;
663
799
  }
800
+ async simpleClick(elementDescription, _params, options = {}, world = null) {
801
+ const startTime = Date.now();
802
+ let timeout = 30000;
803
+ if (options && options.timeout) {
804
+ timeout = options.timeout;
805
+ }
806
+ while (true) {
807
+ try {
808
+ const result = await locate_element(this.context, elementDescription, "click");
809
+ if ((result === null || result === void 0 ? void 0 : result.elementNumber) >= 0) {
810
+ const selectors = {
811
+ frame: result === null || result === void 0 ? void 0 : result.frame,
812
+ locators: [
813
+ {
814
+ css: result === null || result === void 0 ? void 0 : result.css,
815
+ },
816
+ ],
817
+ };
818
+ await this.click(selectors, _params, options, world);
819
+ return;
820
+ }
821
+ }
822
+ catch (e) {
823
+ if (performance.now() - startTime > timeout) {
824
+ throw e;
825
+ }
826
+ }
827
+ await new Promise((resolve) => setTimeout(resolve, 3000));
828
+ }
829
+ }
830
+ async simpleClickType(elementDescription, value, _params, options = {}, world = null) {
831
+ const startTime = Date.now();
832
+ let timeout = 30000;
833
+ if (options && options.timeout) {
834
+ timeout = options.timeout;
835
+ }
836
+ while (true) {
837
+ try {
838
+ const result = await locate_element(this.context, elementDescription, "fill", value);
839
+ if ((result === null || result === void 0 ? void 0 : result.elementNumber) >= 0) {
840
+ const selectors = {
841
+ frame: result === null || result === void 0 ? void 0 : result.frame,
842
+ locators: [
843
+ {
844
+ css: result === null || result === void 0 ? void 0 : result.css,
845
+ },
846
+ ],
847
+ };
848
+ await this.clickType(selectors, value, false, _params, options, world);
849
+ return;
850
+ }
851
+ }
852
+ catch (e) {
853
+ if (performance.now() - startTime > timeout) {
854
+ throw e;
855
+ }
856
+ }
857
+ await new Promise((resolve) => setTimeout(resolve, 3000));
858
+ }
859
+ }
664
860
  async click(selectors, _params, options = {}, world = null) {
665
861
  this._validateSelectors(selectors);
666
862
  const startTime = Date.now();
@@ -680,14 +876,14 @@ class StableBrowser {
680
876
  ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
681
877
  try {
682
878
  await this._highlightElements(element);
683
- await element.click({ timeout: 5000 });
879
+ await element.click();
684
880
  await new Promise((resolve) => setTimeout(resolve, 1000));
685
881
  }
686
882
  catch (e) {
687
883
  // await this.closeUnexpectedPopups();
688
884
  info.log += "click failed, will try again" + "\n";
689
885
  element = await this._locate(selectors, info, _params);
690
- await element.click({ timeout: 10000, force: true });
886
+ await element.dispatchEvent("click");
691
887
  await new Promise((resolve) => setTimeout(resolve, 1000));
692
888
  }
693
889
  await this.waitForPageLoad();
@@ -740,7 +936,7 @@ class StableBrowser {
740
936
  ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
741
937
  try {
742
938
  await this._highlightElements(element);
743
- await element.setChecked(checked, { timeout: 5000 });
939
+ await element.setChecked(checked);
744
940
  await new Promise((resolve) => setTimeout(resolve, 1000));
745
941
  }
746
942
  catch (e) {
@@ -804,7 +1000,7 @@ class StableBrowser {
804
1000
  ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
805
1001
  try {
806
1002
  await this._highlightElements(element);
807
- await element.hover({ timeout: 10000 });
1003
+ await element.hover();
808
1004
  await new Promise((resolve) => setTimeout(resolve, 1000));
809
1005
  }
810
1006
  catch (e) {
@@ -866,7 +1062,7 @@ class StableBrowser {
866
1062
  ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
867
1063
  try {
868
1064
  await this._highlightElements(element);
869
- await element.selectOption(values, { timeout: 5000 });
1065
+ await element.selectOption(values);
870
1066
  }
871
1067
  catch (e) {
872
1068
  //await this.closeUnexpectedPopups();
@@ -1154,7 +1350,6 @@ class StableBrowser {
1154
1350
  let element = await this._locate(selectors, info, _params);
1155
1351
  //insert red border around the element
1156
1352
  await this.scrollIfNeeded(element, info);
1157
- ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1158
1353
  await this._highlightElements(element);
1159
1354
  if (options === null || options === undefined || !options.press) {
1160
1355
  try {
@@ -1204,6 +1399,7 @@ class StableBrowser {
1204
1399
  await new Promise((resolve) => setTimeout(resolve, 500));
1205
1400
  }
1206
1401
  }
1402
+ ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1207
1403
  if (enter === true) {
1208
1404
  await new Promise((resolve) => setTimeout(resolve, 2000));
1209
1405
  await this.page.keyboard.press("Enter");
@@ -1269,7 +1465,7 @@ class StableBrowser {
1269
1465
  let element = await this._locate(selectors, info, _params);
1270
1466
  ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1271
1467
  await this._highlightElements(element);
1272
- await element.fill(value, { timeout: 10000 });
1468
+ await element.fill(value);
1273
1469
  await element.dispatchEvent("change");
1274
1470
  if (enter) {
1275
1471
  await new Promise((resolve) => setTimeout(resolve, 2000));
@@ -1488,7 +1684,7 @@ class StableBrowser {
1488
1684
  return info;
1489
1685
  }
1490
1686
  catch (e) {
1491
- //await this.closeUnexpectedPopups();
1687
+ await this.closeUnexpectedPopups();
1492
1688
  this.logger.error("verify element contains text failed " + info.log);
1493
1689
  ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
1494
1690
  info.screenshotPath = screenshotPath;
@@ -1536,6 +1732,29 @@ class StableBrowser {
1536
1732
  }
1537
1733
  return dataFile;
1538
1734
  }
1735
+ async waitForUserInput(message, world = null) {
1736
+ if (!message) {
1737
+ message = "# Wait for user input. Press any key to continue";
1738
+ }
1739
+ else {
1740
+ message = "# Wait for user input. " + message;
1741
+ }
1742
+ message += "\n";
1743
+ const value = await new Promise((resolve) => {
1744
+ const rl = readline.createInterface({
1745
+ input: process.stdin,
1746
+ output: process.stdout,
1747
+ });
1748
+ rl.question(message, (answer) => {
1749
+ rl.close();
1750
+ resolve(answer);
1751
+ });
1752
+ });
1753
+ if (value) {
1754
+ this.logger.info(`{{userInput}} was set to: ${value}`);
1755
+ }
1756
+ this.setTestData({ userInput: value }, world);
1757
+ }
1539
1758
  setTestData(testData, world = null) {
1540
1759
  if (!testData) {
1541
1760
  return;
@@ -1723,7 +1942,6 @@ class StableBrowser {
1723
1942
  }
1724
1943
  async takeScreenshot(screenshotPath) {
1725
1944
  const playContext = this.context.playContext;
1726
- const client = await playContext.newCDPSession(this.page);
1727
1945
  // Using CDP to capture the screenshot
1728
1946
  const viewportWidth = Math.max(...(await this.page.evaluate(() => [
1729
1947
  document.body.scrollWidth,
@@ -1733,41 +1951,40 @@ class StableBrowser {
1733
1951
  document.body.clientWidth,
1734
1952
  document.documentElement.clientWidth,
1735
1953
  ])));
1736
- const viewportHeight = Math.max(...(await this.page.evaluate(() => [
1737
- document.body.scrollHeight,
1738
- document.documentElement.scrollHeight,
1739
- document.body.offsetHeight,
1740
- document.documentElement.offsetHeight,
1741
- document.body.clientHeight,
1742
- document.documentElement.clientHeight,
1743
- ])));
1744
- const { data } = await client.send("Page.captureScreenshot", {
1745
- format: "png",
1746
- // clip: {
1747
- // x: 0,
1748
- // y: 0,
1749
- // width: viewportWidth,
1750
- // height: viewportHeight,
1751
- // scale: 1,
1752
- // },
1753
- });
1754
- if (!screenshotPath) {
1755
- return data;
1756
- }
1757
- let screenshotBuffer = Buffer.from(data, "base64");
1758
- const sharpBuffer = sharp(screenshotBuffer);
1759
- const metadata = await sharpBuffer.metadata();
1760
- //check if you are on retina display and reduce the quality of the image
1761
- if (metadata.width > viewportWidth || metadata.height > viewportHeight) {
1762
- screenshotBuffer = await sharpBuffer
1763
- .resize(viewportWidth, viewportHeight, {
1764
- fit: sharp.fit.inside,
1765
- withoutEnlargement: true,
1766
- })
1767
- .toBuffer();
1768
- }
1769
- fs.writeFileSync(screenshotPath, screenshotBuffer);
1770
- await client.detach();
1954
+ let screenshotBuffer = null;
1955
+ if (this.context.browserName === "chromium") {
1956
+ const client = await playContext.newCDPSession(this.page);
1957
+ const { data } = await client.send("Page.captureScreenshot", {
1958
+ format: "png",
1959
+ // clip: {
1960
+ // x: 0,
1961
+ // y: 0,
1962
+ // width: viewportWidth,
1963
+ // height: viewportHeight,
1964
+ // scale: 1,
1965
+ // },
1966
+ });
1967
+ await client.detach();
1968
+ if (!screenshotPath) {
1969
+ return data;
1970
+ }
1971
+ screenshotBuffer = Buffer.from(data, "base64");
1972
+ }
1973
+ else {
1974
+ screenshotBuffer = await this.page.screenshot();
1975
+ }
1976
+ let image = await Jimp.read(screenshotBuffer);
1977
+ // Get the image dimensions
1978
+ const { width, height } = image.bitmap;
1979
+ const resizeRatio = viewportWidth / width;
1980
+ // Resize the image to fit within the viewport dimensions without enlarging
1981
+ if (width > viewportWidth) {
1982
+ image = image.resize({ w: viewportWidth, h: height * resizeRatio }); // Resize the image while maintaining aspect ratio
1983
+ await image.write(screenshotPath);
1984
+ }
1985
+ else {
1986
+ fs.writeFileSync(screenshotPath, screenshotBuffer);
1987
+ }
1771
1988
  }
1772
1989
  async verifyElementExistInPage(selectors, _params = null, options = {}, world = null) {
1773
1990
  this._validateSelectors(selectors);
@@ -2127,20 +2344,20 @@ class StableBrowser {
2127
2344
  for (let i = 0; i < frames.length; i++) {
2128
2345
  if (dateAlternatives.date) {
2129
2346
  for (let j = 0; j < dateAlternatives.dates.length; j++) {
2130
- const result = await this._locateElementByText(frames[i], dateAlternatives.dates[j], "*", true, {});
2347
+ const result = await this._locateElementByText(frames[i], dateAlternatives.dates[j], "*", true, true, {});
2131
2348
  result.frame = frames[i];
2132
2349
  results.push(result);
2133
2350
  }
2134
2351
  }
2135
2352
  else if (numberAlternatives.number) {
2136
2353
  for (let j = 0; j < numberAlternatives.numbers.length; j++) {
2137
- const result = await this._locateElementByText(frames[i], numberAlternatives.numbers[j], "*", true, {});
2354
+ const result = await this._locateElementByText(frames[i], numberAlternatives.numbers[j], "*", true, true, {});
2138
2355
  result.frame = frames[i];
2139
2356
  results.push(result);
2140
2357
  }
2141
2358
  }
2142
2359
  else {
2143
- const result = await this._locateElementByText(frames[i], text, "*", true, {});
2360
+ const result = await this._locateElementByText(frames[i], text, "*", true, true, {});
2144
2361
  result.frame = frames[i];
2145
2362
  results.push(result);
2146
2363
  }
@@ -2575,13 +2792,13 @@ class StableBrowser {
2575
2792
  }
2576
2793
  catch (e) {
2577
2794
  if (e.label === "networkidle") {
2578
- console.log("waitted for the network to be idle timeout");
2795
+ console.log("waited for the network to be idle timeout");
2579
2796
  }
2580
2797
  else if (e.label === "load") {
2581
- console.log("waitted for the load timeout");
2798
+ console.log("waited for the load timeout");
2582
2799
  }
2583
2800
  else if (e.label === "domcontentloaded") {
2584
- console.log("waitted for the domcontent loaded timeout");
2801
+ console.log("waited for the domcontent loaded timeout");
2585
2802
  }
2586
2803
  console.log(".");
2587
2804
  }
@@ -2724,33 +2941,18 @@ class StableBrowser {
2724
2941
  }
2725
2942
  async scrollIfNeeded(element, info) {
2726
2943
  try {
2727
- let didScroll = await element.evaluate((node) => {
2728
- const rect = node.getBoundingClientRect();
2729
- if (rect &&
2730
- rect.top >= 0 &&
2731
- rect.left >= 0 &&
2732
- rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
2733
- rect.right <= (window.innerWidth || document.documentElement.clientWidth)) {
2734
- return false;
2735
- }
2736
- else {
2737
- node.scrollIntoView({
2738
- behavior: "smooth",
2739
- block: "center",
2740
- inline: "center",
2741
- });
2742
- return true;
2743
- }
2944
+ await element.scrollIntoViewIfNeeded({
2945
+ timeout: 2000,
2744
2946
  });
2745
- if (didScroll) {
2746
- await new Promise((resolve) => setTimeout(resolve, 500));
2747
- if (info) {
2748
- info.box = await element.boundingBox();
2749
- }
2947
+ await new Promise((resolve) => setTimeout(resolve, 500));
2948
+ if (info) {
2949
+ info.box = await element.boundingBox({
2950
+ timeout: 1000,
2951
+ });
2750
2952
  }
2751
2953
  }
2752
2954
  catch (e) {
2753
- console.log("scroll failed");
2955
+ console.log("#-#");
2754
2956
  }
2755
2957
  }
2756
2958
  _reportToWorld(world, properties) {