automation_model 1.0.486-dev → 1.0.486-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 +2 -1
- package/lib/api.js +95 -98
- package/lib/api.js.map +1 -1
- package/lib/auto_page.d.ts +2 -1
- package/lib/auto_page.js +39 -17
- package/lib/auto_page.js.map +1 -1
- package/lib/browser_manager.d.ts +6 -3
- package/lib/browser_manager.js +110 -16
- package/lib/browser_manager.js.map +1 -1
- package/lib/command_common.d.ts +1 -0
- package/lib/command_common.js +58 -6
- package/lib/command_common.js.map +1 -1
- package/lib/error-messages.d.ts +6 -0
- package/lib/error-messages.js +188 -0
- package/lib/error-messages.js.map +1 -0
- package/lib/generation_scripts.d.ts +4 -0
- package/lib/generation_scripts.js +2 -0
- package/lib/generation_scripts.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 +2 -1
- package/lib/init_browser.js +31 -4
- package/lib/init_browser.js.map +1 -1
- package/lib/locate_element.js +15 -13
- package/lib/locate_element.js.map +1 -1
- package/lib/locator.d.ts +36 -0
- package/lib/locator.js +165 -0
- package/lib/locator.js.map +1 -1
- package/lib/locator_log.d.ts +26 -0
- package/lib/locator_log.js +69 -0
- package/lib/locator_log.js.map +1 -0
- package/lib/network.d.ts +3 -0
- package/lib/network.js +155 -0
- package/lib/network.js.map +1 -0
- package/lib/scripts/find_text.js +126 -0
- package/lib/stable_browser.d.ts +48 -16
- package/lib/stable_browser.js +579 -574
- 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 +1 -0
- package/lib/test_context.js.map +1 -1
- package/lib/utils.d.ts +13 -2
- package/lib/utils.js +238 -5
- package/lib/utils.js.map +1 -1
- package/package.json +7 -5
- /package/lib/{axe → scripts}/axe.mini.js +0 -0
package/lib/network.js
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import path from "path";
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
function _getNetworkFile(world = null, stable = null, context = null) {
|
|
4
|
+
let networkFile = null;
|
|
5
|
+
if (world && world.reportFolder) {
|
|
6
|
+
networkFile = path.join(world.reportFolder, "network.json");
|
|
7
|
+
}
|
|
8
|
+
else if (stable.reportFolder) {
|
|
9
|
+
networkFile = path.join(stable.reportFolder, "network.json");
|
|
10
|
+
}
|
|
11
|
+
else if (context && context.reportFolder) {
|
|
12
|
+
networkFile = path.join(context.reportFolder, "network.json");
|
|
13
|
+
}
|
|
14
|
+
else {
|
|
15
|
+
networkFile = "network.json";
|
|
16
|
+
}
|
|
17
|
+
return networkFile;
|
|
18
|
+
}
|
|
19
|
+
function registerDownloadEvent(page, world, context) {
|
|
20
|
+
if (page) {
|
|
21
|
+
let downloadPath = "./downloads";
|
|
22
|
+
if (world && world.downloadsPath) {
|
|
23
|
+
downloadPath = world.downloadsPath;
|
|
24
|
+
}
|
|
25
|
+
else if (context && context.downloadsPath) {
|
|
26
|
+
downloadPath = context.downloadsPath;
|
|
27
|
+
}
|
|
28
|
+
if (!fs.existsSync(downloadPath)) {
|
|
29
|
+
try {
|
|
30
|
+
fs.mkdirSync(downloadPath);
|
|
31
|
+
}
|
|
32
|
+
catch (e) {
|
|
33
|
+
// ignore
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
page.on("download", async (download) => {
|
|
37
|
+
const suggestedFilename = download.suggestedFilename(); // Get the original file name
|
|
38
|
+
const filePath = `${downloadPath}/${suggestedFilename}`;
|
|
39
|
+
// Save the download with the original name
|
|
40
|
+
await download.saveAs(filePath);
|
|
41
|
+
console.log(`Downloaded file saved as: ${filePath}`);
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function registerNetworkEvents(world, stable, context, page) {
|
|
46
|
+
const networkFile = _getNetworkFile(world, stable, context);
|
|
47
|
+
function saveNetworkData() {
|
|
48
|
+
if (context && context.networkData) {
|
|
49
|
+
fs.writeFileSync(networkFile, JSON.stringify(context.networkData, null, 2), "utf8");
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
if (!context) {
|
|
53
|
+
console.error("No context found to register network events");
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
// Map to hold request start times and IDs
|
|
57
|
+
const requestTimes = new Map();
|
|
58
|
+
let requestIdCounter = 0;
|
|
59
|
+
if (page) {
|
|
60
|
+
if (!context.networkData) {
|
|
61
|
+
context.networkData = [];
|
|
62
|
+
const networkData = context.networkData;
|
|
63
|
+
// Event listener for when a request is made
|
|
64
|
+
page.on("request", (request) => {
|
|
65
|
+
const requestId = requestIdCounter++;
|
|
66
|
+
request.requestId = requestId; // Assign a unique ID to the request
|
|
67
|
+
const startTime = Date.now();
|
|
68
|
+
requestTimes.set(requestId, startTime);
|
|
69
|
+
// Initialize data for this request
|
|
70
|
+
networkData.push({
|
|
71
|
+
requestId,
|
|
72
|
+
requestStart: startTime,
|
|
73
|
+
requestUrl: request.url(),
|
|
74
|
+
method: request.method(),
|
|
75
|
+
status: "Pending",
|
|
76
|
+
responseTime: null,
|
|
77
|
+
responseReceived: null,
|
|
78
|
+
responseEnd: null,
|
|
79
|
+
size: null,
|
|
80
|
+
});
|
|
81
|
+
saveNetworkData();
|
|
82
|
+
});
|
|
83
|
+
// Event listener for when a response is received
|
|
84
|
+
page.on("response", async (response) => {
|
|
85
|
+
const request = response.request();
|
|
86
|
+
const requestId = request.requestId;
|
|
87
|
+
const receivedTime = Date.now();
|
|
88
|
+
// Find the corresponding data object
|
|
89
|
+
const data = networkData.find((item) => item.requestId === requestId);
|
|
90
|
+
if (data) {
|
|
91
|
+
data.status = response.status();
|
|
92
|
+
data.responseReceived = receivedTime;
|
|
93
|
+
saveNetworkData();
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
console.error("No data found for request ID", requestId);
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
// Event listener for when a request is finished
|
|
100
|
+
page.on("requestfinished", async (request) => {
|
|
101
|
+
const requestId = request.requestId;
|
|
102
|
+
const endTime = Date.now();
|
|
103
|
+
const startTime = requestTimes.get(requestId);
|
|
104
|
+
const response = await request.response();
|
|
105
|
+
// Find the corresponding data object
|
|
106
|
+
const data = networkData.find((item) => item.requestId === requestId);
|
|
107
|
+
if (data) {
|
|
108
|
+
data.responseEnd = endTime;
|
|
109
|
+
data.responseTime = endTime - startTime;
|
|
110
|
+
// Get response size
|
|
111
|
+
try {
|
|
112
|
+
const body = await response.body();
|
|
113
|
+
data.size = body.length;
|
|
114
|
+
}
|
|
115
|
+
catch (e) {
|
|
116
|
+
data.size = 0;
|
|
117
|
+
}
|
|
118
|
+
saveNetworkData();
|
|
119
|
+
if (world && world.attach) {
|
|
120
|
+
world.attach(JSON.stringify(data), { mediaType: "application/json+network" });
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
console.error("No data found for request ID", requestId);
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
// Event listener for when a request fails
|
|
128
|
+
page.on("requestfailed", (request) => {
|
|
129
|
+
const requestId = request.requestId;
|
|
130
|
+
const endTime = Date.now();
|
|
131
|
+
const startTime = requestTimes.get(requestId);
|
|
132
|
+
// Find the corresponding data object
|
|
133
|
+
const data = networkData.find((item) => item.requestId === requestId);
|
|
134
|
+
if (data) {
|
|
135
|
+
data.responseEnd = endTime;
|
|
136
|
+
data.responseTime = endTime - startTime;
|
|
137
|
+
data.status = "Failed";
|
|
138
|
+
data.size = 0;
|
|
139
|
+
saveNetworkData();
|
|
140
|
+
if (world && world.attach) {
|
|
141
|
+
world.attach(JSON.stringify(data), { mediaType: "application/json+network" });
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
console.error("No data found for request ID", requestId);
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
console.error("No page found to register network events");
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
export { registerNetworkEvents, registerDownloadEvent };
|
|
155
|
+
//# sourceMappingURL=network.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"network.js","sourceRoot":"","sources":["../../src/network.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Find elements by universal selector and check if they match the provided text pattern.
|
|
3
|
+
*/
|
|
4
|
+
function findMatchingElements(textToMatch, options = {}, root = document) {
|
|
5
|
+
function findLeafElements(elements) {
|
|
6
|
+
const nonLeaf = new Set();
|
|
7
|
+
elements.forEach((el) => {
|
|
8
|
+
elements.forEach((otherEl) => {
|
|
9
|
+
if (el !== otherEl && el.contains(otherEl)) {
|
|
10
|
+
nonLeaf.add(el);
|
|
11
|
+
}
|
|
12
|
+
});
|
|
13
|
+
});
|
|
14
|
+
return elements.filter((el) => !nonLeaf.has(el));
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function escapeRegex(s) {
|
|
18
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
19
|
+
}
|
|
20
|
+
function collectAllShadowDomElements(element, result = []) {
|
|
21
|
+
// Check and add the element if it has a shadow root
|
|
22
|
+
if (element instanceof Element && element.shadowRoot) {
|
|
23
|
+
result.push(element);
|
|
24
|
+
// Also search within the shadow root
|
|
25
|
+
collectAllShadowDomElements(element.shadowRoot, result);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Iterate over child nodes
|
|
29
|
+
element.childNodes.forEach((child) => {
|
|
30
|
+
// Recursively call the function for each child node
|
|
31
|
+
if (child instanceof Element) {
|
|
32
|
+
collectAllShadowDomElements(child, result);
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
return result;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Convert a single snippet into an OR group for:
|
|
40
|
+
* 1) literal text
|
|
41
|
+
* 2) interpreted as a raw regex
|
|
42
|
+
*/
|
|
43
|
+
function snippetToAlternatives(snippet) {
|
|
44
|
+
if (snippet.startsWith("/") && snippet.endsWith("/")) {
|
|
45
|
+
return snippet.slice(1, -1);
|
|
46
|
+
}
|
|
47
|
+
const literalPattern = escapeRegex(snippet);
|
|
48
|
+
return literalPattern;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Build a single RegExp that:
|
|
53
|
+
* - splits the user's text by whitespace
|
|
54
|
+
* - for each token, matches either literal or regex
|
|
55
|
+
* - allows arbitrary whitespace between tokens
|
|
56
|
+
*/
|
|
57
|
+
function buildLooseRegexFromText(text, options) {
|
|
58
|
+
if (options.singleRegex === true) {
|
|
59
|
+
return new RegExp(text, options.ignoreCase === false ? "" : "i");
|
|
60
|
+
}
|
|
61
|
+
const tokens = text.split(/\s+/);
|
|
62
|
+
let pattern = tokens.map((token) => snippetToAlternatives(token)).join("\\s*");
|
|
63
|
+
if (options.exactMatch === true) {
|
|
64
|
+
pattern = `^${pattern}$`;
|
|
65
|
+
}
|
|
66
|
+
// check if one of the tokens end with /i
|
|
67
|
+
const endWithI = tokens.some((token) => token.endsWith("/i"));
|
|
68
|
+
return new RegExp(pattern, endWithI || options.ignoreCase === false ? "" : "i");
|
|
69
|
+
}
|
|
70
|
+
let climb = 0;
|
|
71
|
+
// check if the text to merge end with ^ follow by a number (climb), e.g. "some text^2" we should set the climb and remove the ^2 from the text
|
|
72
|
+
if (textToMatch.match(/\^(\d+)$/)) {
|
|
73
|
+
climb = parseInt(textToMatch.match(/\^(\d+)$/)[1]);
|
|
74
|
+
textToMatch = textToMatch.replace(/\^(\d+)$/, "");
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
let tag = options.tag || "*";
|
|
78
|
+
// Build the pattern
|
|
79
|
+
const regex = buildLooseRegexFromText(textToMatch, options);
|
|
80
|
+
// Query all elements
|
|
81
|
+
let elements = Array.from(root.querySelectorAll(tag));
|
|
82
|
+
|
|
83
|
+
let shadowHosts = [];
|
|
84
|
+
collectAllShadowDomElements(document, shadowHosts);
|
|
85
|
+
for (let i = 0; i < shadowHosts.length; i++) {
|
|
86
|
+
let shadowElement = shadowHosts[i].shadowRoot;
|
|
87
|
+
if (!shadowElement) {
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
let shadowElements = Array.from(shadowElement.querySelectorAll(tag));
|
|
91
|
+
elements = elements.concat(shadowElements);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// filter out elements that are style or script tags
|
|
95
|
+
elements = elements.filter((el) => !["STYLE", "SCRIPT", "HEAD"].includes(el.tagName));
|
|
96
|
+
elements = findLeafElements(
|
|
97
|
+
elements.filter((el) => {
|
|
98
|
+
// Normalize text content
|
|
99
|
+
let normalized = options.innerText === false || !el.innerText ? el.textContent : el.innerText;
|
|
100
|
+
if (!normalized) {
|
|
101
|
+
normalized = "";
|
|
102
|
+
}
|
|
103
|
+
let normalizedSpace = normalized.replace(/\s+/g, " ").trim();
|
|
104
|
+
let normalizedNoSpace = normalized.replace(/\s+/g, "").trim();
|
|
105
|
+
regex.lastIndex = 0; // reset if using 'g'
|
|
106
|
+
return regex.test(normalizedSpace) || regex.test(normalizedNoSpace);
|
|
107
|
+
})
|
|
108
|
+
);
|
|
109
|
+
// if climb is greater than 0, we should climb up the DOM tree for each element
|
|
110
|
+
if (climb > 0) {
|
|
111
|
+
let newElements = [];
|
|
112
|
+
for (let i = 0; i < elements.length; i++) {
|
|
113
|
+
let el = elements[i];
|
|
114
|
+
for (let j = 0; j < climb; j++) {
|
|
115
|
+
if (!el.parentElement) {
|
|
116
|
+
break;
|
|
117
|
+
}
|
|
118
|
+
el = el.parentElement;
|
|
119
|
+
}
|
|
120
|
+
newElements.push(el);
|
|
121
|
+
}
|
|
122
|
+
elements = newElements;
|
|
123
|
+
}
|
|
124
|
+
return elements;
|
|
125
|
+
}
|
|
126
|
+
window.findMatchingElements = findMatchingElements;
|
package/lib/stable_browser.d.ts
CHANGED
|
@@ -1,5 +1,37 @@
|
|
|
1
1
|
import type { Browser, Page } from "playwright";
|
|
2
|
-
|
|
2
|
+
import { Params } from "./utils.js";
|
|
3
|
+
export declare const Types: {
|
|
4
|
+
CLICK: string;
|
|
5
|
+
NAVIGATE: string;
|
|
6
|
+
FILL: string;
|
|
7
|
+
EXECUTE: string;
|
|
8
|
+
OPEN: string;
|
|
9
|
+
COMPLETE: string;
|
|
10
|
+
ASK: string;
|
|
11
|
+
GET_PAGE_STATUS: string;
|
|
12
|
+
CLICK_ROW_ACTION: string;
|
|
13
|
+
VERIFY_ELEMENT_CONTAINS_TEXT: string;
|
|
14
|
+
VERIFY_PAGE_CONTAINS_TEXT: string;
|
|
15
|
+
VERIFY_PAGE_CONTAINS_NO_TEXT: string;
|
|
16
|
+
ANALYZE_TABLE: string;
|
|
17
|
+
SELECT: string;
|
|
18
|
+
VERIFY_PAGE_PATH: string;
|
|
19
|
+
TYPE_PRESS: string;
|
|
20
|
+
PRESS: string;
|
|
21
|
+
HOVER: string;
|
|
22
|
+
CHECK: string;
|
|
23
|
+
UNCHECK: string;
|
|
24
|
+
EXTRACT: string;
|
|
25
|
+
CLOSE_PAGE: string;
|
|
26
|
+
SET_DATE_TIME: string;
|
|
27
|
+
SET_VIEWPORT: string;
|
|
28
|
+
VERIFY_VISUAL: string;
|
|
29
|
+
LOAD_DATA: string;
|
|
30
|
+
SET_INPUT: string;
|
|
31
|
+
WAIT_FOR_TEXT_TO_DISAPPEAR: string;
|
|
32
|
+
VERIFY_ATTRIBUTE: string;
|
|
33
|
+
VERIFY_TEXT_WITH_RELATION: string;
|
|
34
|
+
};
|
|
3
35
|
export declare const apps: {};
|
|
4
36
|
declare class StableBrowser {
|
|
5
37
|
browser: Browser;
|
|
@@ -12,18 +44,13 @@ declare class StableBrowser {
|
|
|
12
44
|
networkLogger: null;
|
|
13
45
|
configuration: null;
|
|
14
46
|
appName: string;
|
|
47
|
+
tags: null;
|
|
15
48
|
constructor(browser: Browser, page: Page, logger?: any, context?: any, world?: any);
|
|
16
49
|
registerEventListeners(context: any): void;
|
|
17
50
|
switchApp(appName: any): Promise<void>;
|
|
18
|
-
_copyContext(from: any, to: any): void;
|
|
19
|
-
getWebLogFile(logFolder: string): string;
|
|
20
51
|
registerConsoleLogListener(page: Page, context: any): void;
|
|
21
52
|
registerRequestListener(page: Page, context: any, logFile: string): void;
|
|
22
53
|
goto(url: string): Promise<void>;
|
|
23
|
-
_fixUsingParams(text: any, _params: Params): any;
|
|
24
|
-
_fixLocatorUsingParams(locator: any, _params: Params): any;
|
|
25
|
-
_isObject(value: any): any;
|
|
26
|
-
scanAndManipulate(currentObj: any, _params: Params): void;
|
|
27
54
|
_getLocator(locator: any, scope: any, _params: any): any;
|
|
28
55
|
_locateElmentByTextClimbCss(scope: any, text: any, climb: any, css: any, _params: Params): Promise<string | undefined>;
|
|
29
56
|
_locateElementByText(scope: any, text1: any, tag1: any, regex1: boolean | undefined, partial1: any, _params: Params): Promise<any>;
|
|
@@ -32,8 +59,8 @@ declare class StableBrowser {
|
|
|
32
59
|
rerun: boolean;
|
|
33
60
|
}>;
|
|
34
61
|
_locate(selectors: any, info: any, _params?: Params, timeout: any): Promise<any>;
|
|
35
|
-
_findFrameScope(selectors: any, timeout
|
|
36
|
-
_getDocumentBody(selectors: any, timeout
|
|
62
|
+
_findFrameScope(selectors: any, timeout: number | undefined, info: any): Promise<any>;
|
|
63
|
+
_getDocumentBody(selectors: any, timeout: number | undefined, info: any): Promise<any>;
|
|
37
64
|
_locate_internal(selectors: any, info: any, _params?: Params, timeout?: number): Promise<any>;
|
|
38
65
|
_scanLocatorsGroup(locatorsGroup: any, scope: any, _params: any, info: any, visibleOnly: any): Promise<{
|
|
39
66
|
foundElements: any[];
|
|
@@ -92,27 +119,32 @@ declare class StableBrowser {
|
|
|
92
119
|
_screenShot(options?: {}, world?: null, info?: null): Promise<{}>;
|
|
93
120
|
takeScreenshot(screenshotPath: any): Promise<any>;
|
|
94
121
|
verifyElementExistInPage(selectors: any, _params?: null, options?: {}, world?: null): Promise<any>;
|
|
95
|
-
extractAttribute(selectors: any, attribute: any, variable: any, _params?: null, options?: {}, world?: null): Promise<
|
|
122
|
+
extractAttribute(selectors: any, attribute: any, variable: any, _params?: null, options?: {}, world?: null): Promise<any>;
|
|
123
|
+
verifyAttribute(selectors: any, attribute: any, value: any, _params?: null, options?: {}, world?: null): Promise<any>;
|
|
96
124
|
extractEmailData(emailAddress: any, options: any, world: any): Promise<{
|
|
97
125
|
emailUrl: any;
|
|
98
126
|
emailCode: any;
|
|
99
127
|
}>;
|
|
100
128
|
_highlightElements(scope: any, css: any): Promise<void>;
|
|
101
129
|
verifyPagePath(pathPart: any, options?: {}, world?: null): Promise<{} | undefined>;
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
130
|
+
findTextInAllFrames(dateAlternatives: any, numberAlternatives: any, text: any, state: any): Promise<any[]>;
|
|
131
|
+
verifyTextExistInPage(text: any, options?: {}, world?: null): Promise<any>;
|
|
132
|
+
waitForTextToDisappear(text: any, options?: {}, world?: null): Promise<any>;
|
|
133
|
+
verifyTextRelatedToText(textAnchor: string, climb: number, textToVerify: string, options?: {}, world?: any): Promise<any>;
|
|
134
|
+
visualVerification(text: any, options?: {}, world?: null): Promise<{} | undefined>;
|
|
105
135
|
verifyTableData(selectors: any, data: any, _params?: null, options?: {}, world?: null): Promise<void>;
|
|
106
136
|
getTableData(selectors: any, _params?: null, options?: {}, world?: null): Promise<any>;
|
|
107
|
-
analyzeTable(selectors: any, query: any, operator: any, value: any, _params?: null, options?: {}, world?: null): Promise<{}>;
|
|
137
|
+
analyzeTable(selectors: any, query: any, operator: any, value: any, _params?: null, options?: {}, world?: null): Promise<{} | undefined>;
|
|
108
138
|
_replaceWithLocalData(value: any, world: any, _decrypt?: boolean, totpWait?: boolean): Promise<string>;
|
|
109
139
|
_getLoadTimeout(options: any): number;
|
|
110
140
|
waitForPageLoad(options?: {}, world?: null): Promise<void>;
|
|
111
141
|
closePage(options?: {}, world?: null): Promise<void>;
|
|
142
|
+
saveTestDataAsGlobal(options: any, world: any): void;
|
|
112
143
|
setViewportSize(width: number, hight: number, options?: {}, world?: null): Promise<void>;
|
|
113
144
|
reloadPage(options?: {}, world?: null): Promise<void>;
|
|
114
145
|
scrollIfNeeded(element: any, info: any): Promise<void>;
|
|
115
|
-
|
|
146
|
+
beforeStep(world: any, step: any): Promise<void>;
|
|
147
|
+
afterStep(world: any, step: any): Promise<void>;
|
|
116
148
|
}
|
|
117
149
|
type JsonTimestamp = number;
|
|
118
150
|
type JsonResultPassed = {
|
|
@@ -127,7 +159,7 @@ type JsonResultFailed = {
|
|
|
127
159
|
message?: string;
|
|
128
160
|
};
|
|
129
161
|
type JsonCommandResult = JsonResultPassed | JsonResultFailed;
|
|
130
|
-
type JsonCommandReport = {
|
|
162
|
+
export type JsonCommandReport = {
|
|
131
163
|
type: string;
|
|
132
164
|
value?: string;
|
|
133
165
|
text: string;
|