automation_model 1.0.724-dev → 1.0.726-dev
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/stable_browser.d.ts +22 -2
- package/lib/stable_browser.js +219 -96
- package/lib/stable_browser.js.map +1 -1
- package/lib/utils.js +62 -59
- package/lib/utils.js.map +1 -1
- package/package.json +1 -1
package/lib/stable_browser.d.ts
CHANGED
|
@@ -17,6 +17,7 @@ export declare const Types: {
|
|
|
17
17
|
ANALYZE_TABLE: string;
|
|
18
18
|
SELECT: string;
|
|
19
19
|
VERIFY_PAGE_PATH: string;
|
|
20
|
+
VERIFY_PAGE_TITLE: string;
|
|
20
21
|
TYPE_PRESS: string;
|
|
21
22
|
PRESS: string;
|
|
22
23
|
HOVER: string;
|
|
@@ -143,8 +144,27 @@ declare class StableBrowser {
|
|
|
143
144
|
emailCode: any;
|
|
144
145
|
}>;
|
|
145
146
|
_highlightElements(scope: any, css: any): Promise<void>;
|
|
146
|
-
|
|
147
|
-
|
|
147
|
+
_matcher(text: any): {
|
|
148
|
+
matcher: any;
|
|
149
|
+
queryText: any;
|
|
150
|
+
};
|
|
151
|
+
_getDomain(url: string): string;
|
|
152
|
+
/**
|
|
153
|
+
* Verify the page path matches the given path.
|
|
154
|
+
* @param {string} pathPart - The path to verify.
|
|
155
|
+
* @param {object} options - Options for verification.
|
|
156
|
+
* @param {object} world - The world context.
|
|
157
|
+
* @returns {Promise<object>} - The state info after verification.
|
|
158
|
+
*/
|
|
159
|
+
verifyPagePath(pathPart: string, options?: object, world?: object): Promise<object>;
|
|
160
|
+
/**
|
|
161
|
+
* Verify the page title matches the given title.
|
|
162
|
+
* @param {string} title - The title to verify.
|
|
163
|
+
* @param {object} options - Options for verification.
|
|
164
|
+
* @param {object} world - The world context.
|
|
165
|
+
* @returns {Promise<object>} - The state info after verification.
|
|
166
|
+
*/
|
|
167
|
+
verifyPageTitle(title: string, options?: object, world?: object): Promise<object>;
|
|
148
168
|
findTextInAllFrames(dateAlternatives: any, numberAlternatives: any, text: any, state: any, partial?: boolean, ignoreCase?: boolean): Promise<{
|
|
149
169
|
elementCount: number;
|
|
150
170
|
randomToken: string;
|
package/lib/stable_browser.js
CHANGED
|
@@ -42,6 +42,7 @@ export const Types = {
|
|
|
42
42
|
ANALYZE_TABLE: "analyze_table",
|
|
43
43
|
SELECT: "select_combobox", //
|
|
44
44
|
VERIFY_PAGE_PATH: "verify_page_path",
|
|
45
|
+
VERIFY_PAGE_TITLE: "verify_page_title",
|
|
45
46
|
TYPE_PRESS: "type_press",
|
|
46
47
|
PRESS: "press_key",
|
|
47
48
|
HOVER: "hover_element",
|
|
@@ -2388,8 +2389,49 @@ class StableBrowser {
|
|
|
2388
2389
|
console.debug(error);
|
|
2389
2390
|
}
|
|
2390
2391
|
}
|
|
2392
|
+
_matcher(text) {
|
|
2393
|
+
if (!text) {
|
|
2394
|
+
return { matcher: "contains", queryText: "" };
|
|
2395
|
+
}
|
|
2396
|
+
if (text.length < 2) {
|
|
2397
|
+
return { matcher: "contains", queryText: text };
|
|
2398
|
+
}
|
|
2399
|
+
const split = text.split(":");
|
|
2400
|
+
const matcher = split[0].toLowerCase();
|
|
2401
|
+
const queryText = split.slice(1).join(":").trim();
|
|
2402
|
+
return { matcher, queryText };
|
|
2403
|
+
}
|
|
2404
|
+
_getDomain(url) {
|
|
2405
|
+
if (url.length === 0 || (!url.startsWith("http://") && !url.startsWith("https://"))) {
|
|
2406
|
+
return "";
|
|
2407
|
+
}
|
|
2408
|
+
let hostnameFragments = url.split("/")[2].split(".");
|
|
2409
|
+
if (hostnameFragments.some((fragment) => fragment.includes(":"))) {
|
|
2410
|
+
return hostnameFragments.join("-").split(":").join("-");
|
|
2411
|
+
}
|
|
2412
|
+
let n = hostnameFragments.length;
|
|
2413
|
+
let fragments = [...hostnameFragments];
|
|
2414
|
+
while (n > 0 && hostnameFragments[n - 1].length <= 3) {
|
|
2415
|
+
hostnameFragments.pop();
|
|
2416
|
+
n = hostnameFragments.length;
|
|
2417
|
+
}
|
|
2418
|
+
if (n == 0) {
|
|
2419
|
+
if (fragments[0] === "www")
|
|
2420
|
+
fragments = fragments.slice(1);
|
|
2421
|
+
return fragments.length > 1 ? fragments.slice(0, fragments.length - 1).join("-") : fragments.join("-");
|
|
2422
|
+
}
|
|
2423
|
+
if (hostnameFragments[0] === "www")
|
|
2424
|
+
hostnameFragments = hostnameFragments.slice(1);
|
|
2425
|
+
return hostnameFragments.join(".");
|
|
2426
|
+
}
|
|
2427
|
+
/**
|
|
2428
|
+
* Verify the page path matches the given path.
|
|
2429
|
+
* @param {string} pathPart - The path to verify.
|
|
2430
|
+
* @param {object} options - Options for verification.
|
|
2431
|
+
* @param {object} world - The world context.
|
|
2432
|
+
* @returns {Promise<object>} - The state info after verification.
|
|
2433
|
+
*/
|
|
2391
2434
|
async verifyPagePath(pathPart, options = {}, world = null) {
|
|
2392
|
-
const startTime = Date.now();
|
|
2393
2435
|
let error = null;
|
|
2394
2436
|
let screenshotId = null;
|
|
2395
2437
|
let screenshotPath = null;
|
|
@@ -2403,113 +2445,212 @@ class StableBrowser {
|
|
|
2403
2445
|
pathPart = newValue;
|
|
2404
2446
|
}
|
|
2405
2447
|
info.pathPart = pathPart;
|
|
2448
|
+
const { matcher, queryText } = this._matcher(pathPart);
|
|
2449
|
+
const state = {
|
|
2450
|
+
text_search: queryText,
|
|
2451
|
+
options,
|
|
2452
|
+
world,
|
|
2453
|
+
locate: false,
|
|
2454
|
+
scroll: false,
|
|
2455
|
+
highlight: false,
|
|
2456
|
+
type: Types.VERIFY_PAGE_PATH,
|
|
2457
|
+
text: `Verify the page url is ${queryText}`,
|
|
2458
|
+
_text: `Verify the page url is ${queryText}`,
|
|
2459
|
+
operation: "verifyPagePath",
|
|
2460
|
+
log: "***** verify page url is " + queryText + " *****\n",
|
|
2461
|
+
};
|
|
2406
2462
|
try {
|
|
2463
|
+
await _preCommand(state, this);
|
|
2464
|
+
state.info.text = queryText;
|
|
2407
2465
|
for (let i = 0; i < 30; i++) {
|
|
2408
2466
|
const url = await this.page.url();
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2467
|
+
switch (matcher) {
|
|
2468
|
+
case "exact":
|
|
2469
|
+
if (url !== queryText) {
|
|
2470
|
+
if (i === 29) {
|
|
2471
|
+
throw new Error(`Page URL ${url} is not equal to ${queryText}`);
|
|
2472
|
+
}
|
|
2473
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
2474
|
+
continue;
|
|
2475
|
+
}
|
|
2476
|
+
break;
|
|
2477
|
+
case "contains":
|
|
2478
|
+
if (!url.includes(queryText)) {
|
|
2479
|
+
if (i === 29) {
|
|
2480
|
+
throw new Error(`Page URL ${url} doesn't contain ${queryText}`);
|
|
2481
|
+
}
|
|
2482
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
2483
|
+
continue;
|
|
2484
|
+
}
|
|
2485
|
+
break;
|
|
2486
|
+
case "starts-with":
|
|
2487
|
+
{
|
|
2488
|
+
const domain = this._getDomain(url);
|
|
2489
|
+
if (domain.length > 0 && domain !== queryText) {
|
|
2490
|
+
if (i === 29) {
|
|
2491
|
+
throw new Error(`Page URL ${url} doesn't start with ${queryText}`);
|
|
2492
|
+
}
|
|
2493
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
2494
|
+
continue;
|
|
2495
|
+
}
|
|
2496
|
+
}
|
|
2497
|
+
break;
|
|
2498
|
+
case "ends-with":
|
|
2499
|
+
{
|
|
2500
|
+
const urlObj = new URL(url);
|
|
2501
|
+
let route = "/";
|
|
2502
|
+
if (urlObj.pathname !== "/") {
|
|
2503
|
+
route = urlObj.pathname.split("/").slice(-1)[0].trim();
|
|
2504
|
+
}
|
|
2505
|
+
else {
|
|
2506
|
+
route = "/";
|
|
2507
|
+
}
|
|
2508
|
+
if (route !== queryText) {
|
|
2509
|
+
if (i === 29) {
|
|
2510
|
+
throw new Error(`Page URL ${url} doesn't end with ${queryText}`);
|
|
2511
|
+
}
|
|
2512
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
2513
|
+
continue;
|
|
2514
|
+
}
|
|
2515
|
+
}
|
|
2516
|
+
break;
|
|
2517
|
+
case "regex":
|
|
2518
|
+
const regex = new RegExp(queryText.slice(1, -1), "g");
|
|
2519
|
+
if (!regex.test(url)) {
|
|
2520
|
+
if (i === 29) {
|
|
2521
|
+
throw new Error(`Page URL ${url} doesn't match regex ${queryText}`);
|
|
2522
|
+
}
|
|
2523
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
2524
|
+
continue;
|
|
2525
|
+
}
|
|
2526
|
+
break;
|
|
2527
|
+
default:
|
|
2528
|
+
console.log("Unknown matching type, defaulting to contains match");
|
|
2529
|
+
if (!url.includes(queryText)) {
|
|
2530
|
+
if (i === 29) {
|
|
2531
|
+
throw new Error(`Page URL ${url} does not contain ${queryText}`);
|
|
2532
|
+
}
|
|
2533
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
2534
|
+
continue;
|
|
2535
|
+
}
|
|
2415
2536
|
}
|
|
2416
|
-
|
|
2417
|
-
return info;
|
|
2537
|
+
await _screenshot(state, this);
|
|
2538
|
+
return state.info;
|
|
2418
2539
|
}
|
|
2419
2540
|
}
|
|
2420
2541
|
catch (e) {
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
info.screenshotPath = screenshotPath;
|
|
2425
|
-
Object.assign(e, { info: info });
|
|
2426
|
-
error = e;
|
|
2427
|
-
// throw e;
|
|
2428
|
-
await _commandError({ text: "verifyPagePath", operation: "verifyPagePath", pathPart, info, throwError: true }, e, this);
|
|
2542
|
+
state.info.failCause.lastError = e.message;
|
|
2543
|
+
state.info.failCause.assertionFailed = true;
|
|
2544
|
+
await _commandError(state, e, this);
|
|
2429
2545
|
}
|
|
2430
2546
|
finally {
|
|
2431
|
-
|
|
2432
|
-
_reportToWorld(world, {
|
|
2433
|
-
type: Types.VERIFY_PAGE_PATH,
|
|
2434
|
-
text: "Verify page path",
|
|
2435
|
-
_text: "Verify the page path contains " + pathPart,
|
|
2436
|
-
screenshotId,
|
|
2437
|
-
result: error
|
|
2438
|
-
? {
|
|
2439
|
-
status: "FAILED",
|
|
2440
|
-
startTime,
|
|
2441
|
-
endTime,
|
|
2442
|
-
message: error?.message,
|
|
2443
|
-
}
|
|
2444
|
-
: {
|
|
2445
|
-
status: "PASSED",
|
|
2446
|
-
startTime,
|
|
2447
|
-
endTime,
|
|
2448
|
-
},
|
|
2449
|
-
info: info,
|
|
2450
|
-
});
|
|
2547
|
+
await _commandFinally(state, this);
|
|
2451
2548
|
}
|
|
2452
2549
|
}
|
|
2550
|
+
/**
|
|
2551
|
+
* Verify the page title matches the given title.
|
|
2552
|
+
* @param {string} title - The title to verify.
|
|
2553
|
+
* @param {object} options - Options for verification.
|
|
2554
|
+
* @param {object} world - The world context.
|
|
2555
|
+
* @returns {Promise<object>} - The state info after verification.
|
|
2556
|
+
*/
|
|
2453
2557
|
async verifyPageTitle(title, options = {}, world = null) {
|
|
2454
|
-
const startTime = Date.now();
|
|
2455
2558
|
let error = null;
|
|
2456
2559
|
let screenshotId = null;
|
|
2457
2560
|
let screenshotPath = null;
|
|
2458
2561
|
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
2459
|
-
const info = {};
|
|
2460
|
-
info.log = "***** verify page title " + title + " *****\n";
|
|
2461
|
-
info.operation = "verifyPageTitle";
|
|
2462
2562
|
const newValue = await this._replaceWithLocalData(title, world);
|
|
2463
2563
|
if (newValue !== title) {
|
|
2464
2564
|
this.logger.info(title + "=" + newValue);
|
|
2465
2565
|
title = newValue;
|
|
2466
2566
|
}
|
|
2467
|
-
|
|
2567
|
+
const { matcher, queryText } = this._matcher(title);
|
|
2568
|
+
const state = {
|
|
2569
|
+
text_search: queryText,
|
|
2570
|
+
options,
|
|
2571
|
+
world,
|
|
2572
|
+
locate: false,
|
|
2573
|
+
scroll: false,
|
|
2574
|
+
highlight: false,
|
|
2575
|
+
type: Types.VERIFY_PAGE_TITLE,
|
|
2576
|
+
text: `Verify the page title is ${queryText}`,
|
|
2577
|
+
_text: `Verify the page title is ${queryText}`,
|
|
2578
|
+
operation: "verifyPageTitle",
|
|
2579
|
+
log: "***** verify page title is " + queryText + " *****\n",
|
|
2580
|
+
};
|
|
2468
2581
|
try {
|
|
2582
|
+
await _preCommand(state, this);
|
|
2583
|
+
state.info.text = queryText;
|
|
2469
2584
|
for (let i = 0; i < 30; i++) {
|
|
2470
2585
|
const foundTitle = await this.page.title();
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2586
|
+
switch (matcher) {
|
|
2587
|
+
case "exact":
|
|
2588
|
+
if (foundTitle !== queryText) {
|
|
2589
|
+
if (i === 29) {
|
|
2590
|
+
throw new Error(`Page Title ${foundTitle} is not equal to ${queryText}`);
|
|
2591
|
+
}
|
|
2592
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
2593
|
+
continue;
|
|
2594
|
+
}
|
|
2595
|
+
break;
|
|
2596
|
+
case "contains":
|
|
2597
|
+
if (!foundTitle.includes(queryText)) {
|
|
2598
|
+
if (i === 29) {
|
|
2599
|
+
throw new Error(`Page Title ${foundTitle} doesn't contain ${queryText}`);
|
|
2600
|
+
}
|
|
2601
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
2602
|
+
continue;
|
|
2603
|
+
}
|
|
2604
|
+
break;
|
|
2605
|
+
case "starts-with":
|
|
2606
|
+
if (!foundTitle.startsWith(queryText)) {
|
|
2607
|
+
if (i === 29) {
|
|
2608
|
+
throw new Error(`Page title ${foundTitle} doesn't start with ${queryText}`);
|
|
2609
|
+
}
|
|
2610
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
2611
|
+
continue;
|
|
2612
|
+
}
|
|
2613
|
+
break;
|
|
2614
|
+
case "ends-with":
|
|
2615
|
+
if (!foundTitle.endsWith(queryText)) {
|
|
2616
|
+
if (i === 29) {
|
|
2617
|
+
throw new Error(`Page Title ${foundTitle} doesn't end with ${queryText}`);
|
|
2618
|
+
}
|
|
2619
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
2620
|
+
continue;
|
|
2621
|
+
}
|
|
2622
|
+
break;
|
|
2623
|
+
case "regex":
|
|
2624
|
+
const regex = new RegExp(queryText.slice(1, -1), "g");
|
|
2625
|
+
if (!regex.test(foundTitle)) {
|
|
2626
|
+
if (i === 29) {
|
|
2627
|
+
throw new Error(`Page Title ${foundTitle} doesn't match regex ${queryText}`);
|
|
2628
|
+
}
|
|
2629
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
2630
|
+
continue;
|
|
2631
|
+
}
|
|
2632
|
+
break;
|
|
2633
|
+
default:
|
|
2634
|
+
console.log("Unknown matching type, defaulting to contains match");
|
|
2635
|
+
if (foundTitle !== queryText) {
|
|
2636
|
+
if (i === 29) {
|
|
2637
|
+
throw new Error(`Page Title ${foundTitle} does not contain ${queryText}`);
|
|
2638
|
+
}
|
|
2639
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
2640
|
+
continue;
|
|
2641
|
+
}
|
|
2477
2642
|
}
|
|
2478
|
-
|
|
2479
|
-
return info;
|
|
2643
|
+
await _screenshot(state, this);
|
|
2644
|
+
return state.info;
|
|
2480
2645
|
}
|
|
2481
2646
|
}
|
|
2482
2647
|
catch (e) {
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
info.screenshotPath = screenshotPath;
|
|
2487
|
-
Object.assign(e, { info: info });
|
|
2488
|
-
error = e;
|
|
2489
|
-
// throw e;
|
|
2490
|
-
await _commandError({ text: "verifyPageTitle", operation: "verifyPageTitle", title, info, throwError: true }, e, this);
|
|
2648
|
+
state.info.failCause.lastError = e.message;
|
|
2649
|
+
state.info.failCause.assertionFailed = true;
|
|
2650
|
+
await _commandError(state, e, this);
|
|
2491
2651
|
}
|
|
2492
2652
|
finally {
|
|
2493
|
-
|
|
2494
|
-
_reportToWorld(world, {
|
|
2495
|
-
type: Types.VERIFY_PAGE_PATH,
|
|
2496
|
-
text: "Verify page title",
|
|
2497
|
-
_text: "Verify the page title contains " + title,
|
|
2498
|
-
screenshotId,
|
|
2499
|
-
result: error
|
|
2500
|
-
? {
|
|
2501
|
-
status: "FAILED",
|
|
2502
|
-
startTime,
|
|
2503
|
-
endTime,
|
|
2504
|
-
message: error?.message,
|
|
2505
|
-
}
|
|
2506
|
-
: {
|
|
2507
|
-
status: "PASSED",
|
|
2508
|
-
startTime,
|
|
2509
|
-
endTime,
|
|
2510
|
-
},
|
|
2511
|
-
info: info,
|
|
2512
|
-
});
|
|
2653
|
+
await _commandFinally(state, this);
|
|
2513
2654
|
}
|
|
2514
2655
|
}
|
|
2515
2656
|
async findTextInAllFrames(dateAlternatives, numberAlternatives, text, state, partial = true, ignoreCase = false) {
|
|
@@ -2593,27 +2734,10 @@ class StableBrowser {
|
|
|
2593
2734
|
const frame = resultWithElementsFound[0].frame;
|
|
2594
2735
|
const dataAttribute = `[data-blinq-id-${resultWithElementsFound[0].randomToken}]`;
|
|
2595
2736
|
await this._highlightElements(frame, dataAttribute);
|
|
2596
|
-
// if (world && world.screenshot && !world.screenshotPath) {
|
|
2597
|
-
// console.log(`Highlighting for verify text is found while running from recorder`);
|
|
2598
|
-
// this._highlightElements(frame, dataAttribute).then(async () => {
|
|
2599
|
-
// await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
2600
|
-
// this._unhighlightElements(frame, dataAttribute)
|
|
2601
|
-
// .then(async () => {
|
|
2602
|
-
// console.log(`Unhighlighted frame dataAttribute successfully`);
|
|
2603
|
-
// })
|
|
2604
|
-
// .catch(
|
|
2605
|
-
// (e) => {}
|
|
2606
|
-
// console.error(e)
|
|
2607
|
-
// );
|
|
2608
|
-
// });
|
|
2609
|
-
// }
|
|
2610
2737
|
const element = await frame.locator(dataAttribute).first();
|
|
2611
|
-
// await new Promise((resolve) => setTimeout(resolve, 100));
|
|
2612
|
-
// await this._unhighlightElements(frame, dataAttribute);
|
|
2613
2738
|
if (element) {
|
|
2614
2739
|
await this.scrollIfNeeded(element, state.info);
|
|
2615
2740
|
await element.dispatchEvent("bvt_verify_page_contains_text");
|
|
2616
|
-
// await _screenshot(state, this, element);
|
|
2617
2741
|
}
|
|
2618
2742
|
}
|
|
2619
2743
|
await _screenshot(state, this);
|
|
@@ -2623,7 +2747,6 @@ class StableBrowser {
|
|
|
2623
2747
|
console.error(error);
|
|
2624
2748
|
}
|
|
2625
2749
|
}
|
|
2626
|
-
// await expect(element).toHaveCount(1, { timeout: 10000 });
|
|
2627
2750
|
}
|
|
2628
2751
|
catch (e) {
|
|
2629
2752
|
await _commandError(state, e, this);
|