automation_model 1.0.463-dev → 1.0.463-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.
- package/lib/api.d.ts +42 -1
- package/lib/api.js +181 -7
- package/lib/api.js.map +1 -1
- package/lib/auto_page.js +38 -16
- package/lib/auto_page.js.map +1 -1
- package/lib/axe/axe.mini.js +12 -0
- package/lib/browser_manager.d.ts +5 -3
- package/lib/browser_manager.js +44 -19
- package/lib/browser_manager.js.map +1 -1
- package/lib/command_common.d.ts +6 -0
- package/lib/command_common.js +138 -0
- package/lib/command_common.js.map +1 -0
- package/lib/environment.js +5 -3
- package/lib/environment.js.map +1 -1
- package/lib/error-messages.d.ts +6 -0
- package/lib/error-messages.js +182 -0
- package/lib/error-messages.js.map +1 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/index.js.map +1 -1
- package/lib/init_browser.d.ts +1 -1
- package/lib/init_browser.js +18 -3
- package/lib/init_browser.js.map +1 -1
- package/lib/locate_element.d.ts +7 -0
- package/lib/locate_element.js +213 -0
- package/lib/locate_element.js.map +1 -0
- package/lib/locator.d.ts +36 -0
- package/lib/locator.js +165 -0
- package/lib/locator.js.map +1 -1
- package/lib/network.d.ts +3 -0
- package/lib/network.js +144 -0
- package/lib/network.js.map +1 -0
- package/lib/stable_browser.d.ts +26 -19
- package/lib/stable_browser.js +632 -773
- package/lib/stable_browser.js.map +1 -1
- package/lib/table.d.ts +13 -0
- package/lib/table.js +187 -0
- package/lib/table.js.map +1 -0
- package/lib/test_context.d.ts +1 -0
- package/lib/test_context.js +12 -12
- package/lib/test_context.js.map +1 -1
- package/lib/utils.d.ts +3 -1
- package/lib/utils.js +68 -1
- package/lib/utils.js.map +1 -1
- package/package.json +4 -5
package/lib/stable_browser.js
CHANGED
|
@@ -10,12 +10,14 @@ import { getDateTimeValue } from "./date_time.js";
|
|
|
10
10
|
import drawRectangle from "./drawRect.js";
|
|
11
11
|
//import { closeUnexpectedPopups } from "./popups.js";
|
|
12
12
|
import { getTableCells, getTableData } from "./table_analyze.js";
|
|
13
|
-
import
|
|
14
|
-
import { decrypt } from "./utils.js";
|
|
13
|
+
import { maskValue, replaceWithLocalTestData } from "./utils.js";
|
|
15
14
|
import csv from "csv-parser";
|
|
16
15
|
import { Readable } from "node:stream";
|
|
17
16
|
import readline from "readline";
|
|
18
17
|
import { getContext } from "./init_browser.js";
|
|
18
|
+
import { locate_element } from "./locate_element.js";
|
|
19
|
+
import { _commandError, _commandFinally, _preCommand, _validateSelectors, _screenshot, _reportToWorld, } from "./command_common.js";
|
|
20
|
+
import { registerDownloadEvent, registerNetworkEvents } from "./network.js";
|
|
19
21
|
const Types = {
|
|
20
22
|
CLICK: "click_element",
|
|
21
23
|
NAVIGATE: "navigate",
|
|
@@ -42,20 +44,27 @@ const Types = {
|
|
|
42
44
|
VERIFY_VISUAL: "verify_visual",
|
|
43
45
|
LOAD_DATA: "load_data",
|
|
44
46
|
SET_INPUT: "set_input",
|
|
47
|
+
WAIT_FOR_TEXT_TO_DISAPPEAR: "wait_for_text_to_disappear",
|
|
45
48
|
};
|
|
46
49
|
export const apps = {};
|
|
47
50
|
class StableBrowser {
|
|
51
|
+
browser;
|
|
52
|
+
page;
|
|
53
|
+
logger;
|
|
54
|
+
context;
|
|
55
|
+
world;
|
|
56
|
+
project_path = null;
|
|
57
|
+
webLogFile = null;
|
|
58
|
+
networkLogger = null;
|
|
59
|
+
configuration = null;
|
|
60
|
+
appName = "main";
|
|
61
|
+
tags = null;
|
|
48
62
|
constructor(browser, page, logger = null, context = null, world = null) {
|
|
49
63
|
this.browser = browser;
|
|
50
64
|
this.page = page;
|
|
51
65
|
this.logger = logger;
|
|
52
66
|
this.context = context;
|
|
53
67
|
this.world = world;
|
|
54
|
-
this.project_path = null;
|
|
55
|
-
this.webLogFile = null;
|
|
56
|
-
this.networkLogger = null;
|
|
57
|
-
this.configuration = null;
|
|
58
|
-
this.appName = "main";
|
|
59
68
|
if (!this.logger) {
|
|
60
69
|
this.logger = console;
|
|
61
70
|
}
|
|
@@ -80,11 +89,13 @@ class StableBrowser {
|
|
|
80
89
|
catch (e) {
|
|
81
90
|
this.logger.error("unable to read ai_config.json");
|
|
82
91
|
}
|
|
83
|
-
context.pageLoading = { status: false };
|
|
84
|
-
context.pages = [this.page];
|
|
85
92
|
const logFolder = path.join(this.project_path, "logs", "web");
|
|
86
93
|
this.world = world;
|
|
94
|
+
context.pages = [this.page];
|
|
95
|
+
context.pageLoading = { status: false };
|
|
87
96
|
this.registerEventListeners(this.context);
|
|
97
|
+
registerNetworkEvents(this.world, this, this.context, this.page);
|
|
98
|
+
registerDownloadEvent(this.page, this.world, this.context);
|
|
88
99
|
}
|
|
89
100
|
registerEventListeners(context) {
|
|
90
101
|
this.registerConsoleLogListener(this.page, context);
|
|
@@ -93,10 +104,17 @@ class StableBrowser {
|
|
|
93
104
|
context.pageLoading = { status: false };
|
|
94
105
|
}
|
|
95
106
|
context.playContext.on("page", async function (page) {
|
|
107
|
+
if (this.configuration && this.configuration.closePopups === true) {
|
|
108
|
+
console.log("close unexpected popups");
|
|
109
|
+
await page.close();
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
96
112
|
context.pageLoading.status = true;
|
|
97
113
|
this.page = page;
|
|
98
114
|
context.page = page;
|
|
99
115
|
context.pages.push(page);
|
|
116
|
+
registerNetworkEvents(this.world, this, context, this.page);
|
|
117
|
+
registerDownloadEvent(this.page, this.world, context);
|
|
100
118
|
page.on("close", async () => {
|
|
101
119
|
if (this.context && this.context.pages && this.context.pages.length > 1) {
|
|
102
120
|
this.context.pages.pop();
|
|
@@ -126,9 +144,9 @@ class StableBrowser {
|
|
|
126
144
|
if (this.appName === appName) {
|
|
127
145
|
return;
|
|
128
146
|
}
|
|
129
|
-
let
|
|
147
|
+
let navigate = false;
|
|
130
148
|
if (!apps[appName]) {
|
|
131
|
-
let newContext = await getContext(null, this.context.headless ? this.context.headless : false, this, this.logger, appName, false, this);
|
|
149
|
+
let newContext = await getContext(null, this.context.headless ? this.context.headless : false, this, this.logger, appName, false, this, -1, this.context.reportFolder);
|
|
132
150
|
newContextCreated = true;
|
|
133
151
|
apps[appName] = {
|
|
134
152
|
context: newContext,
|
|
@@ -141,8 +159,7 @@ class StableBrowser {
|
|
|
141
159
|
this._copyContext(apps[appName], this);
|
|
142
160
|
apps[this.appName] = tempContext;
|
|
143
161
|
this.appName = appName;
|
|
144
|
-
if (
|
|
145
|
-
this.registerEventListeners(this.context);
|
|
162
|
+
if (navigate) {
|
|
146
163
|
await this.goto(this.context.environment.baseUrl);
|
|
147
164
|
await this.waitForPageLoad();
|
|
148
165
|
}
|
|
@@ -168,7 +185,6 @@ class StableBrowser {
|
|
|
168
185
|
this.context.webLogger = [];
|
|
169
186
|
}
|
|
170
187
|
page.on("console", async (msg) => {
|
|
171
|
-
var _a;
|
|
172
188
|
const obj = {
|
|
173
189
|
type: msg.type(),
|
|
174
190
|
text: msg.text(),
|
|
@@ -176,7 +192,9 @@ class StableBrowser {
|
|
|
176
192
|
time: new Date().toISOString(),
|
|
177
193
|
};
|
|
178
194
|
this.context.webLogger.push(obj);
|
|
179
|
-
|
|
195
|
+
if (msg.type() === "error") {
|
|
196
|
+
this.world?.attach(JSON.stringify(obj), { mediaType: "application/json+log" });
|
|
197
|
+
}
|
|
180
198
|
});
|
|
181
199
|
}
|
|
182
200
|
registerRequestListener(page, context, logFile) {
|
|
@@ -184,7 +202,6 @@ class StableBrowser {
|
|
|
184
202
|
this.context.networkLogger = [];
|
|
185
203
|
}
|
|
186
204
|
page.on("request", async (data) => {
|
|
187
|
-
var _a;
|
|
188
205
|
const startTime = new Date().getTime();
|
|
189
206
|
try {
|
|
190
207
|
const pageUrl = new URL(page.url());
|
|
@@ -209,10 +226,10 @@ class StableBrowser {
|
|
|
209
226
|
startTime,
|
|
210
227
|
};
|
|
211
228
|
context.networkLogger.push(obj);
|
|
212
|
-
|
|
229
|
+
this.world?.attach(JSON.stringify(obj), { mediaType: "application/json+network" });
|
|
213
230
|
}
|
|
214
231
|
catch (error) {
|
|
215
|
-
console.error("Error in request listener", error);
|
|
232
|
+
// console.error("Error in request listener", error);
|
|
216
233
|
context.networkLogger.push({
|
|
217
234
|
error: "not able to listen",
|
|
218
235
|
message: error.message,
|
|
@@ -234,20 +251,6 @@ class StableBrowser {
|
|
|
234
251
|
timeout: 60000,
|
|
235
252
|
});
|
|
236
253
|
}
|
|
237
|
-
_validateSelectors(selectors) {
|
|
238
|
-
if (!selectors) {
|
|
239
|
-
throw new Error("selectors is null");
|
|
240
|
-
}
|
|
241
|
-
if (!selectors.locators) {
|
|
242
|
-
throw new Error("selectors.locators is null");
|
|
243
|
-
}
|
|
244
|
-
if (!Array.isArray(selectors.locators)) {
|
|
245
|
-
throw new Error("selectors.locators expected to be array");
|
|
246
|
-
}
|
|
247
|
-
if (selectors.locators.length === 0) {
|
|
248
|
-
throw new Error("selectors.locators expected to be non empty array");
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
254
|
_fixUsingParams(text, _params) {
|
|
252
255
|
if (!_params || typeof text !== "string") {
|
|
253
256
|
return text;
|
|
@@ -315,7 +318,7 @@ class StableBrowser {
|
|
|
315
318
|
locatorReturn = scope.getByRole(role, { name }, { exact: flags === "i" });
|
|
316
319
|
}
|
|
317
320
|
}
|
|
318
|
-
if (locator
|
|
321
|
+
if (locator?.engine) {
|
|
319
322
|
if (locator.engine === "css") {
|
|
320
323
|
locatorReturn = scope.locator(locator.selector);
|
|
321
324
|
}
|
|
@@ -339,7 +342,7 @@ class StableBrowser {
|
|
|
339
342
|
if (css && css.locator) {
|
|
340
343
|
css = css.locator;
|
|
341
344
|
}
|
|
342
|
-
let result = await this._locateElementByText(scope, this._fixUsingParams(text, _params), "
|
|
345
|
+
let result = await this._locateElementByText(scope, this._fixUsingParams(text, _params), "*:not(script, style, head)", false, false, _params);
|
|
343
346
|
if (result.elementCount === 0) {
|
|
344
347
|
return;
|
|
345
348
|
}
|
|
@@ -354,7 +357,7 @@ class StableBrowser {
|
|
|
354
357
|
}
|
|
355
358
|
async _locateElementByText(scope, text1, tag1, regex1 = false, partial1, _params) {
|
|
356
359
|
//const stringifyText = JSON.stringify(text);
|
|
357
|
-
return await scope.evaluate(([text, tag, regex, partial]) => {
|
|
360
|
+
return await scope.locator(":root").evaluate((_node, [text, tag, regex, partial]) => {
|
|
358
361
|
function isParent(parent, child) {
|
|
359
362
|
let currentNode = child.parentNode;
|
|
360
363
|
while (currentNode !== null) {
|
|
@@ -391,7 +394,7 @@ class StableBrowser {
|
|
|
391
394
|
}
|
|
392
395
|
document.collectAllShadowDomElements = collectAllShadowDomElements;
|
|
393
396
|
if (!tag) {
|
|
394
|
-
tag = "
|
|
397
|
+
tag = "*:not(script, style, head)";
|
|
395
398
|
}
|
|
396
399
|
let regexpSearch = document.getRegex(text);
|
|
397
400
|
if (regexpSearch) {
|
|
@@ -473,19 +476,39 @@ class StableBrowser {
|
|
|
473
476
|
}, [text1, tag1, regex1, partial1]);
|
|
474
477
|
}
|
|
475
478
|
async _collectLocatorInformation(selectorHierarchy, index = 0, scope, foundLocators, _params, info, visibleOnly = true) {
|
|
479
|
+
if (!info) {
|
|
480
|
+
info = {};
|
|
481
|
+
}
|
|
482
|
+
if (!info.failCause) {
|
|
483
|
+
info.failCause = {};
|
|
484
|
+
}
|
|
485
|
+
if (!info.log) {
|
|
486
|
+
info.log = "";
|
|
487
|
+
}
|
|
476
488
|
let locatorSearch = selectorHierarchy[index];
|
|
489
|
+
try {
|
|
490
|
+
locatorSearch = JSON.parse(this._fixUsingParams(JSON.stringify(locatorSearch), _params));
|
|
491
|
+
}
|
|
492
|
+
catch (e) {
|
|
493
|
+
console.error(e);
|
|
494
|
+
}
|
|
477
495
|
//info.log += "searching for locator " + JSON.stringify(locatorSearch) + "\n";
|
|
478
496
|
let locator = null;
|
|
479
497
|
if (locatorSearch.climb && locatorSearch.climb >= 0) {
|
|
480
498
|
let locatorString = await this._locateElmentByTextClimbCss(scope, locatorSearch.text, locatorSearch.climb, locatorSearch.css, _params);
|
|
481
499
|
if (!locatorString) {
|
|
500
|
+
info.failCause.textNotFound = true;
|
|
501
|
+
info.failCause.lastError = "failed to locate element by text: " + locatorSearch.text;
|
|
482
502
|
return;
|
|
483
503
|
}
|
|
484
504
|
locator = this._getLocator({ css: locatorString }, scope, _params);
|
|
485
505
|
}
|
|
486
506
|
else if (locatorSearch.text) {
|
|
487
|
-
let
|
|
507
|
+
let text = this._fixUsingParams(locatorSearch.text, _params);
|
|
508
|
+
let result = await this._locateElementByText(scope, text, locatorSearch.tag, false, locatorSearch.partial === true, _params);
|
|
488
509
|
if (result.elementCount === 0) {
|
|
510
|
+
info.failCause.textNotFound = true;
|
|
511
|
+
info.failCause.lastError = "failed to locate element by text: " + text;
|
|
489
512
|
return;
|
|
490
513
|
}
|
|
491
514
|
locatorSearch.css = "[data-blinq-id='blinq-id-" + result.randomToken + "']";
|
|
@@ -502,6 +525,9 @@ class StableBrowser {
|
|
|
502
525
|
// cssHref = true;
|
|
503
526
|
// }
|
|
504
527
|
let count = await locator.count();
|
|
528
|
+
if (count > 0 && !info.failCause.count) {
|
|
529
|
+
info.failCause.count = count;
|
|
530
|
+
}
|
|
505
531
|
//info.log += "total elements found " + count + "\n";
|
|
506
532
|
//let visibleCount = 0;
|
|
507
533
|
let visibleLocator = null;
|
|
@@ -519,6 +545,8 @@ class StableBrowser {
|
|
|
519
545
|
foundLocators.push(locator.nth(j));
|
|
520
546
|
}
|
|
521
547
|
else {
|
|
548
|
+
info.failCause.visible = visible;
|
|
549
|
+
info.failCause.enabled = enabled;
|
|
522
550
|
if (!info.printMessages) {
|
|
523
551
|
info.printMessages = {};
|
|
524
552
|
}
|
|
@@ -530,6 +558,11 @@ class StableBrowser {
|
|
|
530
558
|
}
|
|
531
559
|
}
|
|
532
560
|
async closeUnexpectedPopups(info, _params) {
|
|
561
|
+
if (!info) {
|
|
562
|
+
info = {};
|
|
563
|
+
info.failCause = {};
|
|
564
|
+
info.log = "";
|
|
565
|
+
}
|
|
533
566
|
if (this.configuration.popupHandlers && this.configuration.popupHandlers.length > 0) {
|
|
534
567
|
if (!info) {
|
|
535
568
|
info = {};
|
|
@@ -570,7 +603,10 @@ class StableBrowser {
|
|
|
570
603
|
}
|
|
571
604
|
return { rerun: false };
|
|
572
605
|
}
|
|
573
|
-
async _locate(selectors, info, _params, timeout
|
|
606
|
+
async _locate(selectors, info, _params, timeout) {
|
|
607
|
+
if (!timeout) {
|
|
608
|
+
timeout = 30000;
|
|
609
|
+
}
|
|
574
610
|
for (let i = 0; i < 3; i++) {
|
|
575
611
|
info.log += "attempt " + i + ": total locators " + selectors.locators.length + "\n";
|
|
576
612
|
for (let j = 0; j < selectors.locators.length; j++) {
|
|
@@ -584,13 +620,16 @@ class StableBrowser {
|
|
|
584
620
|
}
|
|
585
621
|
throw new Error("unable to locate element " + JSON.stringify(selectors));
|
|
586
622
|
}
|
|
587
|
-
async
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
623
|
+
async _findFrameScope(selectors, timeout = 30000, info) {
|
|
624
|
+
if (!info) {
|
|
625
|
+
info = {};
|
|
626
|
+
info.failCause = {};
|
|
627
|
+
info.log = "";
|
|
628
|
+
}
|
|
593
629
|
let scope = this.page;
|
|
630
|
+
if (selectors.frame) {
|
|
631
|
+
return selectors.frame;
|
|
632
|
+
}
|
|
594
633
|
if (selectors.iframe_src || selectors.frameLocators) {
|
|
595
634
|
const findFrame = async (frame, framescope) => {
|
|
596
635
|
for (let i = 0; i < frame.selectors.length; i++) {
|
|
@@ -617,7 +656,6 @@ class StableBrowser {
|
|
|
617
656
|
}
|
|
618
657
|
return framescope;
|
|
619
658
|
};
|
|
620
|
-
info.log += "searching for iframe " + selectors.iframe_src + "/" + selectors.frameLocators + "\n";
|
|
621
659
|
while (true) {
|
|
622
660
|
let frameFound = false;
|
|
623
661
|
if (selectors.nestFrmLoc) {
|
|
@@ -641,6 +679,8 @@ class StableBrowser {
|
|
|
641
679
|
if (!scope) {
|
|
642
680
|
info.log += "unable to locate iframe " + selectors.iframe_src + "\n";
|
|
643
681
|
if (performance.now() - startTime > timeout) {
|
|
682
|
+
info.failCause.iframeNotFound = true;
|
|
683
|
+
info.failCause.lastError = "unable to locate iframe " + selectors.iframe_src;
|
|
644
684
|
throw new Error("unable to locate iframe " + selectors.iframe_src);
|
|
645
685
|
}
|
|
646
686
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
@@ -650,6 +690,30 @@ class StableBrowser {
|
|
|
650
690
|
}
|
|
651
691
|
}
|
|
652
692
|
}
|
|
693
|
+
if (!scope) {
|
|
694
|
+
scope = this.page;
|
|
695
|
+
}
|
|
696
|
+
return scope;
|
|
697
|
+
}
|
|
698
|
+
async _getDocumentBody(selectors, timeout = 30000, info) {
|
|
699
|
+
let scope = await this._findFrameScope(selectors, timeout, info);
|
|
700
|
+
return scope.evaluate(() => {
|
|
701
|
+
var bodyContent = document.body.innerHTML;
|
|
702
|
+
return bodyContent;
|
|
703
|
+
});
|
|
704
|
+
}
|
|
705
|
+
async _locate_internal(selectors, info, _params, timeout = 30000) {
|
|
706
|
+
if (!info) {
|
|
707
|
+
info = {};
|
|
708
|
+
info.failCause = {};
|
|
709
|
+
info.log = "";
|
|
710
|
+
}
|
|
711
|
+
let highPriorityTimeout = 5000;
|
|
712
|
+
let visibleOnlyTimeout = 6000;
|
|
713
|
+
let startTime = performance.now();
|
|
714
|
+
let locatorsCount = 0;
|
|
715
|
+
//let arrayMode = Array.isArray(selectors);
|
|
716
|
+
let scope = await this._findFrameScope(selectors, timeout, info);
|
|
653
717
|
let selectorsLocators = null;
|
|
654
718
|
selectorsLocators = selectors.locators;
|
|
655
719
|
// group selectors by priority
|
|
@@ -751,6 +815,8 @@ class StableBrowser {
|
|
|
751
815
|
}
|
|
752
816
|
this.logger.debug("unable to locate unique element, total elements found " + locatorsCount);
|
|
753
817
|
info.log += "failed to locate unique element, total elements found " + locatorsCount + "\n";
|
|
818
|
+
info.failCause.locatorNotFound = true;
|
|
819
|
+
info.failCause.lastError = "failed to locate unique element";
|
|
754
820
|
throw new Error("failed to locate first element no elements found, " + info.log);
|
|
755
821
|
}
|
|
756
822
|
async _scanLocatorsGroup(locatorsGroup, scope, _params, info, visibleOnly) {
|
|
@@ -782,89 +848,129 @@ class StableBrowser {
|
|
|
782
848
|
});
|
|
783
849
|
result.locatorIndex = i;
|
|
784
850
|
}
|
|
851
|
+
if (foundLocators.length > 1) {
|
|
852
|
+
info.failCause.foundMultiple = true;
|
|
853
|
+
}
|
|
785
854
|
}
|
|
786
855
|
return result;
|
|
787
856
|
}
|
|
788
|
-
async
|
|
789
|
-
this._validateSelectors(selectors);
|
|
857
|
+
async simpleClick(elementDescription, _params, options = {}, world = null) {
|
|
790
858
|
const startTime = Date.now();
|
|
791
|
-
|
|
792
|
-
|
|
859
|
+
let timeout = 30000;
|
|
860
|
+
if (options && options.timeout) {
|
|
861
|
+
timeout = options.timeout;
|
|
793
862
|
}
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
863
|
+
while (true) {
|
|
864
|
+
try {
|
|
865
|
+
const result = await locate_element(this.context, elementDescription, "click");
|
|
866
|
+
if (result?.elementNumber >= 0) {
|
|
867
|
+
const selectors = {
|
|
868
|
+
frame: result?.frame,
|
|
869
|
+
locators: [
|
|
870
|
+
{
|
|
871
|
+
css: result?.css,
|
|
872
|
+
},
|
|
873
|
+
],
|
|
874
|
+
};
|
|
875
|
+
await this.click(selectors, _params, options, world);
|
|
876
|
+
return;
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
catch (e) {
|
|
880
|
+
if (performance.now() - startTime > timeout) {
|
|
881
|
+
// throw e;
|
|
882
|
+
await _commandError({ text: "simpleClick", operation: "simpleClick", elementDescription, info: {} }, e, this);
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
await new Promise((resolve) => setTimeout(resolve, 3000));
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
async simpleClickType(elementDescription, value, _params, options = {}, world = null) {
|
|
889
|
+
const startTime = Date.now();
|
|
890
|
+
let timeout = 30000;
|
|
891
|
+
if (options && options.timeout) {
|
|
892
|
+
timeout = options.timeout;
|
|
893
|
+
}
|
|
894
|
+
while (true) {
|
|
895
|
+
try {
|
|
896
|
+
const result = await locate_element(this.context, elementDescription, "fill", value);
|
|
897
|
+
if (result?.elementNumber >= 0) {
|
|
898
|
+
const selectors = {
|
|
899
|
+
frame: result?.frame,
|
|
900
|
+
locators: [
|
|
901
|
+
{
|
|
902
|
+
css: result?.css,
|
|
903
|
+
},
|
|
904
|
+
],
|
|
905
|
+
};
|
|
906
|
+
await this.clickType(selectors, value, false, _params, options, world);
|
|
907
|
+
return;
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
catch (e) {
|
|
911
|
+
if (performance.now() - startTime > timeout) {
|
|
912
|
+
// throw e;
|
|
913
|
+
await _commandError({ text: "simpleClickType", operation: "simpleClickType", value, elementDescription, info: {} }, e, this);
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
await new Promise((resolve) => setTimeout(resolve, 3000));
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
async click(selectors, _params, options = {}, world = null) {
|
|
920
|
+
const state = {
|
|
921
|
+
selectors,
|
|
922
|
+
_params,
|
|
923
|
+
options,
|
|
924
|
+
world,
|
|
925
|
+
text: "Click element",
|
|
926
|
+
type: Types.CLICK,
|
|
927
|
+
operation: "click",
|
|
928
|
+
log: "***** click on " + selectors.element_name + " *****\n",
|
|
929
|
+
};
|
|
801
930
|
try {
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
931
|
+
await _preCommand(state, this);
|
|
932
|
+
if (state.options && state.options.context) {
|
|
933
|
+
state.selectors.locators[0].text = state.options.context;
|
|
934
|
+
}
|
|
805
935
|
try {
|
|
806
|
-
await
|
|
807
|
-
await
|
|
808
|
-
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
936
|
+
await state.element.click();
|
|
937
|
+
// await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
809
938
|
}
|
|
810
939
|
catch (e) {
|
|
811
940
|
// await this.closeUnexpectedPopups();
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
await
|
|
815
|
-
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
941
|
+
state.element = await this._locate(selectors, state.info, _params);
|
|
942
|
+
await state.element.dispatchEvent("click");
|
|
943
|
+
// await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
816
944
|
}
|
|
817
945
|
await this.waitForPageLoad();
|
|
818
|
-
return info;
|
|
946
|
+
return state.info;
|
|
819
947
|
}
|
|
820
948
|
catch (e) {
|
|
821
|
-
|
|
822
|
-
({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
|
|
823
|
-
info.screenshotPath = screenshotPath;
|
|
824
|
-
Object.assign(e, { info: info });
|
|
825
|
-
error = e;
|
|
826
|
-
throw e;
|
|
949
|
+
await _commandError(state, e, this);
|
|
827
950
|
}
|
|
828
951
|
finally {
|
|
829
|
-
|
|
830
|
-
this._reportToWorld(world, {
|
|
831
|
-
element_name: selectors.element_name,
|
|
832
|
-
type: Types.CLICK,
|
|
833
|
-
text: `Click element`,
|
|
834
|
-
screenshotId,
|
|
835
|
-
result: error
|
|
836
|
-
? {
|
|
837
|
-
status: "FAILED",
|
|
838
|
-
startTime,
|
|
839
|
-
endTime,
|
|
840
|
-
message: error === null || error === void 0 ? void 0 : error.message,
|
|
841
|
-
}
|
|
842
|
-
: {
|
|
843
|
-
status: "PASSED",
|
|
844
|
-
startTime,
|
|
845
|
-
endTime,
|
|
846
|
-
},
|
|
847
|
-
info: info,
|
|
848
|
-
});
|
|
952
|
+
_commandFinally(state, this);
|
|
849
953
|
}
|
|
850
954
|
}
|
|
851
955
|
async setCheck(selectors, checked = true, _params, options = {}, world = null) {
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
956
|
+
const state = {
|
|
957
|
+
selectors,
|
|
958
|
+
_params,
|
|
959
|
+
options,
|
|
960
|
+
world,
|
|
961
|
+
type: checked ? Types.CHECK : Types.UNCHECK,
|
|
962
|
+
text: checked ? `Check element` : `Uncheck element`,
|
|
963
|
+
operation: "setCheck",
|
|
964
|
+
log: "***** check " + selectors.element_name + " *****\n",
|
|
965
|
+
};
|
|
862
966
|
try {
|
|
863
|
-
|
|
864
|
-
|
|
967
|
+
await _preCommand(state, this);
|
|
968
|
+
state.info.checked = checked;
|
|
969
|
+
// let element = await this._locate(selectors, info, _params);
|
|
970
|
+
// ({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
|
|
865
971
|
try {
|
|
866
|
-
await this._highlightElements(element);
|
|
867
|
-
await element.setChecked(checked);
|
|
972
|
+
// await this._highlightElements(element);
|
|
973
|
+
await state.element.setChecked(checked);
|
|
868
974
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
869
975
|
}
|
|
870
976
|
catch (e) {
|
|
@@ -873,179 +979,108 @@ class StableBrowser {
|
|
|
873
979
|
}
|
|
874
980
|
else {
|
|
875
981
|
//await this.closeUnexpectedPopups();
|
|
876
|
-
info.log += "setCheck failed, will try again" + "\n";
|
|
877
|
-
element = await this._locate(selectors, info, _params);
|
|
878
|
-
await element.setChecked(checked, { timeout: 5000, force: true });
|
|
982
|
+
state.info.log += "setCheck failed, will try again" + "\n";
|
|
983
|
+
state.element = await this._locate(selectors, state.info, _params);
|
|
984
|
+
await state.element.setChecked(checked, { timeout: 5000, force: true });
|
|
879
985
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
880
986
|
}
|
|
881
987
|
}
|
|
882
988
|
await this.waitForPageLoad();
|
|
883
|
-
return info;
|
|
989
|
+
return state.info;
|
|
884
990
|
}
|
|
885
991
|
catch (e) {
|
|
886
|
-
|
|
887
|
-
({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
|
|
888
|
-
info.screenshotPath = screenshotPath;
|
|
889
|
-
Object.assign(e, { info: info });
|
|
890
|
-
error = e;
|
|
891
|
-
throw e;
|
|
992
|
+
await _commandError(state, e, this);
|
|
892
993
|
}
|
|
893
994
|
finally {
|
|
894
|
-
|
|
895
|
-
this._reportToWorld(world, {
|
|
896
|
-
element_name: selectors.element_name,
|
|
897
|
-
type: checked ? Types.CHECK : Types.UNCHECK,
|
|
898
|
-
text: checked ? `Check element` : `Uncheck element`,
|
|
899
|
-
screenshotId,
|
|
900
|
-
result: error
|
|
901
|
-
? {
|
|
902
|
-
status: "FAILED",
|
|
903
|
-
startTime,
|
|
904
|
-
endTime,
|
|
905
|
-
message: error === null || error === void 0 ? void 0 : error.message,
|
|
906
|
-
}
|
|
907
|
-
: {
|
|
908
|
-
status: "PASSED",
|
|
909
|
-
startTime,
|
|
910
|
-
endTime,
|
|
911
|
-
},
|
|
912
|
-
info: info,
|
|
913
|
-
});
|
|
995
|
+
_commandFinally(state, this);
|
|
914
996
|
}
|
|
915
997
|
}
|
|
916
998
|
async hover(selectors, _params, options = {}, world = null) {
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
999
|
+
const state = {
|
|
1000
|
+
selectors,
|
|
1001
|
+
_params,
|
|
1002
|
+
options,
|
|
1003
|
+
world,
|
|
1004
|
+
type: Types.HOVER,
|
|
1005
|
+
text: `Hover element`,
|
|
1006
|
+
operation: "hover",
|
|
1007
|
+
log: "***** hover " + selectors.element_name + " *****\n",
|
|
1008
|
+
};
|
|
926
1009
|
try {
|
|
927
|
-
|
|
928
|
-
({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
|
|
1010
|
+
await _preCommand(state, this);
|
|
929
1011
|
try {
|
|
930
|
-
await
|
|
931
|
-
await element.hover();
|
|
1012
|
+
await state.element.hover();
|
|
932
1013
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
933
1014
|
}
|
|
934
1015
|
catch (e) {
|
|
935
1016
|
//await this.closeUnexpectedPopups();
|
|
936
|
-
info.log += "hover failed, will try again" + "\n";
|
|
937
|
-
element = await this._locate(selectors, info, _params);
|
|
938
|
-
await element.hover({ timeout: 10000 });
|
|
1017
|
+
state.info.log += "hover failed, will try again" + "\n";
|
|
1018
|
+
state.element = await this._locate(selectors, state.info, _params);
|
|
1019
|
+
await state.element.hover({ timeout: 10000 });
|
|
939
1020
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
940
1021
|
}
|
|
941
1022
|
await this.waitForPageLoad();
|
|
942
|
-
return info;
|
|
1023
|
+
return state.info;
|
|
943
1024
|
}
|
|
944
1025
|
catch (e) {
|
|
945
|
-
|
|
946
|
-
({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
|
|
947
|
-
info.screenshotPath = screenshotPath;
|
|
948
|
-
Object.assign(e, { info: info });
|
|
949
|
-
error = e;
|
|
950
|
-
throw e;
|
|
1026
|
+
await _commandError(state, e, this);
|
|
951
1027
|
}
|
|
952
1028
|
finally {
|
|
953
|
-
|
|
954
|
-
this._reportToWorld(world, {
|
|
955
|
-
element_name: selectors.element_name,
|
|
956
|
-
type: Types.HOVER,
|
|
957
|
-
text: `Hover element`,
|
|
958
|
-
screenshotId,
|
|
959
|
-
result: error
|
|
960
|
-
? {
|
|
961
|
-
status: "FAILED",
|
|
962
|
-
startTime,
|
|
963
|
-
endTime,
|
|
964
|
-
message: error === null || error === void 0 ? void 0 : error.message,
|
|
965
|
-
}
|
|
966
|
-
: {
|
|
967
|
-
status: "PASSED",
|
|
968
|
-
startTime,
|
|
969
|
-
endTime,
|
|
970
|
-
},
|
|
971
|
-
info: info,
|
|
972
|
-
});
|
|
1029
|
+
_commandFinally(state, this);
|
|
973
1030
|
}
|
|
974
1031
|
}
|
|
975
1032
|
async selectOption(selectors, values, _params = null, options = {}, world = null) {
|
|
976
|
-
this._validateSelectors(selectors);
|
|
977
1033
|
if (!values) {
|
|
978
1034
|
throw new Error("values is null");
|
|
979
1035
|
}
|
|
980
|
-
const
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
1036
|
+
const state = {
|
|
1037
|
+
selectors,
|
|
1038
|
+
_params,
|
|
1039
|
+
options,
|
|
1040
|
+
world,
|
|
1041
|
+
value: values.toString(),
|
|
1042
|
+
type: Types.SELECT,
|
|
1043
|
+
text: `Select option: ${values}`,
|
|
1044
|
+
operation: "selectOption",
|
|
1045
|
+
log: "***** select option " + selectors.element_name + " *****\n",
|
|
1046
|
+
};
|
|
988
1047
|
try {
|
|
989
|
-
|
|
990
|
-
({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
|
|
1048
|
+
await _preCommand(state, this);
|
|
991
1049
|
try {
|
|
992
|
-
await
|
|
993
|
-
await element.selectOption(values);
|
|
1050
|
+
await state.element.selectOption(values);
|
|
994
1051
|
}
|
|
995
1052
|
catch (e) {
|
|
996
1053
|
//await this.closeUnexpectedPopups();
|
|
997
|
-
info.log += "selectOption failed, will try force" + "\n";
|
|
998
|
-
await element.selectOption(values, { timeout: 10000, force: true });
|
|
1054
|
+
state.info.log += "selectOption failed, will try force" + "\n";
|
|
1055
|
+
await state.element.selectOption(values, { timeout: 10000, force: true });
|
|
999
1056
|
}
|
|
1000
1057
|
await this.waitForPageLoad();
|
|
1001
|
-
return info;
|
|
1058
|
+
return state.info;
|
|
1002
1059
|
}
|
|
1003
1060
|
catch (e) {
|
|
1004
|
-
|
|
1005
|
-
({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
|
|
1006
|
-
info.screenshotPath = screenshotPath;
|
|
1007
|
-
Object.assign(e, { info: info });
|
|
1008
|
-
this.logger.info("click failed, will try next selector");
|
|
1009
|
-
error = e;
|
|
1010
|
-
throw e;
|
|
1061
|
+
await _commandError(state, e, this);
|
|
1011
1062
|
}
|
|
1012
1063
|
finally {
|
|
1013
|
-
|
|
1014
|
-
this._reportToWorld(world, {
|
|
1015
|
-
element_name: selectors.element_name,
|
|
1016
|
-
type: Types.SELECT,
|
|
1017
|
-
text: `Select option: ${values}`,
|
|
1018
|
-
value: values.toString(),
|
|
1019
|
-
screenshotId,
|
|
1020
|
-
result: error
|
|
1021
|
-
? {
|
|
1022
|
-
status: "FAILED",
|
|
1023
|
-
startTime,
|
|
1024
|
-
endTime,
|
|
1025
|
-
message: error === null || error === void 0 ? void 0 : error.message,
|
|
1026
|
-
}
|
|
1027
|
-
: {
|
|
1028
|
-
status: "PASSED",
|
|
1029
|
-
startTime,
|
|
1030
|
-
endTime,
|
|
1031
|
-
},
|
|
1032
|
-
info: info,
|
|
1033
|
-
});
|
|
1064
|
+
_commandFinally(state, this);
|
|
1034
1065
|
}
|
|
1035
1066
|
}
|
|
1036
1067
|
async type(_value, _params = null, options = {}, world = null) {
|
|
1037
|
-
const
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1068
|
+
const state = {
|
|
1069
|
+
value: _value,
|
|
1070
|
+
_params,
|
|
1071
|
+
options,
|
|
1072
|
+
world,
|
|
1073
|
+
locate: false,
|
|
1074
|
+
scroll: false,
|
|
1075
|
+
highlight: false,
|
|
1076
|
+
type: Types.TYPE_PRESS,
|
|
1077
|
+
text: `Type value: ${_value}`,
|
|
1078
|
+
operation: "type",
|
|
1079
|
+
log: "",
|
|
1080
|
+
};
|
|
1046
1081
|
try {
|
|
1047
|
-
|
|
1048
|
-
const valueSegment =
|
|
1082
|
+
await _preCommand(state, this);
|
|
1083
|
+
const valueSegment = state.value.split("&&");
|
|
1049
1084
|
for (let i = 0; i < valueSegment.length; i++) {
|
|
1050
1085
|
if (i > 0) {
|
|
1051
1086
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
@@ -1065,134 +1100,76 @@ class StableBrowser {
|
|
|
1065
1100
|
await this.page.keyboard.type(value);
|
|
1066
1101
|
}
|
|
1067
1102
|
}
|
|
1068
|
-
return info;
|
|
1103
|
+
return state.info;
|
|
1069
1104
|
}
|
|
1070
1105
|
catch (e) {
|
|
1071
|
-
|
|
1072
|
-
this.logger.error("type failed " + info.log);
|
|
1073
|
-
({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
|
|
1074
|
-
info.screenshotPath = screenshotPath;
|
|
1075
|
-
Object.assign(e, { info: info });
|
|
1076
|
-
error = e;
|
|
1077
|
-
throw e;
|
|
1106
|
+
await _commandError(state, e, this);
|
|
1078
1107
|
}
|
|
1079
1108
|
finally {
|
|
1080
|
-
|
|
1081
|
-
this._reportToWorld(world, {
|
|
1082
|
-
type: Types.TYPE_PRESS,
|
|
1083
|
-
screenshotId,
|
|
1084
|
-
value: _value,
|
|
1085
|
-
text: `type value: ${_value}`,
|
|
1086
|
-
result: error
|
|
1087
|
-
? {
|
|
1088
|
-
status: "FAILED",
|
|
1089
|
-
startTime,
|
|
1090
|
-
endTime,
|
|
1091
|
-
message: error === null || error === void 0 ? void 0 : error.message,
|
|
1092
|
-
}
|
|
1093
|
-
: {
|
|
1094
|
-
status: "PASSED",
|
|
1095
|
-
startTime,
|
|
1096
|
-
endTime,
|
|
1097
|
-
},
|
|
1098
|
-
info: info,
|
|
1099
|
-
});
|
|
1109
|
+
_commandFinally(state, this);
|
|
1100
1110
|
}
|
|
1101
1111
|
}
|
|
1102
1112
|
async setInputValue(selectors, value, _params = null, options = {}, world = null) {
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
let screenshotPath = null;
|
|
1113
|
+
const state = {
|
|
1114
|
+
selectors,
|
|
1115
|
+
_params,
|
|
1116
|
+
value,
|
|
1117
|
+
options,
|
|
1118
|
+
world,
|
|
1119
|
+
type: Types.SET_INPUT,
|
|
1120
|
+
text: `Set input value`,
|
|
1121
|
+
operation: "setInputValue",
|
|
1122
|
+
log: "***** set input value " + selectors.element_name + " *****\n",
|
|
1123
|
+
};
|
|
1115
1124
|
try {
|
|
1116
|
-
|
|
1117
|
-
let
|
|
1118
|
-
await this.scrollIfNeeded(element, info);
|
|
1119
|
-
({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
|
|
1120
|
-
await this._highlightElements(element);
|
|
1125
|
+
await _preCommand(state, this);
|
|
1126
|
+
let value = await this._replaceWithLocalData(state.value, this);
|
|
1121
1127
|
try {
|
|
1122
|
-
await element.evaluateHandle((el, value) => {
|
|
1128
|
+
await state.element.evaluateHandle((el, value) => {
|
|
1123
1129
|
el.value = value;
|
|
1124
1130
|
}, value);
|
|
1125
1131
|
}
|
|
1126
1132
|
catch (error) {
|
|
1127
1133
|
this.logger.error("setInputValue failed, will try again");
|
|
1128
|
-
|
|
1129
|
-
info.
|
|
1130
|
-
|
|
1131
|
-
await element.evaluateHandle((el, value) => {
|
|
1134
|
+
await _screenshot(state, this);
|
|
1135
|
+
Object.assign(error, { info: state.info });
|
|
1136
|
+
await state.element.evaluateHandle((el, value) => {
|
|
1132
1137
|
el.value = value;
|
|
1133
1138
|
});
|
|
1134
1139
|
}
|
|
1135
1140
|
}
|
|
1136
1141
|
catch (e) {
|
|
1137
|
-
|
|
1138
|
-
({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
|
|
1139
|
-
info.screenshotPath = screenshotPath;
|
|
1140
|
-
Object.assign(e, { info: info });
|
|
1141
|
-
error = e;
|
|
1142
|
-
throw e;
|
|
1142
|
+
await _commandError(state, e, this);
|
|
1143
1143
|
}
|
|
1144
1144
|
finally {
|
|
1145
|
-
|
|
1146
|
-
this._reportToWorld(world, {
|
|
1147
|
-
element_name: selectors.element_name,
|
|
1148
|
-
type: Types.SET_INPUT,
|
|
1149
|
-
text: `Set input value`,
|
|
1150
|
-
value: value,
|
|
1151
|
-
screenshotId,
|
|
1152
|
-
result: error
|
|
1153
|
-
? {
|
|
1154
|
-
status: "FAILED",
|
|
1155
|
-
startTime,
|
|
1156
|
-
endTime,
|
|
1157
|
-
message: error === null || error === void 0 ? void 0 : error.message,
|
|
1158
|
-
}
|
|
1159
|
-
: {
|
|
1160
|
-
status: "PASSED",
|
|
1161
|
-
startTime,
|
|
1162
|
-
endTime,
|
|
1163
|
-
},
|
|
1164
|
-
info: info,
|
|
1165
|
-
});
|
|
1145
|
+
_commandFinally(state, this);
|
|
1166
1146
|
}
|
|
1167
1147
|
}
|
|
1168
1148
|
async setDateTime(selectors, value, format = null, enter = false, _params = null, options = {}, world = null) {
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1149
|
+
const state = {
|
|
1150
|
+
selectors,
|
|
1151
|
+
_params,
|
|
1152
|
+
value: await this._replaceWithLocalData(value, this),
|
|
1153
|
+
options,
|
|
1154
|
+
world,
|
|
1155
|
+
type: Types.SET_DATE_TIME,
|
|
1156
|
+
text: `Set date time value: ${value}`,
|
|
1157
|
+
operation: "setDateTime",
|
|
1158
|
+
log: "***** set date time value " + selectors.element_name + " *****\n",
|
|
1159
|
+
throwError: false,
|
|
1160
|
+
};
|
|
1179
1161
|
try {
|
|
1180
|
-
|
|
1181
|
-
let element = await this._locate(selectors, info, _params);
|
|
1182
|
-
//insert red border around the element
|
|
1183
|
-
await this.scrollIfNeeded(element, info);
|
|
1184
|
-
({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
|
|
1185
|
-
await this._highlightElements(element);
|
|
1162
|
+
await _preCommand(state, this);
|
|
1186
1163
|
try {
|
|
1187
|
-
await element.click();
|
|
1164
|
+
await state.element.click();
|
|
1188
1165
|
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
1189
1166
|
if (format) {
|
|
1190
|
-
value = dayjs(value).format(format);
|
|
1191
|
-
await element.fill(value);
|
|
1167
|
+
state.value = dayjs(state.value).format(format);
|
|
1168
|
+
await state.element.fill(state.value);
|
|
1192
1169
|
}
|
|
1193
1170
|
else {
|
|
1194
|
-
const dateTimeValue = await getDateTimeValue({ value, element });
|
|
1195
|
-
await element.evaluateHandle((el, dateTimeValue) => {
|
|
1171
|
+
const dateTimeValue = await getDateTimeValue({ value: state.value, element: state.element });
|
|
1172
|
+
await state.element.evaluateHandle((el, dateTimeValue) => {
|
|
1196
1173
|
el.value = ""; // clear input
|
|
1197
1174
|
el.value = dateTimeValue;
|
|
1198
1175
|
}, dateTimeValue);
|
|
@@ -1205,20 +1182,19 @@ class StableBrowser {
|
|
|
1205
1182
|
}
|
|
1206
1183
|
catch (err) {
|
|
1207
1184
|
//await this.closeUnexpectedPopups();
|
|
1208
|
-
this.logger.error("setting date time input failed " + JSON.stringify(info));
|
|
1185
|
+
this.logger.error("setting date time input failed " + JSON.stringify(state.info));
|
|
1209
1186
|
this.logger.info("Trying again");
|
|
1210
|
-
|
|
1211
|
-
info.
|
|
1212
|
-
Object.assign(err, { info: info });
|
|
1187
|
+
await _screenshot(state, this);
|
|
1188
|
+
Object.assign(err, { info: state.info });
|
|
1213
1189
|
await element.click();
|
|
1214
1190
|
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
1215
1191
|
if (format) {
|
|
1216
|
-
value = dayjs(value).format(format);
|
|
1217
|
-
await element.fill(value);
|
|
1192
|
+
state.value = dayjs(state.value).format(format);
|
|
1193
|
+
await state.element.fill(state.value);
|
|
1218
1194
|
}
|
|
1219
1195
|
else {
|
|
1220
|
-
const dateTimeValue = await getDateTimeValue({ value, element });
|
|
1221
|
-
await element.evaluateHandle((el, dateTimeValue) => {
|
|
1196
|
+
const dateTimeValue = await getDateTimeValue({ value: state.value, element: state.element });
|
|
1197
|
+
await state.element.evaluateHandle((el, dateTimeValue) => {
|
|
1222
1198
|
el.value = ""; // clear input
|
|
1223
1199
|
el.value = dateTimeValue;
|
|
1224
1200
|
}, dateTimeValue);
|
|
@@ -1231,60 +1207,39 @@ class StableBrowser {
|
|
|
1231
1207
|
}
|
|
1232
1208
|
}
|
|
1233
1209
|
catch (e) {
|
|
1234
|
-
|
|
1235
|
-
throw e;
|
|
1210
|
+
await _commandError(state, e, this);
|
|
1236
1211
|
}
|
|
1237
1212
|
finally {
|
|
1238
|
-
|
|
1239
|
-
this._reportToWorld(world, {
|
|
1240
|
-
element_name: selectors.element_name,
|
|
1241
|
-
type: Types.SET_DATE_TIME,
|
|
1242
|
-
screenshotId,
|
|
1243
|
-
value: value,
|
|
1244
|
-
text: `setDateTime input with value: ${value}`,
|
|
1245
|
-
result: error
|
|
1246
|
-
? {
|
|
1247
|
-
status: "FAILED",
|
|
1248
|
-
startTime,
|
|
1249
|
-
endTime,
|
|
1250
|
-
message: error === null || error === void 0 ? void 0 : error.message,
|
|
1251
|
-
}
|
|
1252
|
-
: {
|
|
1253
|
-
status: "PASSED",
|
|
1254
|
-
startTime,
|
|
1255
|
-
endTime,
|
|
1256
|
-
},
|
|
1257
|
-
info: info,
|
|
1258
|
-
});
|
|
1213
|
+
_commandFinally(state, this);
|
|
1259
1214
|
}
|
|
1260
1215
|
}
|
|
1261
1216
|
async clickType(selectors, _value, enter = false, _params = null, options = {}, world = null) {
|
|
1262
1217
|
_value = unEscapeString(_value);
|
|
1263
|
-
this._validateSelectors(selectors);
|
|
1264
|
-
const startTime = Date.now();
|
|
1265
|
-
let error = null;
|
|
1266
|
-
let screenshotId = null;
|
|
1267
|
-
let screenshotPath = null;
|
|
1268
|
-
const info = {};
|
|
1269
|
-
info.log = "***** clickType on " + selectors.element_name + " with value " + _value + "*****\n";
|
|
1270
|
-
info.operation = "clickType";
|
|
1271
|
-
info.selectors = selectors;
|
|
1272
1218
|
const newValue = await this._replaceWithLocalData(_value, world);
|
|
1219
|
+
const state = {
|
|
1220
|
+
selectors,
|
|
1221
|
+
_params,
|
|
1222
|
+
value: newValue,
|
|
1223
|
+
originalValue: _value,
|
|
1224
|
+
options,
|
|
1225
|
+
world,
|
|
1226
|
+
type: Types.FILL,
|
|
1227
|
+
text: `Click type input with value: ${_value}`,
|
|
1228
|
+
operation: "clickType",
|
|
1229
|
+
log: "***** clickType on " + selectors.element_name + " with value " + maskValue(_value) + "*****\n",
|
|
1230
|
+
};
|
|
1273
1231
|
if (newValue !== _value) {
|
|
1274
1232
|
//this.logger.info(_value + "=" + newValue);
|
|
1275
1233
|
_value = newValue;
|
|
1276
1234
|
}
|
|
1277
|
-
info.value = _value;
|
|
1278
1235
|
try {
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
await this.scrollIfNeeded(element, info);
|
|
1282
|
-
await this._highlightElements(element);
|
|
1236
|
+
await _preCommand(state, this);
|
|
1237
|
+
state.info.value = _value;
|
|
1283
1238
|
if (options === null || options === undefined || !options.press) {
|
|
1284
1239
|
try {
|
|
1285
|
-
let currentValue = await element.inputValue();
|
|
1240
|
+
let currentValue = await state.element.inputValue();
|
|
1286
1241
|
if (currentValue) {
|
|
1287
|
-
await element.fill("");
|
|
1242
|
+
await state.element.fill("");
|
|
1288
1243
|
}
|
|
1289
1244
|
}
|
|
1290
1245
|
catch (e) {
|
|
@@ -1293,22 +1248,22 @@ class StableBrowser {
|
|
|
1293
1248
|
}
|
|
1294
1249
|
if (options === null || options === undefined || options.press) {
|
|
1295
1250
|
try {
|
|
1296
|
-
await element.click({ timeout: 5000 });
|
|
1251
|
+
await state.element.click({ timeout: 5000 });
|
|
1297
1252
|
}
|
|
1298
1253
|
catch (e) {
|
|
1299
|
-
await element.dispatchEvent("click");
|
|
1254
|
+
await state.element.dispatchEvent("click");
|
|
1300
1255
|
}
|
|
1301
1256
|
}
|
|
1302
1257
|
else {
|
|
1303
1258
|
try {
|
|
1304
|
-
await element.focus();
|
|
1259
|
+
await state.element.focus();
|
|
1305
1260
|
}
|
|
1306
1261
|
catch (e) {
|
|
1307
|
-
await element.dispatchEvent("focus");
|
|
1262
|
+
await state.element.dispatchEvent("focus");
|
|
1308
1263
|
}
|
|
1309
1264
|
}
|
|
1310
1265
|
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
1311
|
-
const valueSegment =
|
|
1266
|
+
const valueSegment = state.value.split("&&");
|
|
1312
1267
|
for (let i = 0; i < valueSegment.length; i++) {
|
|
1313
1268
|
if (i > 0) {
|
|
1314
1269
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
@@ -1328,14 +1283,14 @@ class StableBrowser {
|
|
|
1328
1283
|
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
1329
1284
|
}
|
|
1330
1285
|
}
|
|
1331
|
-
|
|
1286
|
+
await _screenshot(state, this);
|
|
1332
1287
|
if (enter === true) {
|
|
1333
1288
|
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
1334
1289
|
await this.page.keyboard.press("Enter");
|
|
1335
1290
|
await this.waitForPageLoad();
|
|
1336
1291
|
}
|
|
1337
1292
|
else if (enter === false) {
|
|
1338
|
-
await element.dispatchEvent("change");
|
|
1293
|
+
await state.element.dispatchEvent("change");
|
|
1339
1294
|
//await this.page.keyboard.press("Tab");
|
|
1340
1295
|
}
|
|
1341
1296
|
else {
|
|
@@ -1344,104 +1299,50 @@ class StableBrowser {
|
|
|
1344
1299
|
await this.waitForPageLoad();
|
|
1345
1300
|
}
|
|
1346
1301
|
}
|
|
1347
|
-
return info;
|
|
1302
|
+
return state.info;
|
|
1348
1303
|
}
|
|
1349
1304
|
catch (e) {
|
|
1350
|
-
|
|
1351
|
-
this.logger.error("fill failed " + JSON.stringify(info));
|
|
1352
|
-
({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
|
|
1353
|
-
info.screenshotPath = screenshotPath;
|
|
1354
|
-
Object.assign(e, { info: info });
|
|
1355
|
-
error = e;
|
|
1356
|
-
throw e;
|
|
1305
|
+
await _commandError(state, e, this);
|
|
1357
1306
|
}
|
|
1358
1307
|
finally {
|
|
1359
|
-
|
|
1360
|
-
this._reportToWorld(world, {
|
|
1361
|
-
element_name: selectors.element_name,
|
|
1362
|
-
type: Types.FILL,
|
|
1363
|
-
screenshotId,
|
|
1364
|
-
value: _value,
|
|
1365
|
-
text: `clickType input with value: ${_value}`,
|
|
1366
|
-
result: error
|
|
1367
|
-
? {
|
|
1368
|
-
status: "FAILED",
|
|
1369
|
-
startTime,
|
|
1370
|
-
endTime,
|
|
1371
|
-
message: error === null || error === void 0 ? void 0 : error.message,
|
|
1372
|
-
}
|
|
1373
|
-
: {
|
|
1374
|
-
status: "PASSED",
|
|
1375
|
-
startTime,
|
|
1376
|
-
endTime,
|
|
1377
|
-
},
|
|
1378
|
-
info: info,
|
|
1379
|
-
});
|
|
1308
|
+
_commandFinally(state, this);
|
|
1380
1309
|
}
|
|
1381
1310
|
}
|
|
1382
1311
|
async fill(selectors, value, enter = false, _params = null, options = {}, world = null) {
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1312
|
+
const state = {
|
|
1313
|
+
selectors,
|
|
1314
|
+
_params,
|
|
1315
|
+
value: unEscapeString(value),
|
|
1316
|
+
options,
|
|
1317
|
+
world,
|
|
1318
|
+
type: Types.FILL,
|
|
1319
|
+
text: `Fill input with value: ${value}`,
|
|
1320
|
+
operation: "fill",
|
|
1321
|
+
log: "***** fill on " + selectors.element_name + " with value " + value + "*****\n",
|
|
1322
|
+
};
|
|
1394
1323
|
try {
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
await
|
|
1398
|
-
await element.fill(value);
|
|
1399
|
-
await element.dispatchEvent("change");
|
|
1324
|
+
await _preCommand(state, this);
|
|
1325
|
+
await state.element.fill(value);
|
|
1326
|
+
await state.element.dispatchEvent("change");
|
|
1400
1327
|
if (enter) {
|
|
1401
1328
|
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
1402
1329
|
await this.page.keyboard.press("Enter");
|
|
1403
1330
|
}
|
|
1404
1331
|
await this.waitForPageLoad();
|
|
1405
|
-
return info;
|
|
1332
|
+
return state.info;
|
|
1406
1333
|
}
|
|
1407
|
-
catch (e) {
|
|
1408
|
-
|
|
1409
|
-
this.logger.error("fill failed " + info.log);
|
|
1410
|
-
({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
|
|
1411
|
-
info.screenshotPath = screenshotPath;
|
|
1412
|
-
Object.assign(e, { info: info });
|
|
1413
|
-
error = e;
|
|
1414
|
-
throw e;
|
|
1334
|
+
catch (e) {
|
|
1335
|
+
await _commandError(state, e, this);
|
|
1415
1336
|
}
|
|
1416
1337
|
finally {
|
|
1417
|
-
|
|
1418
|
-
this._reportToWorld(world, {
|
|
1419
|
-
element_name: selectors.element_name,
|
|
1420
|
-
type: Types.FILL,
|
|
1421
|
-
screenshotId,
|
|
1422
|
-
value,
|
|
1423
|
-
text: `Fill input with value: ${value}`,
|
|
1424
|
-
result: error
|
|
1425
|
-
? {
|
|
1426
|
-
status: "FAILED",
|
|
1427
|
-
startTime,
|
|
1428
|
-
endTime,
|
|
1429
|
-
message: error === null || error === void 0 ? void 0 : error.message,
|
|
1430
|
-
}
|
|
1431
|
-
: {
|
|
1432
|
-
status: "PASSED",
|
|
1433
|
-
startTime,
|
|
1434
|
-
endTime,
|
|
1435
|
-
},
|
|
1436
|
-
info: info,
|
|
1437
|
-
});
|
|
1338
|
+
_commandFinally(state, this);
|
|
1438
1339
|
}
|
|
1439
1340
|
}
|
|
1440
1341
|
async getText(selectors, _params = null, options = {}, info = {}, world = null) {
|
|
1441
1342
|
return await this._getText(selectors, 0, _params, options, info, world);
|
|
1442
1343
|
}
|
|
1443
1344
|
async _getText(selectors, climb, _params = null, options = {}, info = {}, world = null) {
|
|
1444
|
-
|
|
1345
|
+
_validateSelectors(selectors);
|
|
1445
1346
|
let screenshotId = null;
|
|
1446
1347
|
let screenshotPath = null;
|
|
1447
1348
|
if (!info.log) {
|
|
@@ -1485,166 +1386,124 @@ class StableBrowser {
|
|
|
1485
1386
|
}
|
|
1486
1387
|
}
|
|
1487
1388
|
async containsPattern(selectors, pattern, text, _params = null, options = {}, world = null) {
|
|
1488
|
-
var _a;
|
|
1489
|
-
this._validateSelectors(selectors);
|
|
1490
1389
|
if (!pattern) {
|
|
1491
1390
|
throw new Error("pattern is null");
|
|
1492
1391
|
}
|
|
1493
1392
|
if (!text) {
|
|
1494
1393
|
throw new Error("text is null");
|
|
1495
1394
|
}
|
|
1395
|
+
const state = {
|
|
1396
|
+
selectors,
|
|
1397
|
+
_params,
|
|
1398
|
+
pattern,
|
|
1399
|
+
value: pattern,
|
|
1400
|
+
options,
|
|
1401
|
+
world,
|
|
1402
|
+
locate: false,
|
|
1403
|
+
scroll: false,
|
|
1404
|
+
screenshot: false,
|
|
1405
|
+
highlight: false,
|
|
1406
|
+
type: Types.VERIFY_ELEMENT_CONTAINS_TEXT,
|
|
1407
|
+
text: `Verify element contains pattern: ${pattern}`,
|
|
1408
|
+
operation: "containsPattern",
|
|
1409
|
+
log: "***** verify element " + selectors.element_name + " contains pattern " + pattern + " *****\n",
|
|
1410
|
+
};
|
|
1496
1411
|
const newValue = await this._replaceWithLocalData(text, world);
|
|
1497
1412
|
if (newValue !== text) {
|
|
1498
1413
|
this.logger.info(text + "=" + newValue);
|
|
1499
1414
|
text = newValue;
|
|
1500
1415
|
}
|
|
1501
|
-
const startTime = Date.now();
|
|
1502
|
-
let error = null;
|
|
1503
|
-
let screenshotId = null;
|
|
1504
|
-
let screenshotPath = null;
|
|
1505
|
-
const info = {};
|
|
1506
|
-
info.log =
|
|
1507
|
-
"***** verify element " + selectors.element_name + " contains pattern " + pattern + "/" + text + " *****\n";
|
|
1508
|
-
info.operation = "containsPattern";
|
|
1509
|
-
info.selectors = selectors;
|
|
1510
|
-
info.value = text;
|
|
1511
|
-
info.pattern = pattern;
|
|
1512
1416
|
let foundObj = null;
|
|
1513
1417
|
try {
|
|
1514
|
-
|
|
1418
|
+
await _preCommand(state, this);
|
|
1419
|
+
state.info.pattern = pattern;
|
|
1420
|
+
foundObj = await this._getText(selectors, 0, _params, options, state.info, world);
|
|
1515
1421
|
if (foundObj && foundObj.element) {
|
|
1516
|
-
await this.scrollIfNeeded(foundObj.element, info);
|
|
1422
|
+
await this.scrollIfNeeded(foundObj.element, state.info);
|
|
1517
1423
|
}
|
|
1518
|
-
|
|
1424
|
+
await _screenshot(state, this);
|
|
1519
1425
|
let escapedText = text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
|
|
1520
1426
|
pattern = pattern.replace("{text}", escapedText);
|
|
1521
1427
|
let regex = new RegExp(pattern, "im");
|
|
1522
|
-
if (!regex.test(foundObj
|
|
1523
|
-
info.foundText = foundObj
|
|
1428
|
+
if (!regex.test(foundObj?.text) && !foundObj?.value?.includes(text)) {
|
|
1429
|
+
state.info.foundText = foundObj?.text;
|
|
1524
1430
|
throw new Error("element doesn't contain text " + text);
|
|
1525
1431
|
}
|
|
1526
|
-
return info;
|
|
1432
|
+
return state.info;
|
|
1527
1433
|
}
|
|
1528
1434
|
catch (e) {
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
this.logger.error("found text " + (foundObj === null || foundObj === void 0 ? void 0 : foundObj.text) + " pattern " + pattern);
|
|
1532
|
-
({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
|
|
1533
|
-
info.screenshotPath = screenshotPath;
|
|
1534
|
-
Object.assign(e, { info: info });
|
|
1535
|
-
error = e;
|
|
1536
|
-
throw e;
|
|
1435
|
+
this.logger.error("found text " + foundObj?.text + " pattern " + pattern);
|
|
1436
|
+
await _commandError(state, e, this);
|
|
1537
1437
|
}
|
|
1538
1438
|
finally {
|
|
1539
|
-
|
|
1540
|
-
this._reportToWorld(world, {
|
|
1541
|
-
element_name: selectors.element_name,
|
|
1542
|
-
type: Types.VERIFY_ELEMENT_CONTAINS_TEXT,
|
|
1543
|
-
value: pattern,
|
|
1544
|
-
text: `Verify element contains pattern: ${pattern}`,
|
|
1545
|
-
screenshotId: foundObj === null || foundObj === void 0 ? void 0 : foundObj.screenshotId,
|
|
1546
|
-
result: error
|
|
1547
|
-
? {
|
|
1548
|
-
status: "FAILED",
|
|
1549
|
-
startTime,
|
|
1550
|
-
endTime,
|
|
1551
|
-
message: error === null || error === void 0 ? void 0 : error.message,
|
|
1552
|
-
}
|
|
1553
|
-
: {
|
|
1554
|
-
status: "PASSED",
|
|
1555
|
-
startTime,
|
|
1556
|
-
endTime,
|
|
1557
|
-
},
|
|
1558
|
-
info: info,
|
|
1559
|
-
});
|
|
1439
|
+
_commandFinally(state, this);
|
|
1560
1440
|
}
|
|
1561
1441
|
}
|
|
1562
1442
|
async containsText(selectors, text, climb, _params = null, options = {}, world = null) {
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1443
|
+
const state = {
|
|
1444
|
+
selectors,
|
|
1445
|
+
_params,
|
|
1446
|
+
value: text,
|
|
1447
|
+
options,
|
|
1448
|
+
world,
|
|
1449
|
+
locate: false,
|
|
1450
|
+
scroll: false,
|
|
1451
|
+
screenshot: false,
|
|
1452
|
+
highlight: false,
|
|
1453
|
+
type: Types.VERIFY_ELEMENT_CONTAINS_TEXT,
|
|
1454
|
+
text: `Verify element contains text: ${text}`,
|
|
1455
|
+
operation: "containsText",
|
|
1456
|
+
log: "***** verify element " + selectors.element_name + " contains text " + text + " *****\n",
|
|
1457
|
+
};
|
|
1566
1458
|
if (!text) {
|
|
1567
1459
|
throw new Error("text is null");
|
|
1568
1460
|
}
|
|
1569
|
-
|
|
1570
|
-
let error = null;
|
|
1571
|
-
let screenshotId = null;
|
|
1572
|
-
let screenshotPath = null;
|
|
1573
|
-
const info = {};
|
|
1574
|
-
info.log = "***** verify element " + selectors.element_name + " contains text " + text + " *****\n";
|
|
1575
|
-
info.operation = "containsText";
|
|
1576
|
-
info.selectors = selectors;
|
|
1461
|
+
text = unEscapeString(text);
|
|
1577
1462
|
const newValue = await this._replaceWithLocalData(text, world);
|
|
1578
1463
|
if (newValue !== text) {
|
|
1579
1464
|
this.logger.info(text + "=" + newValue);
|
|
1580
1465
|
text = newValue;
|
|
1581
1466
|
}
|
|
1582
|
-
info.value = text;
|
|
1583
1467
|
let foundObj = null;
|
|
1584
1468
|
try {
|
|
1585
|
-
|
|
1469
|
+
await _preCommand(state, this);
|
|
1470
|
+
foundObj = await this._getText(selectors, climb, _params, options, state.info, world);
|
|
1586
1471
|
if (foundObj && foundObj.element) {
|
|
1587
|
-
await this.scrollIfNeeded(foundObj.element, info);
|
|
1472
|
+
await this.scrollIfNeeded(foundObj.element, state.info);
|
|
1588
1473
|
}
|
|
1589
|
-
|
|
1474
|
+
await _screenshot(state, this);
|
|
1590
1475
|
const dateAlternatives = findDateAlternatives(text);
|
|
1591
1476
|
const numberAlternatives = findNumberAlternatives(text);
|
|
1592
1477
|
if (dateAlternatives.date) {
|
|
1593
1478
|
for (let i = 0; i < dateAlternatives.dates.length; i++) {
|
|
1594
|
-
if (
|
|
1595
|
-
|
|
1596
|
-
return info;
|
|
1479
|
+
if (foundObj?.text.includes(dateAlternatives.dates[i]) ||
|
|
1480
|
+
foundObj?.value?.includes(dateAlternatives.dates[i])) {
|
|
1481
|
+
return state.info;
|
|
1597
1482
|
}
|
|
1598
1483
|
}
|
|
1599
1484
|
throw new Error("element doesn't contain text " + text);
|
|
1600
1485
|
}
|
|
1601
1486
|
else if (numberAlternatives.number) {
|
|
1602
1487
|
for (let i = 0; i < numberAlternatives.numbers.length; i++) {
|
|
1603
|
-
if (
|
|
1604
|
-
|
|
1605
|
-
return info;
|
|
1488
|
+
if (foundObj?.text.includes(numberAlternatives.numbers[i]) ||
|
|
1489
|
+
foundObj?.value?.includes(numberAlternatives.numbers[i])) {
|
|
1490
|
+
return state.info;
|
|
1606
1491
|
}
|
|
1607
1492
|
}
|
|
1608
1493
|
throw new Error("element doesn't contain text " + text);
|
|
1609
1494
|
}
|
|
1610
|
-
else if (!
|
|
1611
|
-
info.foundText = foundObj
|
|
1612
|
-
info.value = foundObj
|
|
1495
|
+
else if (!foundObj?.text.includes(text) && !foundObj?.value?.includes(text)) {
|
|
1496
|
+
state.info.foundText = foundObj?.text;
|
|
1497
|
+
state.info.value = foundObj?.value;
|
|
1613
1498
|
throw new Error("element doesn't contain text " + text);
|
|
1614
1499
|
}
|
|
1615
|
-
return info;
|
|
1500
|
+
return state.info;
|
|
1616
1501
|
}
|
|
1617
1502
|
catch (e) {
|
|
1618
|
-
|
|
1619
|
-
this.logger.error("verify element contains text failed " + info.log);
|
|
1620
|
-
({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
|
|
1621
|
-
info.screenshotPath = screenshotPath;
|
|
1622
|
-
Object.assign(e, { info: info });
|
|
1623
|
-
error = e;
|
|
1624
|
-
throw e;
|
|
1503
|
+
await _commandError(state, e, this);
|
|
1625
1504
|
}
|
|
1626
1505
|
finally {
|
|
1627
|
-
|
|
1628
|
-
this._reportToWorld(world, {
|
|
1629
|
-
element_name: selectors.element_name,
|
|
1630
|
-
type: Types.VERIFY_ELEMENT_CONTAINS_TEXT,
|
|
1631
|
-
text: `Verify element contains text: ${text}`,
|
|
1632
|
-
value: text,
|
|
1633
|
-
screenshotId: foundObj === null || foundObj === void 0 ? void 0 : foundObj.screenshotId,
|
|
1634
|
-
result: error
|
|
1635
|
-
? {
|
|
1636
|
-
status: "FAILED",
|
|
1637
|
-
startTime,
|
|
1638
|
-
endTime,
|
|
1639
|
-
message: error === null || error === void 0 ? void 0 : error.message,
|
|
1640
|
-
}
|
|
1641
|
-
: {
|
|
1642
|
-
status: "PASSED",
|
|
1643
|
-
startTime,
|
|
1644
|
-
endTime,
|
|
1645
|
-
},
|
|
1646
|
-
info: info,
|
|
1647
|
-
});
|
|
1506
|
+
_commandFinally(state, this);
|
|
1648
1507
|
}
|
|
1649
1508
|
}
|
|
1650
1509
|
_getDataFile(world = null) {
|
|
@@ -1918,127 +1777,69 @@ class StableBrowser {
|
|
|
1918
1777
|
}
|
|
1919
1778
|
}
|
|
1920
1779
|
async verifyElementExistInPage(selectors, _params = null, options = {}, world = null) {
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1780
|
+
const state = {
|
|
1781
|
+
selectors,
|
|
1782
|
+
_params,
|
|
1783
|
+
options,
|
|
1784
|
+
world,
|
|
1785
|
+
type: Types.VERIFY_ELEMENT_CONTAINS_TEXT,
|
|
1786
|
+
text: `Verify element exists in page`,
|
|
1787
|
+
operation: "verifyElementExistInPage",
|
|
1788
|
+
log: "***** verify element " + selectors.element_name + " exists in page *****\n",
|
|
1789
|
+
};
|
|
1926
1790
|
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
1927
|
-
const info = {};
|
|
1928
|
-
info.log = "***** verify element " + selectors.element_name + " exists in page *****\n";
|
|
1929
|
-
info.operation = "verify";
|
|
1930
|
-
info.selectors = selectors;
|
|
1931
1791
|
try {
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
}
|
|
1936
|
-
await this._highlightElements(element);
|
|
1937
|
-
({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
|
|
1938
|
-
await expect(element).toHaveCount(1, { timeout: 10000 });
|
|
1939
|
-
return info;
|
|
1792
|
+
await _preCommand(state, this);
|
|
1793
|
+
await expect(state.element).toHaveCount(1, { timeout: 10000 });
|
|
1794
|
+
return state.info;
|
|
1940
1795
|
}
|
|
1941
1796
|
catch (e) {
|
|
1942
|
-
|
|
1943
|
-
this.logger.error("verify failed " + info.log);
|
|
1944
|
-
({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
|
|
1945
|
-
info.screenshotPath = screenshotPath;
|
|
1946
|
-
Object.assign(e, { info: info });
|
|
1947
|
-
error = e;
|
|
1948
|
-
throw e;
|
|
1797
|
+
await _commandError(state, e, this);
|
|
1949
1798
|
}
|
|
1950
1799
|
finally {
|
|
1951
|
-
|
|
1952
|
-
this._reportToWorld(world, {
|
|
1953
|
-
element_name: selectors.element_name,
|
|
1954
|
-
type: Types.VERIFY_ELEMENT_CONTAINS_TEXT,
|
|
1955
|
-
text: "Verify element exists in page",
|
|
1956
|
-
screenshotId,
|
|
1957
|
-
result: error
|
|
1958
|
-
? {
|
|
1959
|
-
status: "FAILED",
|
|
1960
|
-
startTime,
|
|
1961
|
-
endTime,
|
|
1962
|
-
message: error === null || error === void 0 ? void 0 : error.message,
|
|
1963
|
-
}
|
|
1964
|
-
: {
|
|
1965
|
-
status: "PASSED",
|
|
1966
|
-
startTime,
|
|
1967
|
-
endTime,
|
|
1968
|
-
},
|
|
1969
|
-
info: info,
|
|
1970
|
-
});
|
|
1800
|
+
_commandFinally(state, this);
|
|
1971
1801
|
}
|
|
1972
1802
|
}
|
|
1973
1803
|
async extractAttribute(selectors, attribute, variable, _params = null, options = {}, world = null) {
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1804
|
+
const state = {
|
|
1805
|
+
selectors,
|
|
1806
|
+
_params,
|
|
1807
|
+
attribute,
|
|
1808
|
+
variable,
|
|
1809
|
+
options,
|
|
1810
|
+
world,
|
|
1811
|
+
type: Types.EXTRACT,
|
|
1812
|
+
text: `Extract attribute from element`,
|
|
1813
|
+
operation: "extractAttribute",
|
|
1814
|
+
log: "***** extract attribute " + attribute + " from " + selectors.element_name + " *****\n",
|
|
1815
|
+
};
|
|
1979
1816
|
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
1980
|
-
const info = {};
|
|
1981
|
-
info.log = "***** extract attribute " + attribute + " from " + selectors.element_name + " *****\n";
|
|
1982
|
-
info.operation = "extract";
|
|
1983
|
-
info.selectors = selectors;
|
|
1984
1817
|
try {
|
|
1985
|
-
|
|
1986
|
-
await this._highlightElements(element);
|
|
1987
|
-
({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
|
|
1818
|
+
await _preCommand(state, this);
|
|
1988
1819
|
switch (attribute) {
|
|
1989
1820
|
case "inner_text":
|
|
1990
|
-
|
|
1821
|
+
state.value = await state.element.innerText();
|
|
1991
1822
|
break;
|
|
1992
1823
|
case "href":
|
|
1993
|
-
|
|
1824
|
+
state.value = await state.element.getAttribute("href");
|
|
1994
1825
|
break;
|
|
1995
1826
|
case "value":
|
|
1996
|
-
|
|
1827
|
+
state.value = await state.element.inputValue();
|
|
1997
1828
|
break;
|
|
1998
1829
|
default:
|
|
1999
|
-
|
|
1830
|
+
state.value = await state.element.getAttribute(attribute);
|
|
2000
1831
|
break;
|
|
2001
1832
|
}
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
this.setTestData({ [variable]: info.value }, world);
|
|
2007
|
-
this.logger.info("set test data: " + variable + "=" + info.value);
|
|
2008
|
-
return info;
|
|
1833
|
+
state.info.value = state.value;
|
|
1834
|
+
this.setTestData({ [variable]: state.value }, world);
|
|
1835
|
+
this.logger.info("set test data: " + variable + "=" + state.value);
|
|
1836
|
+
return state.info;
|
|
2009
1837
|
}
|
|
2010
1838
|
catch (e) {
|
|
2011
|
-
|
|
2012
|
-
this.logger.error("extract failed " + info.log);
|
|
2013
|
-
({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
|
|
2014
|
-
info.screenshotPath = screenshotPath;
|
|
2015
|
-
Object.assign(e, { info: info });
|
|
2016
|
-
error = e;
|
|
2017
|
-
throw e;
|
|
1839
|
+
await _commandError(state, e, this);
|
|
2018
1840
|
}
|
|
2019
1841
|
finally {
|
|
2020
|
-
|
|
2021
|
-
this._reportToWorld(world, {
|
|
2022
|
-
element_name: selectors.element_name,
|
|
2023
|
-
type: Types.EXTRACT_ATTRIBUTE,
|
|
2024
|
-
variable: variable,
|
|
2025
|
-
value: info.value,
|
|
2026
|
-
text: "Extract attribute from element",
|
|
2027
|
-
screenshotId,
|
|
2028
|
-
result: error
|
|
2029
|
-
? {
|
|
2030
|
-
status: "FAILED",
|
|
2031
|
-
startTime,
|
|
2032
|
-
endTime,
|
|
2033
|
-
message: error === null || error === void 0 ? void 0 : error.message,
|
|
2034
|
-
}
|
|
2035
|
-
: {
|
|
2036
|
-
status: "PASSED",
|
|
2037
|
-
startTime,
|
|
2038
|
-
endTime,
|
|
2039
|
-
},
|
|
2040
|
-
info: info,
|
|
2041
|
-
});
|
|
1842
|
+
_commandFinally(state, this);
|
|
2042
1843
|
}
|
|
2043
1844
|
}
|
|
2044
1845
|
async extractEmailData(emailAddress, options, world) {
|
|
@@ -2115,7 +1916,8 @@ class StableBrowser {
|
|
|
2115
1916
|
catch (e) {
|
|
2116
1917
|
errorCount++;
|
|
2117
1918
|
if (errorCount > 3) {
|
|
2118
|
-
throw e;
|
|
1919
|
+
// throw e;
|
|
1920
|
+
await _commandError({ text: "extractEmailData", operation: "extractEmailData", emailAddress, info: {} }, e, this);
|
|
2119
1921
|
}
|
|
2120
1922
|
// ignore
|
|
2121
1923
|
}
|
|
@@ -2226,11 +2028,12 @@ class StableBrowser {
|
|
|
2226
2028
|
info.screenshotPath = screenshotPath;
|
|
2227
2029
|
Object.assign(e, { info: info });
|
|
2228
2030
|
error = e;
|
|
2229
|
-
throw e;
|
|
2031
|
+
// throw e;
|
|
2032
|
+
await _commandError({ text: "verifyPagePath", operation: "verifyPagePath", pathPart, info }, e, this);
|
|
2230
2033
|
}
|
|
2231
2034
|
finally {
|
|
2232
2035
|
const endTime = Date.now();
|
|
2233
|
-
|
|
2036
|
+
_reportToWorld(world, {
|
|
2234
2037
|
type: Types.VERIFY_PAGE_PATH,
|
|
2235
2038
|
text: "Verify page path",
|
|
2236
2039
|
screenshotId,
|
|
@@ -2239,7 +2042,7 @@ class StableBrowser {
|
|
|
2239
2042
|
status: "FAILED",
|
|
2240
2043
|
startTime,
|
|
2241
2044
|
endTime,
|
|
2242
|
-
message: error
|
|
2045
|
+
message: error?.message,
|
|
2243
2046
|
}
|
|
2244
2047
|
: {
|
|
2245
2048
|
status: "PASSED",
|
|
@@ -2252,52 +2055,58 @@ class StableBrowser {
|
|
|
2252
2055
|
}
|
|
2253
2056
|
async verifyTextExistInPage(text, options = {}, world = null) {
|
|
2254
2057
|
text = unEscapeString(text);
|
|
2255
|
-
const
|
|
2058
|
+
const state = {
|
|
2059
|
+
text_search: text,
|
|
2060
|
+
options,
|
|
2061
|
+
world,
|
|
2062
|
+
locate: false,
|
|
2063
|
+
scroll: false,
|
|
2064
|
+
highlight: false,
|
|
2065
|
+
type: Types.VERIFY_ELEMENT_CONTAINS_TEXT,
|
|
2066
|
+
text: `Verify text exists in page`,
|
|
2067
|
+
operation: "verifyTextExistInPage",
|
|
2068
|
+
log: "***** verify text " + text + " exists in page *****\n",
|
|
2069
|
+
};
|
|
2256
2070
|
const timeout = this._getLoadTimeout(options);
|
|
2257
|
-
let error = null;
|
|
2258
|
-
let screenshotId = null;
|
|
2259
|
-
let screenshotPath = null;
|
|
2260
2071
|
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
2261
|
-
const info = {};
|
|
2262
|
-
info.log = "***** verify text " + text + " exists in page *****\n";
|
|
2263
|
-
info.operation = "verifyTextExistInPage";
|
|
2264
2072
|
const newValue = await this._replaceWithLocalData(text, world);
|
|
2265
2073
|
if (newValue !== text) {
|
|
2266
2074
|
this.logger.info(text + "=" + newValue);
|
|
2267
2075
|
text = newValue;
|
|
2268
2076
|
}
|
|
2269
|
-
info.text = text;
|
|
2270
2077
|
let dateAlternatives = findDateAlternatives(text);
|
|
2271
2078
|
let numberAlternatives = findNumberAlternatives(text);
|
|
2272
2079
|
try {
|
|
2080
|
+
await _preCommand(state, this);
|
|
2081
|
+
state.info.text = text;
|
|
2273
2082
|
while (true) {
|
|
2274
2083
|
const frames = this.page.frames();
|
|
2275
2084
|
let results = [];
|
|
2276
2085
|
for (let i = 0; i < frames.length; i++) {
|
|
2277
2086
|
if (dateAlternatives.date) {
|
|
2278
2087
|
for (let j = 0; j < dateAlternatives.dates.length; j++) {
|
|
2279
|
-
const result = await this._locateElementByText(frames[i], dateAlternatives.dates[j], "
|
|
2088
|
+
const result = await this._locateElementByText(frames[i], dateAlternatives.dates[j], "*:not(script, style, head)", true, true, {});
|
|
2280
2089
|
result.frame = frames[i];
|
|
2281
2090
|
results.push(result);
|
|
2282
2091
|
}
|
|
2283
2092
|
}
|
|
2284
2093
|
else if (numberAlternatives.number) {
|
|
2285
2094
|
for (let j = 0; j < numberAlternatives.numbers.length; j++) {
|
|
2286
|
-
const result = await this._locateElementByText(frames[i], numberAlternatives.numbers[j], "
|
|
2095
|
+
const result = await this._locateElementByText(frames[i], numberAlternatives.numbers[j], "*:not(script, style, head)", true, true, {});
|
|
2287
2096
|
result.frame = frames[i];
|
|
2288
2097
|
results.push(result);
|
|
2289
2098
|
}
|
|
2290
2099
|
}
|
|
2291
2100
|
else {
|
|
2292
|
-
const result = await this._locateElementByText(frames[i], text, "
|
|
2101
|
+
const result = await this._locateElementByText(frames[i], text, "*:not(script, style, head)", true, true, {});
|
|
2293
2102
|
result.frame = frames[i];
|
|
2294
2103
|
results.push(result);
|
|
2295
2104
|
}
|
|
2296
2105
|
}
|
|
2297
|
-
info.results = results;
|
|
2106
|
+
state.info.results = results;
|
|
2298
2107
|
const resultWithElementsFound = results.filter((result) => result.elementCount > 0);
|
|
2299
2108
|
if (resultWithElementsFound.length === 0) {
|
|
2300
|
-
if (Date.now() - startTime > timeout) {
|
|
2109
|
+
if (Date.now() - state.startTime > timeout) {
|
|
2301
2110
|
throw new Error(`Text ${text} not found in page`);
|
|
2302
2111
|
}
|
|
2303
2112
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
@@ -2309,44 +2118,89 @@ class StableBrowser {
|
|
|
2309
2118
|
await this._highlightElements(frame, dataAttribute);
|
|
2310
2119
|
const element = await frame.$(dataAttribute);
|
|
2311
2120
|
if (element) {
|
|
2312
|
-
await this.scrollIfNeeded(element, info);
|
|
2121
|
+
await this.scrollIfNeeded(element, state.info);
|
|
2313
2122
|
await element.dispatchEvent("bvt_verify_page_contains_text");
|
|
2314
2123
|
}
|
|
2315
2124
|
}
|
|
2316
|
-
|
|
2317
|
-
return info;
|
|
2125
|
+
await _screenshot(state, this);
|
|
2126
|
+
return state.info;
|
|
2318
2127
|
}
|
|
2319
2128
|
// await expect(element).toHaveCount(1, { timeout: 10000 });
|
|
2320
2129
|
}
|
|
2321
2130
|
catch (e) {
|
|
2322
|
-
|
|
2323
|
-
this.logger.error("verify text exist in page failed " + info.log);
|
|
2324
|
-
({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
|
|
2325
|
-
info.screenshotPath = screenshotPath;
|
|
2326
|
-
Object.assign(e, { info: info });
|
|
2327
|
-
error = e;
|
|
2328
|
-
throw e;
|
|
2131
|
+
await _commandError(state, e, this);
|
|
2329
2132
|
}
|
|
2330
2133
|
finally {
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2134
|
+
_commandFinally(state, this);
|
|
2135
|
+
}
|
|
2136
|
+
}
|
|
2137
|
+
async waitForTextToDisappear(text, options = {}, world = null) {
|
|
2138
|
+
text = unEscapeString(text);
|
|
2139
|
+
const state = {
|
|
2140
|
+
text_search: text,
|
|
2141
|
+
options,
|
|
2142
|
+
world,
|
|
2143
|
+
locate: false,
|
|
2144
|
+
scroll: false,
|
|
2145
|
+
highlight: false,
|
|
2146
|
+
type: Types.WAIT_FOR_TEXT_TO_DISAPPEAR,
|
|
2147
|
+
text: `Verify text does not exist in page`,
|
|
2148
|
+
operation: "verifyTextNotExistInPage",
|
|
2149
|
+
log: "***** verify text " + text + " does not exist in page *****\n",
|
|
2150
|
+
};
|
|
2151
|
+
const timeout = this._getLoadTimeout(options);
|
|
2152
|
+
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
2153
|
+
const newValue = await this._replaceWithLocalData(text, world);
|
|
2154
|
+
if (newValue !== text) {
|
|
2155
|
+
this.logger.info(text + "=" + newValue);
|
|
2156
|
+
text = newValue;
|
|
2157
|
+
}
|
|
2158
|
+
let dateAlternatives = findDateAlternatives(text);
|
|
2159
|
+
let numberAlternatives = findNumberAlternatives(text);
|
|
2160
|
+
try {
|
|
2161
|
+
await _preCommand(state, this);
|
|
2162
|
+
state.info.text = text;
|
|
2163
|
+
while (true) {
|
|
2164
|
+
const frames = this.page.frames();
|
|
2165
|
+
let results = [];
|
|
2166
|
+
for (let i = 0; i < frames.length; i++) {
|
|
2167
|
+
if (dateAlternatives.date) {
|
|
2168
|
+
for (let j = 0; j < dateAlternatives.dates.length; j++) {
|
|
2169
|
+
const result = await this._locateElementByText(frames[i], dateAlternatives.dates[j], "*:not(script, style, head)", true, true, {});
|
|
2170
|
+
result.frame = frames[i];
|
|
2171
|
+
results.push(result);
|
|
2172
|
+
}
|
|
2342
2173
|
}
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2174
|
+
else if (numberAlternatives.number) {
|
|
2175
|
+
for (let j = 0; j < numberAlternatives.numbers.length; j++) {
|
|
2176
|
+
const result = await this._locateElementByText(frames[i], numberAlternatives.numbers[j], "*:not(script, style, head)", true, true, {});
|
|
2177
|
+
result.frame = frames[i];
|
|
2178
|
+
results.push(result);
|
|
2179
|
+
}
|
|
2180
|
+
}
|
|
2181
|
+
else {
|
|
2182
|
+
const result = await this._locateElementByText(frames[i], text, "*:not(script, style, head)", true, true, {});
|
|
2183
|
+
result.frame = frames[i];
|
|
2184
|
+
results.push(result);
|
|
2185
|
+
}
|
|
2186
|
+
}
|
|
2187
|
+
state.info.results = results;
|
|
2188
|
+
const resultWithElementsFound = results.filter((result) => result.elementCount > 0);
|
|
2189
|
+
if (resultWithElementsFound.length === 0) {
|
|
2190
|
+
await _screenshot(state, this);
|
|
2191
|
+
return state.info;
|
|
2192
|
+
}
|
|
2193
|
+
if (Date.now() - state.startTime > timeout) {
|
|
2194
|
+
throw new Error(`Text ${text} found in page`);
|
|
2195
|
+
}
|
|
2196
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
2197
|
+
}
|
|
2198
|
+
}
|
|
2199
|
+
catch (e) {
|
|
2200
|
+
await _commandError(state, e, this);
|
|
2201
|
+
}
|
|
2202
|
+
finally {
|
|
2203
|
+
_commandFinally(state, this);
|
|
2350
2204
|
}
|
|
2351
2205
|
}
|
|
2352
2206
|
_getServerUrl() {
|
|
@@ -2409,11 +2263,12 @@ class StableBrowser {
|
|
|
2409
2263
|
info.screenshotPath = screenshotPath;
|
|
2410
2264
|
Object.assign(e, { info: info });
|
|
2411
2265
|
error = e;
|
|
2412
|
-
throw e;
|
|
2266
|
+
// throw e;
|
|
2267
|
+
await _commandError({ text: "visualVerification", operation: "visualVerification", text, info }, e, this);
|
|
2413
2268
|
}
|
|
2414
2269
|
finally {
|
|
2415
2270
|
const endTime = Date.now();
|
|
2416
|
-
|
|
2271
|
+
_reportToWorld(world, {
|
|
2417
2272
|
type: Types.VERIFY_VISUAL,
|
|
2418
2273
|
text: "Visual verification",
|
|
2419
2274
|
screenshotId,
|
|
@@ -2422,7 +2277,7 @@ class StableBrowser {
|
|
|
2422
2277
|
status: "FAILED",
|
|
2423
2278
|
startTime,
|
|
2424
2279
|
endTime,
|
|
2425
|
-
message: error
|
|
2280
|
+
message: error?.message,
|
|
2426
2281
|
}
|
|
2427
2282
|
: {
|
|
2428
2283
|
status: "PASSED",
|
|
@@ -2454,7 +2309,7 @@ class StableBrowser {
|
|
|
2454
2309
|
this.logger.info("Table data verified");
|
|
2455
2310
|
}
|
|
2456
2311
|
async getTableData(selectors, _params = null, options = {}, world = null) {
|
|
2457
|
-
|
|
2312
|
+
_validateSelectors(selectors);
|
|
2458
2313
|
const startTime = Date.now();
|
|
2459
2314
|
let error = null;
|
|
2460
2315
|
let screenshotId = null;
|
|
@@ -2476,11 +2331,12 @@ class StableBrowser {
|
|
|
2476
2331
|
info.screenshotPath = screenshotPath;
|
|
2477
2332
|
Object.assign(e, { info: info });
|
|
2478
2333
|
error = e;
|
|
2479
|
-
throw e;
|
|
2334
|
+
// throw e;
|
|
2335
|
+
await _commandError({ text: "getTableData", operation: "getTableData", selectors, info }, e, this);
|
|
2480
2336
|
}
|
|
2481
2337
|
finally {
|
|
2482
2338
|
const endTime = Date.now();
|
|
2483
|
-
|
|
2339
|
+
_reportToWorld(world, {
|
|
2484
2340
|
element_name: selectors.element_name,
|
|
2485
2341
|
type: Types.GET_TABLE_DATA,
|
|
2486
2342
|
text: "Get table data",
|
|
@@ -2490,7 +2346,7 @@ class StableBrowser {
|
|
|
2490
2346
|
status: "FAILED",
|
|
2491
2347
|
startTime,
|
|
2492
2348
|
endTime,
|
|
2493
|
-
message: error
|
|
2349
|
+
message: error?.message,
|
|
2494
2350
|
}
|
|
2495
2351
|
: {
|
|
2496
2352
|
status: "PASSED",
|
|
@@ -2502,7 +2358,7 @@ class StableBrowser {
|
|
|
2502
2358
|
}
|
|
2503
2359
|
}
|
|
2504
2360
|
async analyzeTable(selectors, query, operator, value, _params = null, options = {}, world = null) {
|
|
2505
|
-
|
|
2361
|
+
_validateSelectors(selectors);
|
|
2506
2362
|
if (!query) {
|
|
2507
2363
|
throw new Error("query is null");
|
|
2508
2364
|
}
|
|
@@ -2641,11 +2497,12 @@ class StableBrowser {
|
|
|
2641
2497
|
info.screenshotPath = screenshotPath;
|
|
2642
2498
|
Object.assign(e, { info: info });
|
|
2643
2499
|
error = e;
|
|
2644
|
-
throw e;
|
|
2500
|
+
// throw e;
|
|
2501
|
+
await _commandError({ text: "analyzeTable", operation: "analyzeTable", selectors, query, operator, value }, e, this);
|
|
2645
2502
|
}
|
|
2646
2503
|
finally {
|
|
2647
2504
|
const endTime = Date.now();
|
|
2648
|
-
|
|
2505
|
+
_reportToWorld(world, {
|
|
2649
2506
|
element_name: selectors.element_name,
|
|
2650
2507
|
type: Types.ANALYZE_TABLE,
|
|
2651
2508
|
text: "Analyze table",
|
|
@@ -2655,7 +2512,7 @@ class StableBrowser {
|
|
|
2655
2512
|
status: "FAILED",
|
|
2656
2513
|
startTime,
|
|
2657
2514
|
endTime,
|
|
2658
|
-
message: error
|
|
2515
|
+
message: error?.message,
|
|
2659
2516
|
}
|
|
2660
2517
|
: {
|
|
2661
2518
|
status: "PASSED",
|
|
@@ -2667,27 +2524,7 @@ class StableBrowser {
|
|
|
2667
2524
|
}
|
|
2668
2525
|
}
|
|
2669
2526
|
async _replaceWithLocalData(value, world, _decrypt = true, totpWait = true) {
|
|
2670
|
-
|
|
2671
|
-
return value;
|
|
2672
|
-
}
|
|
2673
|
-
// find all the accurance of {{(.*?)}} and replace with the value
|
|
2674
|
-
let regex = /{{(.*?)}}/g;
|
|
2675
|
-
let matches = value.match(regex);
|
|
2676
|
-
if (matches) {
|
|
2677
|
-
const testData = this.getTestData(world);
|
|
2678
|
-
for (let i = 0; i < matches.length; i++) {
|
|
2679
|
-
let match = matches[i];
|
|
2680
|
-
let key = match.substring(2, match.length - 2);
|
|
2681
|
-
let newValue = objectPath.get(testData, key, null);
|
|
2682
|
-
if (newValue !== null) {
|
|
2683
|
-
value = value.replace(match, newValue);
|
|
2684
|
-
}
|
|
2685
|
-
}
|
|
2686
|
-
}
|
|
2687
|
-
if ((value.startsWith("secret:") || value.startsWith("totp:")) && _decrypt) {
|
|
2688
|
-
return await decrypt(value, null, totpWait);
|
|
2689
|
-
}
|
|
2690
|
-
return value;
|
|
2527
|
+
return await replaceWithLocalTestData(value, world, _decrypt, totpWait, this.context, this);
|
|
2691
2528
|
}
|
|
2692
2529
|
_getLoadTimeout(options) {
|
|
2693
2530
|
let timeout = 15000;
|
|
@@ -2738,7 +2575,7 @@ class StableBrowser {
|
|
|
2738
2575
|
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
2739
2576
|
({ screenshotId, screenshotPath } = await this._screenShot(options, world));
|
|
2740
2577
|
const endTime = Date.now();
|
|
2741
|
-
|
|
2578
|
+
_reportToWorld(world, {
|
|
2742
2579
|
type: Types.GET_PAGE_STATUS,
|
|
2743
2580
|
text: "Wait for page load",
|
|
2744
2581
|
screenshotId,
|
|
@@ -2747,7 +2584,7 @@ class StableBrowser {
|
|
|
2747
2584
|
status: "FAILED",
|
|
2748
2585
|
startTime,
|
|
2749
2586
|
endTime,
|
|
2750
|
-
message: error
|
|
2587
|
+
message: error?.message,
|
|
2751
2588
|
}
|
|
2752
2589
|
: {
|
|
2753
2590
|
status: "PASSED",
|
|
@@ -2758,41 +2595,35 @@ class StableBrowser {
|
|
|
2758
2595
|
}
|
|
2759
2596
|
}
|
|
2760
2597
|
async closePage(options = {}, world = null) {
|
|
2761
|
-
const
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2598
|
+
const state = {
|
|
2599
|
+
options,
|
|
2600
|
+
world,
|
|
2601
|
+
locate: false,
|
|
2602
|
+
scroll: false,
|
|
2603
|
+
highlight: false,
|
|
2604
|
+
type: Types.CLOSE_PAGE,
|
|
2605
|
+
text: `Close page`,
|
|
2606
|
+
operation: "closePage",
|
|
2607
|
+
log: "***** close page *****\n",
|
|
2608
|
+
throwError: false,
|
|
2609
|
+
};
|
|
2766
2610
|
try {
|
|
2611
|
+
await _preCommand(state, this);
|
|
2767
2612
|
await this.page.close();
|
|
2768
2613
|
}
|
|
2769
2614
|
catch (e) {
|
|
2770
2615
|
console.log(".");
|
|
2616
|
+
await _commandError(state, e, this);
|
|
2771
2617
|
}
|
|
2772
2618
|
finally {
|
|
2773
|
-
|
|
2774
|
-
({ screenshotId, screenshotPath } = await this._screenShot(options, world));
|
|
2775
|
-
const endTime = Date.now();
|
|
2776
|
-
this._reportToWorld(world, {
|
|
2777
|
-
type: Types.CLOSE_PAGE,
|
|
2778
|
-
text: "close page",
|
|
2779
|
-
screenshotId,
|
|
2780
|
-
result: error
|
|
2781
|
-
? {
|
|
2782
|
-
status: "FAILED",
|
|
2783
|
-
startTime,
|
|
2784
|
-
endTime,
|
|
2785
|
-
message: error === null || error === void 0 ? void 0 : error.message,
|
|
2786
|
-
}
|
|
2787
|
-
: {
|
|
2788
|
-
status: "PASSED",
|
|
2789
|
-
startTime,
|
|
2790
|
-
endTime,
|
|
2791
|
-
},
|
|
2792
|
-
info: info,
|
|
2793
|
-
});
|
|
2619
|
+
_commandFinally(state, this);
|
|
2794
2620
|
}
|
|
2795
2621
|
}
|
|
2622
|
+
saveTestDataAsGlobal(options, world) {
|
|
2623
|
+
const dataFile = this._getDataFile(world);
|
|
2624
|
+
process.env.GLOBAL_TEST_DATA_FILE = dataFile;
|
|
2625
|
+
this.logger.info("Save the scenario test data as global for the following scenarios.");
|
|
2626
|
+
}
|
|
2796
2627
|
async setViewportSize(width, hight, options = {}, world = null) {
|
|
2797
2628
|
const startTime = Date.now();
|
|
2798
2629
|
let error = null;
|
|
@@ -2810,12 +2641,13 @@ class StableBrowser {
|
|
|
2810
2641
|
}
|
|
2811
2642
|
catch (e) {
|
|
2812
2643
|
console.log(".");
|
|
2644
|
+
await _commandError({ text: "setViewportSize", operation: "setViewportSize", width, hight, info }, e, this);
|
|
2813
2645
|
}
|
|
2814
2646
|
finally {
|
|
2815
2647
|
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
2816
2648
|
({ screenshotId, screenshotPath } = await this._screenShot(options, world));
|
|
2817
2649
|
const endTime = Date.now();
|
|
2818
|
-
|
|
2650
|
+
_reportToWorld(world, {
|
|
2819
2651
|
type: Types.SET_VIEWPORT,
|
|
2820
2652
|
text: "set viewport size to " + width + "x" + hight,
|
|
2821
2653
|
screenshotId,
|
|
@@ -2824,7 +2656,7 @@ class StableBrowser {
|
|
|
2824
2656
|
status: "FAILED",
|
|
2825
2657
|
startTime,
|
|
2826
2658
|
endTime,
|
|
2827
|
-
message: error
|
|
2659
|
+
message: error?.message,
|
|
2828
2660
|
}
|
|
2829
2661
|
: {
|
|
2830
2662
|
status: "PASSED",
|
|
@@ -2846,12 +2678,13 @@ class StableBrowser {
|
|
|
2846
2678
|
}
|
|
2847
2679
|
catch (e) {
|
|
2848
2680
|
console.log(".");
|
|
2681
|
+
await _commandError({ text: "reloadPage", operation: "reloadPage", info }, e, this);
|
|
2849
2682
|
}
|
|
2850
2683
|
finally {
|
|
2851
2684
|
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
2852
2685
|
({ screenshotId, screenshotPath } = await this._screenShot(options, world, info));
|
|
2853
2686
|
const endTime = Date.now();
|
|
2854
|
-
|
|
2687
|
+
_reportToWorld(world, {
|
|
2855
2688
|
type: Types.GET_PAGE_STATUS,
|
|
2856
2689
|
text: "page relaod",
|
|
2857
2690
|
screenshotId,
|
|
@@ -2860,7 +2693,7 @@ class StableBrowser {
|
|
|
2860
2693
|
status: "FAILED",
|
|
2861
2694
|
startTime,
|
|
2862
2695
|
endTime,
|
|
2863
|
-
message: error
|
|
2696
|
+
message: error?.message,
|
|
2864
2697
|
}
|
|
2865
2698
|
: {
|
|
2866
2699
|
status: "PASSED",
|
|
@@ -2887,11 +2720,37 @@ class StableBrowser {
|
|
|
2887
2720
|
console.log("#-#");
|
|
2888
2721
|
}
|
|
2889
2722
|
}
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
|
|
2723
|
+
async beforeStep(world, step) {
|
|
2724
|
+
this.stepName = step.pickleStep.text;
|
|
2725
|
+
this.logger.info("step: " + this.stepName);
|
|
2726
|
+
if (this.stepIndex === undefined) {
|
|
2727
|
+
this.stepIndex = 0;
|
|
2728
|
+
}
|
|
2729
|
+
else {
|
|
2730
|
+
this.stepIndex++;
|
|
2731
|
+
}
|
|
2732
|
+
if (this.context && this.context.browserObject && this.context.browserObject.trace === true) {
|
|
2733
|
+
if (this.context.browserObject.context) {
|
|
2734
|
+
await this.context.browserObject.context.tracing.startChunk({ title: this.stepName });
|
|
2735
|
+
}
|
|
2736
|
+
}
|
|
2737
|
+
if (this.tags === null && step && step.pickle && step.pickle.tags) {
|
|
2738
|
+
this.tags = step.pickle.tags.map((tag) => tag.name);
|
|
2739
|
+
// check if @global_test_data tag is present
|
|
2740
|
+
if (this.tags.includes("@global_test_data")) {
|
|
2741
|
+
this.saveTestDataAsGlobal({}, world);
|
|
2742
|
+
}
|
|
2743
|
+
}
|
|
2744
|
+
}
|
|
2745
|
+
async afterStep(world, step) {
|
|
2746
|
+
this.stepName = null;
|
|
2747
|
+
if (this.context && this.context.browserObject && this.context.browserObject.trace === true) {
|
|
2748
|
+
if (this.context.browserObject.context) {
|
|
2749
|
+
await this.context.browserObject.context.tracing.stopChunk({
|
|
2750
|
+
path: path.join(this.context.browserObject.traceFolder, `trace-${this.stepIndex}.zip`),
|
|
2751
|
+
});
|
|
2752
|
+
}
|
|
2893
2753
|
}
|
|
2894
|
-
world.attach(JSON.stringify(properties), { mediaType: "application/json" });
|
|
2895
2754
|
}
|
|
2896
2755
|
}
|
|
2897
2756
|
function createTimedPromise(promise, label) {
|