automation_model 1.0.418-dev → 1.0.418
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/README.md +130 -0
- package/lib/api.d.ts +43 -1
- package/lib/api.js +228 -41
- package/lib/api.js.map +1 -1
- package/lib/auto_page.d.ts +5 -2
- package/lib/auto_page.js +144 -44
- package/lib/auto_page.js.map +1 -1
- package/lib/browser_manager.d.ts +7 -3
- package/lib/browser_manager.js +153 -48
- package/lib/browser_manager.js.map +1 -1
- package/lib/command_common.d.ts +6 -0
- package/lib/command_common.js +182 -0
- package/lib/command_common.js.map +1 -0
- package/lib/environment.d.ts +3 -0
- package/lib/environment.js +5 -2
- package/lib/environment.js.map +1 -1
- package/lib/error-messages.d.ts +6 -0
- package/lib/error-messages.js +206 -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 +5 -2
- package/lib/init_browser.js +118 -7
- package/lib/init_browser.js.map +1 -1
- package/lib/locate_element.d.ts +7 -0
- package/lib/locate_element.js +215 -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/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 +183 -0
- package/lib/network.js.map +1 -0
- package/lib/scripts/axe.mini.js +12 -0
- package/lib/stable_browser.d.ts +98 -36
- package/lib/stable_browser.js +1680 -1271
- 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/table_helper.d.ts +19 -0
- package/lib/table_helper.js +101 -0
- package/lib/table_helper.js.map +1 -0
- package/lib/test_context.d.ts +6 -0
- package/lib/test_context.js +13 -9
- package/lib/test_context.js.map +1 -1
- package/lib/utils.d.ts +19 -1
- package/lib/utils.js +555 -5
- package/lib/utils.js.map +1 -1
- package/package.json +14 -9
package/lib/init_browser.js
CHANGED
|
@@ -7,10 +7,16 @@ import { StableBrowser } from "./stable_browser.js";
|
|
|
7
7
|
import { Api } from "./api.js";
|
|
8
8
|
// let environment = null;
|
|
9
9
|
// init browser create context and page, if context and page are not null
|
|
10
|
-
const getContext = async function (environment, headless = false, logger) {
|
|
10
|
+
const getContext = async function (environment, headless = false, world, logger, appName, createStable = true, stable = null, moveToRight = -1, reportFolder = null, initScripts = null, storageState = null) {
|
|
11
11
|
if (environment === null) {
|
|
12
12
|
environment = initEnvironment();
|
|
13
13
|
}
|
|
14
|
+
if (appName && !environment.apps && !environment.apps[appName]) {
|
|
15
|
+
throw new Error(`App ${appName} not found in environment`);
|
|
16
|
+
}
|
|
17
|
+
if (appName) {
|
|
18
|
+
environment = environment.apps[appName];
|
|
19
|
+
}
|
|
14
20
|
const { cookies, origins } = environment;
|
|
15
21
|
if (cookies) {
|
|
16
22
|
for (let i = 0; i < cookies.length; i++) {
|
|
@@ -22,31 +28,133 @@ const getContext = async function (environment, headless = false, logger) {
|
|
|
22
28
|
}
|
|
23
29
|
let extensionPath = undefined;
|
|
24
30
|
let userDataDirPath = undefined;
|
|
31
|
+
let userAgent = undefined;
|
|
25
32
|
let aiConfigFile = "ai_config.json";
|
|
33
|
+
let channel = undefined;
|
|
26
34
|
if (process.env.PROJECT_PATH) {
|
|
27
35
|
aiConfigFile = path.join(process.env.PROJECT_PATH, "ai_config.json");
|
|
28
36
|
}
|
|
37
|
+
let configuration = {};
|
|
29
38
|
if (fs.existsSync(aiConfigFile)) {
|
|
30
|
-
|
|
39
|
+
configuration = JSON.parse(fs.readFileSync(aiConfigFile, "utf8"));
|
|
31
40
|
if (configuration.userDataDirPath) {
|
|
32
41
|
userDataDirPath = configuration.userDataDirPath;
|
|
33
42
|
}
|
|
34
43
|
if (configuration.extensionPath) {
|
|
35
44
|
extensionPath = configuration.extensionPath;
|
|
36
45
|
}
|
|
46
|
+
if (configuration.useGoogleChrome === true) {
|
|
47
|
+
channel = "chrome";
|
|
48
|
+
}
|
|
49
|
+
else if (configuration.useMicrosoftEdge === true) {
|
|
50
|
+
channel = "msedge";
|
|
51
|
+
}
|
|
52
|
+
if (configuration.overrideUserAgent) {
|
|
53
|
+
userAgent = configuration.overrideUserAgent;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
let usedStorageState = null;
|
|
57
|
+
usedStorageState = { cookies, origins };
|
|
58
|
+
let downloadsPath = "downloads";
|
|
59
|
+
if (reportFolder) {
|
|
60
|
+
downloadsPath = path.join(reportFolder, "downloads");
|
|
61
|
+
}
|
|
62
|
+
else if (stable && stable.context && stable.context.reportFolder) {
|
|
63
|
+
reportFolder = stable.context.reportFolder;
|
|
64
|
+
downloadsPath = path.join(stable.context.reportFolder, "downloads");
|
|
65
|
+
}
|
|
66
|
+
if (world) {
|
|
67
|
+
world.downloadsPath = downloadsPath;
|
|
68
|
+
}
|
|
69
|
+
if (stable && stable.context) {
|
|
70
|
+
stable.context.downloadsPath = downloadsPath;
|
|
71
|
+
}
|
|
72
|
+
// check if data.json exists in the report folder
|
|
73
|
+
// and if it contain storageState field, if so, use it
|
|
74
|
+
if (reportFolder) {
|
|
75
|
+
const dataFile = path.join(reportFolder, "data.json");
|
|
76
|
+
if (fs.existsSync(dataFile)) {
|
|
77
|
+
const data = fs.readFileSync(dataFile, "utf8");
|
|
78
|
+
const dataObject = JSON.parse(data);
|
|
79
|
+
if (dataObject.storageState) {
|
|
80
|
+
console.log("Init browser with storage state");
|
|
81
|
+
usedStorageState = dataObject.storageState;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
if (storageState) {
|
|
86
|
+
usedStorageState = storageState;
|
|
37
87
|
}
|
|
38
|
-
|
|
39
|
-
let browser = await browserManager.getBrowser(headless, storageState, extensionPath, userDataDirPath);
|
|
88
|
+
let browser = await browserManager.createBrowser(headless, usedStorageState, extensionPath, userDataDirPath, reportFolder ? reportFolder : ".", userAgent, channel, configuration, initScripts);
|
|
40
89
|
let context = new TestContext();
|
|
41
90
|
context.browser = browser.browser;
|
|
91
|
+
context.browserObject = browser;
|
|
42
92
|
context.playContext = browser.context;
|
|
43
93
|
context.page = browser.page;
|
|
94
|
+
context.headless = headless;
|
|
44
95
|
context.environment = environment;
|
|
45
|
-
context.
|
|
96
|
+
context.browserName = browser.browser ? browser.browser.browserType().name() : "unknown";
|
|
97
|
+
context.reportFolder = reportFolder;
|
|
98
|
+
context.initScripts = initScripts;
|
|
99
|
+
if (createStable) {
|
|
100
|
+
context.stable = new StableBrowser(context.browser, context.page, logger, context, world);
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
context.stable = stable;
|
|
104
|
+
}
|
|
46
105
|
context.api = new Api(logger);
|
|
106
|
+
if (moveToRight > 0 && context.browserName === "chromium") {
|
|
107
|
+
// move the borwser to the top right corner of the screen
|
|
108
|
+
// create a cdp session
|
|
109
|
+
// Get CDP session
|
|
110
|
+
const playContext = context.playContext;
|
|
111
|
+
const client = await playContext.newCDPSession(context.page);
|
|
112
|
+
// Get window ID for the current target
|
|
113
|
+
const { windowId } = await client.send("Browser.getWindowForTarget");
|
|
114
|
+
//console.log(windowId);
|
|
115
|
+
// get the window for the current target
|
|
116
|
+
const window = await client.send("Browser.getWindowBounds", {
|
|
117
|
+
windowId,
|
|
118
|
+
});
|
|
119
|
+
//console.log(window);
|
|
120
|
+
await client.send("Browser.setWindowBounds", {
|
|
121
|
+
windowId,
|
|
122
|
+
bounds: {
|
|
123
|
+
left: window.bounds.left + moveToRight,
|
|
124
|
+
},
|
|
125
|
+
});
|
|
126
|
+
// close cdp
|
|
127
|
+
await client.detach();
|
|
128
|
+
}
|
|
47
129
|
// await _initCookies(context);
|
|
48
130
|
return context;
|
|
49
131
|
};
|
|
132
|
+
const refreshBrowser = async function (stable, sessionPath, world) {
|
|
133
|
+
await stable.context.browserObject.close();
|
|
134
|
+
stable.context.pages = [];
|
|
135
|
+
let storageState = null;
|
|
136
|
+
if (sessionPath) {
|
|
137
|
+
if (!fs.existsSync(sessionPath)) {
|
|
138
|
+
throw new Error("Session path not found: " + sessionPath);
|
|
139
|
+
}
|
|
140
|
+
const data = fs.readFileSync(sessionPath, "utf8");
|
|
141
|
+
storageState = JSON.parse(data).storageState;
|
|
142
|
+
}
|
|
143
|
+
const newContext = await getContext(stable.context.environment, stable.context.headless, world, null, stable.context.appName, false, stable, -1, stable.context.reportFolder, stable.context.initScripts, storageState);
|
|
144
|
+
// clone all the new context properties to the old context
|
|
145
|
+
stable.context.browser = newContext.browser;
|
|
146
|
+
stable.context.browserObject = newContext.browserObject;
|
|
147
|
+
stable.context.playContext = newContext.playContext;
|
|
148
|
+
stable.context.page = newContext.page;
|
|
149
|
+
stable.page = newContext.page;
|
|
150
|
+
stable.context.pages.push(newContext.page);
|
|
151
|
+
stable.context.headless = newContext.headless;
|
|
152
|
+
stable.context.environment = newContext.environment;
|
|
153
|
+
stable.context.browserName = newContext.browserName;
|
|
154
|
+
stable.context.reportFolder = newContext.reportFolder;
|
|
155
|
+
stable.context.initScripts = newContext.initScripts;
|
|
156
|
+
await stable.goto(stable.context.environment.baseUrl);
|
|
157
|
+
};
|
|
50
158
|
const closeBrowser = async function (browser) {
|
|
51
159
|
await browserManager.closeBrowser(browser);
|
|
52
160
|
};
|
|
@@ -75,7 +183,10 @@ const initEnvironment = function () {
|
|
|
75
183
|
}
|
|
76
184
|
}
|
|
77
185
|
}
|
|
78
|
-
//
|
|
186
|
+
// check if the envFile is not empty and exists
|
|
187
|
+
if (!envFile || !fs.existsSync(envFile)) {
|
|
188
|
+
throw new Error(envFile + " not found");
|
|
189
|
+
}
|
|
79
190
|
const data = fs.readFileSync(envFile, "utf8");
|
|
80
191
|
//console.log("data", data);
|
|
81
192
|
const envObject = JSON.parse(data);
|
|
@@ -101,5 +212,5 @@ const checkForEnvArg = function () {
|
|
|
101
212
|
}
|
|
102
213
|
return null;
|
|
103
214
|
};
|
|
104
|
-
export { getContext, closeBrowser };
|
|
215
|
+
export { getContext, closeBrowser, refreshBrowser };
|
|
105
216
|
//# sourceMappingURL=init_browser.js.map
|
package/lib/init_browser.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init_browser.js","sourceRoot":"","sources":["../../src/init_browser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAGpD,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"init_browser.js","sourceRoot":"","sources":["../../src/init_browser.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import axios from "axios";
|
|
2
|
+
import * as path from "path";
|
|
3
|
+
import { fileURLToPath } from "url";
|
|
4
|
+
import { _getServerUrl } from "./utils.js";
|
|
5
|
+
// Get __filename and __dirname in ESM
|
|
6
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
7
|
+
const __dirname = path.dirname(__filename);
|
|
8
|
+
export async function locate_element(context, elementDescription, operation = "click", value = null) {
|
|
9
|
+
// load the axe-core library to all of the frames in the page
|
|
10
|
+
// read the axe-core library from the file system placed in the same folder as the script file, name axe.mini.js
|
|
11
|
+
// Construct the path to axe.min.js relative to the current file
|
|
12
|
+
// let axeMinJsPath = path.join(__dirname, "..", "scripts", "axe.mini.js");
|
|
13
|
+
// // Check if the file exists
|
|
14
|
+
// if (!fs.existsSync(axeMinJsPath)) {
|
|
15
|
+
// axeMinJsPath = path.join(__dirname, "scripts", "axe.mini.js");
|
|
16
|
+
// }
|
|
17
|
+
// // Read the content of axe.min.js synchronously
|
|
18
|
+
// const axeMinJsContent = fs.readFileSync(axeMinJsPath, "utf-8");
|
|
19
|
+
// await Promise.all(context.stable.page.frames().map((frame: any) => frame.evaluate(axeMinJsContent)));
|
|
20
|
+
const frames = await context.stable.page.frames();
|
|
21
|
+
// for each frame create a tree of the accessibility nodes
|
|
22
|
+
const frameDump = [];
|
|
23
|
+
let iframeIndex = 0;
|
|
24
|
+
let nextFrameIndex = 1;
|
|
25
|
+
let actionableElementIndex = 0;
|
|
26
|
+
const randomToken = Math.random().toString(36).substring(7);
|
|
27
|
+
const actionableElements = [];
|
|
28
|
+
for (let frame of frames) {
|
|
29
|
+
// @ts-ignore
|
|
30
|
+
let result = null;
|
|
31
|
+
try {
|
|
32
|
+
result = await frame.evaluate(
|
|
33
|
+
// @ts-ignore
|
|
34
|
+
([iframeIndex, nextFrameIndex, actionableElementIndex, randomToken]) => {
|
|
35
|
+
let iframeCount = 1;
|
|
36
|
+
const actionableElements = [];
|
|
37
|
+
const actionableRoles = [
|
|
38
|
+
"link",
|
|
39
|
+
"button",
|
|
40
|
+
"tab",
|
|
41
|
+
"menuitem",
|
|
42
|
+
"menuitemcheckbox",
|
|
43
|
+
"menuitemradio",
|
|
44
|
+
"checkbox",
|
|
45
|
+
"textbox",
|
|
46
|
+
"combobox",
|
|
47
|
+
"listitem",
|
|
48
|
+
"radio",
|
|
49
|
+
"searchbox",
|
|
50
|
+
"option",
|
|
51
|
+
"Date",
|
|
52
|
+
"row",
|
|
53
|
+
"DateTime",
|
|
54
|
+
"InputTime",
|
|
55
|
+
"treeitem",
|
|
56
|
+
];
|
|
57
|
+
function isAccessibilityElement(element) {
|
|
58
|
+
if (!element) {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
// @ts-ignore
|
|
62
|
+
let hidden = axe.commons.dom.isHiddenForEveryone(element);
|
|
63
|
+
if (hidden) {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
if (element.tagName === "IFRAME") {
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
// @ts-ignore
|
|
70
|
+
let roles = axe.commons.aria.getRole(element);
|
|
71
|
+
if (!roles) {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
function getAttributes(element) {
|
|
77
|
+
const attrs = element.attributes;
|
|
78
|
+
const result = {};
|
|
79
|
+
for (let i = 0; i < attrs.length; i++) {
|
|
80
|
+
result[attrs[i].name] = attrs[i].value;
|
|
81
|
+
if (attrs[i].name === "class") {
|
|
82
|
+
// clean the spaces
|
|
83
|
+
result[attrs[i].name] = attrs[i].value.replace(/\s+/g, " ").trim();
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return result;
|
|
87
|
+
}
|
|
88
|
+
function createAccessibilityNode(element, actionableElements) {
|
|
89
|
+
// check if the element is an iframe
|
|
90
|
+
const result = {
|
|
91
|
+
tag: element.tagName,
|
|
92
|
+
// @ts-ignore
|
|
93
|
+
role: axe.commons.aria.getRole(element),
|
|
94
|
+
// @ts-ignore
|
|
95
|
+
visible: axe.commons.dom.isVisible(element),
|
|
96
|
+
// @ts-ignore
|
|
97
|
+
name: axe.commons.text.accessibleText(element),
|
|
98
|
+
attributes: getAttributes(element),
|
|
99
|
+
// @ts-ignore
|
|
100
|
+
frameIndex: iframeIndex,
|
|
101
|
+
};
|
|
102
|
+
if (actionableRoles.includes(result.role)) {
|
|
103
|
+
// @ts-ignore
|
|
104
|
+
result.elementNumber = actionableElementIndex;
|
|
105
|
+
element.setAttribute("data-blinq-id", "blinq-id-" + randomToken + "-" + actionableElementIndex);
|
|
106
|
+
//console.log("attribute set to " + "blinq-id-" + randomToken + "-" + actionableElementIndex);
|
|
107
|
+
actionableElementIndex++;
|
|
108
|
+
actionableElements.push(result);
|
|
109
|
+
}
|
|
110
|
+
if (element.tagName === "IFRAME") {
|
|
111
|
+
// @ts-ignore
|
|
112
|
+
result.targetFrameIndex = nextFrameIndex;
|
|
113
|
+
nextFrameIndex++;
|
|
114
|
+
}
|
|
115
|
+
return result;
|
|
116
|
+
}
|
|
117
|
+
// a function that traverses the DOM tree and builds a tree of accessibility nodes
|
|
118
|
+
function buildAccessibilityTree(node, treeRoot) {
|
|
119
|
+
//const foundAccessibilityNodes = [];
|
|
120
|
+
if (!treeRoot.children) {
|
|
121
|
+
treeRoot.children = [];
|
|
122
|
+
}
|
|
123
|
+
//console.log(node.tagName + " " + node.children.length);
|
|
124
|
+
for (let child of node.children) {
|
|
125
|
+
if (isAccessibilityElement(child)) {
|
|
126
|
+
const accessibilityNode = createAccessibilityNode(child, actionableElements);
|
|
127
|
+
// @ts-ignore
|
|
128
|
+
// accessibilityNode.children = buildAccessibilityTree(child, accessibilityNode),
|
|
129
|
+
// foundAccessibilityNodes.push(accessibilityNode);
|
|
130
|
+
treeRoot.children.push(accessibilityNode);
|
|
131
|
+
buildAccessibilityTree(child, accessibilityNode);
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
buildAccessibilityTree(child, treeRoot);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
// @ts-ignore
|
|
139
|
+
axe.utils.getFlattenedTree(document);
|
|
140
|
+
const root = createAccessibilityNode(document.body, actionableElements);
|
|
141
|
+
buildAccessibilityTree(document.body, root);
|
|
142
|
+
return JSON.stringify({ root, nextFrameIndex, actionableElementIndex, actionableElements }, null, 2);
|
|
143
|
+
}, [iframeIndex, nextFrameIndex, actionableElementIndex, randomToken]);
|
|
144
|
+
const resultData = JSON.parse(result);
|
|
145
|
+
nextFrameIndex = resultData.nextFrameIndex;
|
|
146
|
+
actionableElementIndex = resultData.actionableElementIndex;
|
|
147
|
+
frameDump.push(resultData.root);
|
|
148
|
+
actionableElements.push(...resultData.actionableElements);
|
|
149
|
+
iframeIndex++;
|
|
150
|
+
}
|
|
151
|
+
catch (e) {
|
|
152
|
+
// ignore
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
function traverseDFS(node) {
|
|
156
|
+
// Recursively traverse each child node
|
|
157
|
+
if (node.children && node.children.length > 0) {
|
|
158
|
+
node.children.forEach((child) => {
|
|
159
|
+
if (child.tag === "IFRAME") {
|
|
160
|
+
if (child.targetFrameIndex && frameDump.length >= child.targetFrameIndex) {
|
|
161
|
+
child.children = [frameDump[child.targetFrameIndex]];
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
if (child.shadowRoot) {
|
|
165
|
+
traverseDFS(child.shadowRoot);
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
traverseDFS(child);
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
traverseDFS(frameDump[0]);
|
|
174
|
+
let serviceUrl = _getServerUrl();
|
|
175
|
+
const config = {
|
|
176
|
+
method: "post",
|
|
177
|
+
url: `${serviceUrl}/api/runs/locate-element/locate`,
|
|
178
|
+
headers: {
|
|
179
|
+
"x-source": "true",
|
|
180
|
+
"Content-Type": "application/json",
|
|
181
|
+
Authorization: `Bearer ${process.env.TOKEN}`,
|
|
182
|
+
},
|
|
183
|
+
data: JSON.stringify({
|
|
184
|
+
elementDescription: elementDescription,
|
|
185
|
+
operation: operation,
|
|
186
|
+
dump: frameDump[0],
|
|
187
|
+
value: value,
|
|
188
|
+
}),
|
|
189
|
+
};
|
|
190
|
+
let result = await axios.request(config);
|
|
191
|
+
//console.log(JSON.stringify(frameDump[0]));
|
|
192
|
+
if (result.status !== 200 || !result.data || result.data.status !== true || !result.data.result) {
|
|
193
|
+
console.error("Failed to locate element");
|
|
194
|
+
return null;
|
|
195
|
+
}
|
|
196
|
+
const returnData = {
|
|
197
|
+
reason: result.data.result.reason,
|
|
198
|
+
elementNumber: result.data.result.elementNumber,
|
|
199
|
+
frameIndex: -1,
|
|
200
|
+
frame: null,
|
|
201
|
+
css: "",
|
|
202
|
+
};
|
|
203
|
+
if (result.data.result.elementNumber !== -1) {
|
|
204
|
+
// find the iframe index, the element is in, by identifying the actionable element
|
|
205
|
+
const actionableElement = actionableElements.find((element) => element.elementNumber === result.data.result.elementNumber);
|
|
206
|
+
if (actionableElement) {
|
|
207
|
+
returnData.frameIndex = actionableElement.frameIndex;
|
|
208
|
+
returnData.frame = frames[returnData.frameIndex];
|
|
209
|
+
returnData.css = `[data-blinq-id="blinq-id-${randomToken}-${returnData.elementNumber}"]`;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
//console.log(dumpToHtml(frameDump[0]));
|
|
213
|
+
return returnData;
|
|
214
|
+
}
|
|
215
|
+
//# sourceMappingURL=locate_element.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"locate_element.js","sourceRoot":"","sources":["../../src/locate_element.ts"],"names":[],"mappings":"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"}
|
package/lib/locator.d.ts
CHANGED
|
@@ -17,6 +17,42 @@ declare function getTableData(table: Element): {
|
|
|
17
17
|
columnNames: never[];
|
|
18
18
|
rows: never[];
|
|
19
19
|
};
|
|
20
|
+
declare function getTableData2(table: any): {
|
|
21
|
+
rowsCount: number;
|
|
22
|
+
columnsCount: number;
|
|
23
|
+
nodes: never[];
|
|
24
|
+
rows: never[];
|
|
25
|
+
columnHeaders: never[];
|
|
26
|
+
};
|
|
27
|
+
declare function getVisibleText(thElement: any): any;
|
|
28
|
+
declare const Roles: {
|
|
29
|
+
LINK: string;
|
|
30
|
+
BUTTON: string;
|
|
31
|
+
CHECKBOX: string;
|
|
32
|
+
RADIO: string;
|
|
33
|
+
SLIDER: string;
|
|
34
|
+
TEXTBOX: string;
|
|
35
|
+
PRESENTATION: string;
|
|
36
|
+
IMG: string;
|
|
37
|
+
LIST: string;
|
|
38
|
+
LISTITEM: string;
|
|
39
|
+
TABLE: string;
|
|
40
|
+
COLUMNHEADER: string;
|
|
41
|
+
ROWHEADER: string;
|
|
42
|
+
CELL: string;
|
|
43
|
+
ROW: string;
|
|
44
|
+
NAVIGATION: string;
|
|
45
|
+
BANNER: string;
|
|
46
|
+
CONTENTINFO: string;
|
|
47
|
+
MAIN: string;
|
|
48
|
+
ARTICLE: string;
|
|
49
|
+
REGION: string;
|
|
50
|
+
COMPLEMENTARY: string;
|
|
51
|
+
FORM: string;
|
|
52
|
+
LISTBOX: string;
|
|
53
|
+
COMBOBOX: string;
|
|
54
|
+
};
|
|
55
|
+
declare function getRole(element: any): any;
|
|
20
56
|
declare function processTableQuery(table: Element, query: string): {
|
|
21
57
|
cells: any[];
|
|
22
58
|
error?: undefined;
|
package/lib/locator.js
CHANGED
|
@@ -45,6 +45,171 @@ function getTableData(table) {
|
|
|
45
45
|
}
|
|
46
46
|
// @ts-ignore
|
|
47
47
|
document.getTableData = getTableData;
|
|
48
|
+
function getTableData2(table) {
|
|
49
|
+
// Scan the table and build a tree
|
|
50
|
+
function scanTable(root, nodeArray, tableData) {
|
|
51
|
+
const role = document.getRole(root);
|
|
52
|
+
if (role &&
|
|
53
|
+
(role === Roles.CELL || role === Roles.ROW || role === Roles.COLUMNHEADER || role === Roles.ROWHEADER)) {
|
|
54
|
+
const rec = root.getBoundingClientRect();
|
|
55
|
+
const node = {
|
|
56
|
+
tag: root.tagName,
|
|
57
|
+
role,
|
|
58
|
+
rec: rec ? [rec.x, rec.y, rec.width, rec.height] : null,
|
|
59
|
+
children: [],
|
|
60
|
+
};
|
|
61
|
+
if (role === Roles.CELL || role === Roles.COLUMNHEADER || role === Roles.ROWHEADER) {
|
|
62
|
+
node.text = document.getVisibleText(root);
|
|
63
|
+
}
|
|
64
|
+
if (role === Roles.COLUMNHEADER) {
|
|
65
|
+
tableData.columnsCount++;
|
|
66
|
+
tableData.columnHeaders.push(node);
|
|
67
|
+
}
|
|
68
|
+
if (role === Roles.ROW) {
|
|
69
|
+
tableData.rowsCount++;
|
|
70
|
+
tableData.rows.push(node);
|
|
71
|
+
}
|
|
72
|
+
nodeArray.push(node);
|
|
73
|
+
nodeArray = node.children;
|
|
74
|
+
}
|
|
75
|
+
const children = Array.from(root.children);
|
|
76
|
+
for (let i = 0; i < children.length; i++) {
|
|
77
|
+
scanTable(children[i], nodeArray, tableData);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
const tableData = {
|
|
81
|
+
rowsCount: 0,
|
|
82
|
+
columnsCount: 0,
|
|
83
|
+
nodes: [],
|
|
84
|
+
rows: [],
|
|
85
|
+
columnHeaders: [],
|
|
86
|
+
};
|
|
87
|
+
// Pass the root table element and initialize the tree
|
|
88
|
+
scanTable(table, tableData.nodes, tableData);
|
|
89
|
+
return tableData;
|
|
90
|
+
}
|
|
91
|
+
function getVisibleText(thElement) {
|
|
92
|
+
// if (!(thElement instanceof HTMLTableCellElement && thElement.tagName === 'TH')) {
|
|
93
|
+
// throw new Error('Provided element is not a valid TH element.');
|
|
94
|
+
// }
|
|
95
|
+
// Helper function to recursively collect visible text
|
|
96
|
+
function getText(node) {
|
|
97
|
+
if (node.nodeType === Node.TEXT_NODE) {
|
|
98
|
+
return node.textContent.trim(); // Return text content of text nodes
|
|
99
|
+
}
|
|
100
|
+
if (node.nodeType === Node.ELEMENT_NODE) {
|
|
101
|
+
const tagName = node.tagName.toUpperCase();
|
|
102
|
+
if (tagName === "BR") {
|
|
103
|
+
return "\n"; // Treat <br> as a newline
|
|
104
|
+
}
|
|
105
|
+
if (getComputedStyle(node).display === "none") {
|
|
106
|
+
return ""; // Ignore invisible elements
|
|
107
|
+
}
|
|
108
|
+
// Recursively process child nodes
|
|
109
|
+
return Array.from(node.childNodes).map(getText).join("");
|
|
110
|
+
}
|
|
111
|
+
return ""; // Ignore other node types
|
|
112
|
+
}
|
|
113
|
+
return getText(thElement)
|
|
114
|
+
.replace(/\n\s*\n/g, "\n")
|
|
115
|
+
.trim(); // Clean up multiple newlines
|
|
116
|
+
}
|
|
117
|
+
document.getVisibleText = getVisibleText;
|
|
118
|
+
// @ts-ignore
|
|
119
|
+
document.getTableData2 = getTableData2;
|
|
120
|
+
const Roles = {
|
|
121
|
+
LINK: "link",
|
|
122
|
+
BUTTON: "button",
|
|
123
|
+
CHECKBOX: "checkbox",
|
|
124
|
+
RADIO: "radio",
|
|
125
|
+
SLIDER: "slider",
|
|
126
|
+
TEXTBOX: "textbox",
|
|
127
|
+
PRESENTATION: "presentation",
|
|
128
|
+
IMG: "img",
|
|
129
|
+
LIST: "list",
|
|
130
|
+
LISTITEM: "listitem",
|
|
131
|
+
TABLE: "table",
|
|
132
|
+
COLUMNHEADER: "columnheader",
|
|
133
|
+
ROWHEADER: "rowheader",
|
|
134
|
+
CELL: "cell",
|
|
135
|
+
ROW: "row",
|
|
136
|
+
NAVIGATION: "navigation",
|
|
137
|
+
BANNER: "banner",
|
|
138
|
+
CONTENTINFO: "contentinfo",
|
|
139
|
+
MAIN: "main",
|
|
140
|
+
ARTICLE: "article",
|
|
141
|
+
REGION: "region",
|
|
142
|
+
COMPLEMENTARY: "complementary",
|
|
143
|
+
FORM: "form",
|
|
144
|
+
LISTBOX: "listbox",
|
|
145
|
+
COMBOBOX: "combobox",
|
|
146
|
+
};
|
|
147
|
+
function getRole(element) {
|
|
148
|
+
if (!element || typeof element.getAttribute !== "function") {
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
const tagName = element.tagName.toLowerCase();
|
|
152
|
+
function getInputRole(el) {
|
|
153
|
+
const type = el.type;
|
|
154
|
+
if (["button", "submit", "reset", "image"].includes(type)) {
|
|
155
|
+
return Roles.BUTTON;
|
|
156
|
+
}
|
|
157
|
+
if (type === "checkbox")
|
|
158
|
+
return Roles.CHECKBOX;
|
|
159
|
+
if (type === "radio")
|
|
160
|
+
return Roles.RADIO;
|
|
161
|
+
if (type === "range")
|
|
162
|
+
return Roles.SLIDER;
|
|
163
|
+
if (["email", "tel", "text", "search", "url", "password"].includes(type)) {
|
|
164
|
+
return Roles.TEXTBOX;
|
|
165
|
+
}
|
|
166
|
+
return null;
|
|
167
|
+
}
|
|
168
|
+
function getImageRole(el) {
|
|
169
|
+
return el.getAttribute("alt") === "" ? Roles.PRESENTATION : Roles.IMG;
|
|
170
|
+
}
|
|
171
|
+
const implicitRoles = {
|
|
172
|
+
a: (el) => (el.hasAttribute("href") ? Roles.LINK : null),
|
|
173
|
+
button: Roles.BUTTON,
|
|
174
|
+
input: getInputRole,
|
|
175
|
+
select: (el) => (el.hasAttribute("multiple") || el.size > 1 ? Roles.LISTBOX : Roles.COMBOBOX),
|
|
176
|
+
textarea: Roles.TEXTBOX,
|
|
177
|
+
img: getImageRole,
|
|
178
|
+
ul: Roles.LIST,
|
|
179
|
+
ol: Roles.LIST,
|
|
180
|
+
li: Roles.LISTITEM,
|
|
181
|
+
table: Roles.TABLE,
|
|
182
|
+
th: (el) => {
|
|
183
|
+
const scope = el.getAttribute("scope");
|
|
184
|
+
if (scope === "col" || el.closest("thead")) {
|
|
185
|
+
return Roles.COLUMNHEADER;
|
|
186
|
+
}
|
|
187
|
+
if (scope === "row") {
|
|
188
|
+
return Roles.ROWHEADER;
|
|
189
|
+
}
|
|
190
|
+
// Fallback: infer based on context
|
|
191
|
+
const parentRow = el.closest("tr");
|
|
192
|
+
return parentRow && parentRow.parentNode.tagName.toLowerCase() === "thead" ? Roles.COLUMNHEADER : Roles.ROWHEADER;
|
|
193
|
+
},
|
|
194
|
+
td: Roles.CELL,
|
|
195
|
+
tr: Roles.ROW,
|
|
196
|
+
nav: Roles.NAVIGATION,
|
|
197
|
+
header: Roles.BANNER,
|
|
198
|
+
footer: Roles.CONTENTINFO,
|
|
199
|
+
form: (el) => (el.hasAttribute("name") ? Roles.FORM : null),
|
|
200
|
+
main: Roles.MAIN,
|
|
201
|
+
article: Roles.ARTICLE,
|
|
202
|
+
section: Roles.REGION,
|
|
203
|
+
aside: Roles.COMPLEMENTARY,
|
|
204
|
+
};
|
|
205
|
+
const role = element.getAttribute("role");
|
|
206
|
+
if (role) {
|
|
207
|
+
return role;
|
|
208
|
+
}
|
|
209
|
+
const implicitRole = implicitRoles[tagName];
|
|
210
|
+
return typeof implicitRole === "function" ? implicitRole(element) : implicitRole || null;
|
|
211
|
+
}
|
|
212
|
+
document.getRole = getRole;
|
|
48
213
|
// locator | operator | value
|
|
49
214
|
// table.rows | >= | 1
|
|
50
215
|
// table[1]["Availability"].text | equals | 100%
|