ff-automationv2 2.2.29 → 2.2.31
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/dist/ai/llmcalls/llmAction.js +49 -13
- package/dist/ai/llmcalls/parseLlmOputput.js +5 -5
- package/dist/ai/llmprompts/promptRegistry.js +4 -0
- package/dist/ai/llmprompts/systemPrompts/actionExtractorPrompt.js +39 -11
- package/dist/ai/llmprompts/systemPrompts/fireflinkElementIndexExtactors.js +6 -6
- package/dist/ai/llmprompts/systemPrompts/fireflinkElementIndexExtractor_Mob.js +32 -0
- package/dist/ai/llmprompts/systemPrompts/mobileKeywordExtractor.js +17 -8
- package/dist/ai/llmprompts/systemPrompts/otpExtractorPrompt.d.ts +1 -0
- package/dist/ai/llmprompts/systemPrompts/otpExtractorPrompt.js +22 -0
- package/dist/ai/llmprompts/systemPrompts/verifyActionExtractorPrompt.js +3 -1
- package/dist/ai/llmprompts/systemPrompts/visionPrompt.js +14 -6
- package/dist/ai/llmprompts/systemPrompts/visionPromptMobile.js +3 -0
- package/dist/ai/llmprompts/userPrompts/userPrompt.js +1 -0
- package/dist/automation/actions/executor.d.ts +4 -0
- package/dist/automation/actions/executor.js +20 -0
- package/dist/automation/actions/interaction/clear/clear.js +1 -1
- package/dist/automation/actions/interaction/clear/clearAndEnter.js +1 -1
- package/dist/automation/actions/interaction/click/click.js +10 -3
- package/dist/automation/actions/interaction/click/clickNtimes.js +1 -1
- package/dist/automation/actions/interaction/click/doubleClick.js +1 -1
- package/dist/automation/actions/interaction/click/rightClick.js +1 -1
- package/dist/automation/actions/interaction/elementlessActions/getOtp.d.ts +2 -0
- package/dist/automation/actions/interaction/elementlessActions/getOtp.js +101 -0
- package/dist/automation/actions/interaction/enterActions/enterInput.js +11 -6
- package/dist/automation/actions/interaction/enterActions/enterInputAndPress.js +2 -2
- package/dist/automation/actions/interaction/enterActions/enterusingJs.js +2 -2
- package/dist/automation/actions/interaction/enterActions/waitAndEnter.js +1 -1
- package/dist/automation/actions/interaction/upload/uploadfile.js +1 -1
- package/dist/automation/actions/interaction/verify/VerifyNavigateURL.js +38 -11
- package/dist/automation/actions/interface/FireFlinkResponseSchema.d.ts +12 -0
- package/dist/automation/actions/interface/FireFlinkResponseSchema.js +19 -3
- package/dist/automation/actions/interface/getOtpInterface.d.ts +15 -0
- package/dist/automation/actions/interface/getOtpInterface.js +2 -0
- package/dist/automation/browserSession/initiateBrowserSession.d.ts +1 -1
- package/dist/automation/browserSession/initiateBrowserSession.js +15 -7
- package/dist/automation/driverState.d.ts +2 -0
- package/dist/automation/driverState.js +4 -0
- package/dist/automation/mobileSession/initiateMobileSession.d.ts +4 -5
- package/dist/automation/mobileSession/initiateMobileSession.js +83 -19
- package/dist/core/constants/allAction.js +5 -1
- package/dist/core/constants/supportedActions.js +5 -2
- package/dist/core/interfaces/actionInterface.d.ts +4 -0
- package/dist/core/interfaces/browserConfigurationInterface.d.ts +0 -4
- package/dist/core/interfaces/browserConfigurationInterface.js +0 -1
- package/dist/core/interfaces/executionDetails.d.ts +6 -3
- package/dist/core/interfaces/fireflinkScriptPayloadInterface.d.ts +22 -16
- package/dist/core/interfaces/llmResponseInterface.d.ts +1 -0
- package/dist/core/interfaces/promptInterface.d.ts +1 -0
- package/dist/core/main/SessionManager.d.ts +9 -0
- package/dist/core/main/SessionManager.js +23 -0
- package/dist/core/main/actionHandlerFactory.js +261 -64
- package/dist/core/main/executionContext.d.ts +7 -1
- package/dist/core/main/executionContext.js +94 -3
- package/dist/core/main/runAutomationScript.d.ts +1 -0
- package/dist/core/main/runAutomationScript.js +912 -304
- package/dist/core/main/stepProcessor.js +7 -2
- package/dist/core/types/browserType.d.ts +3 -3
- package/dist/core/types/browserType.js +2 -2
- package/dist/core/types/messageType.d.ts +13 -0
- package/dist/core/types/messageType.js +15 -0
- package/dist/core/types/promptType.d.ts +2 -1
- package/dist/core/types/promptType.js +1 -0
- package/dist/domAnalysis/searchBest.js +15 -16
- package/dist/domAnalysis/simplifyAndFlatten.js +6 -4
- package/dist/fireflinkData/fireflinkLocators/getListOfLocators.d.ts +3 -0
- package/dist/fireflinkData/fireflinkLocators/getListOfLocators.js +23 -15
- package/dist/fireflinkData/fireflinkLocators/parser/getElementsFromHTML.d.ts +3 -3
- package/dist/fireflinkData/fireflinkLocators/parser/getElementsFromHTML.js +134 -118
- package/dist/fireflinkData/fireflinkLocators/types/locator.d.ts +11 -1
- package/dist/fireflinkData/fireflinkLocators/utils/androidSelector.d.ts +1 -1
- package/dist/fireflinkData/fireflinkLocators/utils/androidSelector.js +35 -9
- package/dist/fireflinkData/fireflinkLocators/utils/cssSelector.d.ts +10 -10
- package/dist/fireflinkData/fireflinkLocators/utils/cssSelector.js +56 -59
- package/dist/fireflinkData/fireflinkLocators/utils/iosSelector.d.ts +1 -1
- package/dist/fireflinkData/fireflinkLocators/utils/iosSelector.js +53 -29
- package/dist/fireflinkData/fireflinkLocators/utils/referenceXpath.d.ts +8 -8
- package/dist/fireflinkData/fireflinkLocators/utils/referenceXpath.js +113 -190
- package/dist/fireflinkData/fireflinkLocators/utils/xpath.d.ts +17 -26
- package/dist/fireflinkData/fireflinkLocators/utils/xpath.js +314 -786
- package/dist/fireflinkData/fireflinkLocators/utils/xpathHelpers.d.ts +68 -70
- package/dist/fireflinkData/fireflinkLocators/utils/xpathHelpers.js +498 -517
- package/dist/fireflinkData/fireflinkScript/appendScriptData.d.ts +1 -1
- package/dist/fireflinkData/fireflinkScript/appendScriptData.js +5 -8
- package/dist/fireflinkData/fireflinkScript/scriptGenrationData.d.ts +2 -2
- package/dist/fireflinkData/fireflinkScript/scriptGenrationData.js +17 -27
- package/dist/llmConfig/llmConfiguration.js +13 -6
- package/dist/service/api/fireflinkApi.service.d.ts +1 -1
- package/dist/service/api/fireflinkApi.service.js +1 -2
- package/dist/service/fireflink.service.d.ts +3 -3
- package/dist/service/fireflink.service.js +23 -21
- package/dist/service/kafka/fireflinkKafka.service.d.ts +1 -2
- package/dist/service/kafka/fireflinkKafka.service.js +6 -4
- package/dist/tests/test12.d.ts +0 -1
- package/dist/tests/test12.js +65 -78
- package/dist/tests/testkaf.d.ts +0 -1
- package/dist/tests/testkaf.js +51 -55
- package/dist/utils/InstancesDetails/getInstancesInfo.js +1 -1
- package/dist/utils/browserCap/capability.d.ts +5 -1
- package/dist/utils/browserCap/capability.js +91 -15
- package/dist/utils/helpers/domSanitizer.d.ts +1 -0
- package/dist/utils/helpers/domSanitizer.js +9 -0
- package/dist/utils/helpers/enterActionHelper.js +23 -4
- package/dist/utils/helpers/xpathcreation.js +2 -2
- package/dist/utils/javascript/jsFindElement.d.ts +1 -1
- package/dist/utils/javascript/jsFindElement.js +2 -2
- package/dist/utils/newTab/newTabTracker.js +18 -6
- package/dist/utils/workers/LocatorWorkerInterface.d.ts +22 -0
- package/dist/utils/workers/LocatorWorkerInterface.js +2 -0
- package/dist/utils/workers/LocatorWorkerPool.d.ts +13 -0
- package/dist/utils/workers/LocatorWorkerPool.js +89 -0
- package/dist/utils/workers/locatorWorker.d.ts +1 -0
- package/dist/utils/workers/locatorWorker.js +44 -0
- package/package.json +3 -1
|
@@ -1,439 +1,68 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.aiParseDOM = exports.getAiTextXPath = exports.getAiUniqueClassName = exports.attributesAiBasedXPath = void 0;
|
|
4
4
|
const logData_js_1 = require("../../../utils/logger/logData.js");
|
|
5
5
|
const xpathHelpers_js_1 = require("./xpathHelpers.js");
|
|
6
6
|
const androidSelector_js_1 = require("./androidSelector.js");
|
|
7
7
|
const iosSelector_js_1 = require("./iosSelector.js");
|
|
8
8
|
let xpathData = [];
|
|
9
|
-
const
|
|
9
|
+
const xpathValues = new Set();
|
|
10
|
+
const MAX_XPATH_RESULTS = 5;
|
|
10
11
|
const referenceElementMode = false;
|
|
11
12
|
const xpathCache = new Map();
|
|
12
13
|
const cache = new Map();
|
|
14
|
+
const parentRelativeCache = new WeakMap();
|
|
13
15
|
const parentXpathCache = new Map();
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
axes: "axes",
|
|
21
|
-
index: "index",
|
|
22
|
-
hardCodedText: "text",
|
|
23
|
-
tillTag: "tag"
|
|
24
|
-
};
|
|
25
|
-
const getStrategyName = (strategy) => {
|
|
26
|
-
return STRATEGY_MAP[strategy] || strategy;
|
|
27
|
-
};
|
|
28
|
-
const withStrategyKey = (strategy, entries) => {
|
|
29
|
-
return entries.map((entry) => ({
|
|
30
|
-
...entry,
|
|
31
|
-
key: entry?.key?.includes(strategy)
|
|
32
|
-
? entry.key
|
|
33
|
-
: `${strategy} ${entry.key}`.trim()
|
|
34
|
-
}));
|
|
35
|
-
};
|
|
36
|
-
const getUniqueXpathEntries = (entries) => {
|
|
37
|
-
const seen = new Set();
|
|
38
|
-
return entries.filter((entry) => {
|
|
39
|
-
if (!entry?.value || seen.has(entry.value)) {
|
|
40
|
-
return false;
|
|
41
|
-
}
|
|
42
|
-
seen.add(entry.value);
|
|
16
|
+
const filteredTextCache = new WeakMap();
|
|
17
|
+
const textContentCache = new WeakMap();
|
|
18
|
+
const appendXPath = (target, xpath) => {
|
|
19
|
+
if (!xpath.value)
|
|
20
|
+
return false;
|
|
21
|
+
if (xpathValues.has(xpath.value))
|
|
43
22
|
return true;
|
|
44
|
-
|
|
23
|
+
if (target.length >= MAX_XPATH_RESULTS)
|
|
24
|
+
return false;
|
|
25
|
+
target.push(xpath);
|
|
26
|
+
xpathValues.add(xpath.value);
|
|
27
|
+
return target.length < MAX_XPATH_RESULTS;
|
|
45
28
|
};
|
|
46
|
-
const
|
|
47
|
-
return
|
|
29
|
+
const hasReachedRelativeXpathLimit = () => {
|
|
30
|
+
return xpathData.length >= MAX_XPATH_RESULTS;
|
|
48
31
|
};
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
if (strategy === "text") {
|
|
55
|
-
const textXpath = (0, xpathHelpers_js_1.getFilteredTextXPath)(element) ||
|
|
56
|
-
(0, exports.getTextXPath)(element, docmt, false, false, platform);
|
|
57
|
-
return textXpath ? [{ key: "xpath by text", value: textXpath }] : [];
|
|
58
|
-
}
|
|
59
|
-
return [];
|
|
60
|
-
};
|
|
61
|
-
const buildPropertyStrategyXpaths = (element, isTarget, strategy, platform) => {
|
|
62
|
-
const xpaths = [];
|
|
63
|
-
const attributes = Array.from(element.attributes || []).filter((attribute) => attribute?.value && (0, xpathHelpers_js_1.checkBlockedAttributes)(attribute, element, isTarget));
|
|
64
|
-
const text = getNormalizedText(element);
|
|
65
|
-
const getStrategyXPath = strategy === "contains"
|
|
66
|
-
? xpathHelpers_js_1.getContainsPropertyXPath
|
|
67
|
-
: strategy === "startsWith"
|
|
68
|
-
? xpathHelpers_js_1.getStartsWithPropertyXPath
|
|
69
|
-
: strategy === "normalizeSpace"
|
|
70
|
-
? xpathHelpers_js_1.getNormalizedPropertyXPath
|
|
71
|
-
: null;
|
|
72
|
-
if (!getStrategyXPath) {
|
|
73
|
-
return xpaths;
|
|
74
|
-
}
|
|
75
|
-
attributes.forEach((attribute) => {
|
|
76
|
-
const xpath = getStrategyXPath(element, `@${attribute.name}`, attribute.value, platform);
|
|
77
|
-
if (xpath) {
|
|
78
|
-
xpaths.push({
|
|
79
|
-
key: `xpath by ${strategy} ${attribute.name}`,
|
|
80
|
-
value: xpath
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
});
|
|
84
|
-
if (text) {
|
|
85
|
-
const xpath = getStrategyXPath(element, ".", text, platform);
|
|
86
|
-
if (xpath) {
|
|
87
|
-
xpaths.push({
|
|
88
|
-
key: `xpath by ${strategy} text`,
|
|
89
|
-
value: xpath
|
|
90
|
-
});
|
|
32
|
+
const getCachedXPathCount = (xpath, element, doc) => {
|
|
33
|
+
try {
|
|
34
|
+
const cached = xpathCache.get(xpath);
|
|
35
|
+
if (cached !== undefined) {
|
|
36
|
+
return cached;
|
|
91
37
|
}
|
|
38
|
+
const count = (0, xpathHelpers_js_1.getAiCountOfXPath)(xpath, element, doc);
|
|
39
|
+
xpathCache.set(xpath, count);
|
|
40
|
+
return count;
|
|
92
41
|
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
const buildConditionStrategyXpaths = (element, docmt, isTarget, strategy, platform) => {
|
|
96
|
-
const attributes = Array.from(element.attributes || []).filter((attribute) => attribute?.value && (0, xpathHelpers_js_1.checkBlockedAttributes)(attribute, element, isTarget));
|
|
97
|
-
if (strategy === "and") {
|
|
98
|
-
const combinationXpath = (0, xpathHelpers_js_1.getAttributeCombinationXpath)(element, docmt, attributes, isTarget, platform);
|
|
99
|
-
return combinationXpath
|
|
100
|
-
? [{ key: "xpath by combination", value: combinationXpath }]
|
|
101
|
-
: [];
|
|
102
|
-
}
|
|
103
|
-
if (strategy === "or" && attributes.length >= 1) {
|
|
104
|
-
const xpath = (0, xpathHelpers_js_1.getOrAttributesXPath)(element, attributes, platform);
|
|
105
|
-
return xpath ? [{ key: "xpath by or", value: xpath }] : [];
|
|
42
|
+
catch {
|
|
43
|
+
return 0;
|
|
106
44
|
}
|
|
107
|
-
return [];
|
|
108
45
|
};
|
|
109
|
-
const
|
|
110
|
-
const
|
|
111
|
-
if (
|
|
112
|
-
return
|
|
113
|
-
const
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
const currentNode = queue.shift();
|
|
117
|
-
if (currentNode.classList?.contains("flntooltip")) {
|
|
118
|
-
continue;
|
|
119
|
-
}
|
|
120
|
-
nodes.push(currentNode);
|
|
121
|
-
queue.push(...Array.from(currentNode.children || []));
|
|
122
|
-
}
|
|
123
|
-
return nodes;
|
|
46
|
+
const getCachedTextContent = (element) => {
|
|
47
|
+
const cached = textContentCache.get(element);
|
|
48
|
+
if (cached !== undefined)
|
|
49
|
+
return cached;
|
|
50
|
+
const value = (0, xpathHelpers_js_1.getAiTextContent)(element);
|
|
51
|
+
textContentCache.set(element, value);
|
|
52
|
+
return value;
|
|
124
53
|
};
|
|
125
|
-
const
|
|
126
|
-
const
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
nodes.push(currentNode);
|
|
133
|
-
}
|
|
134
|
-
currentNode =
|
|
135
|
-
direction === "previous"
|
|
136
|
-
? currentNode.previousElementSibling
|
|
137
|
-
: currentNode.nextElementSibling;
|
|
138
|
-
}
|
|
139
|
-
return nodes;
|
|
140
|
-
};
|
|
141
|
-
const getDirectionalAxisSeedNodes = (element, direction) => {
|
|
142
|
-
const nodes = [];
|
|
143
|
-
for (let currentNode = element; currentNode?.parentElement; currentNode = currentNode.parentElement) {
|
|
144
|
-
let sibling = direction === "previous"
|
|
145
|
-
? currentNode.previousElementSibling
|
|
146
|
-
: currentNode.nextElementSibling;
|
|
147
|
-
while (sibling) {
|
|
148
|
-
if (!sibling.classList?.contains("flntooltip")) {
|
|
149
|
-
nodes.push(sibling);
|
|
150
|
-
nodes.push({
|
|
151
|
-
node: sibling,
|
|
152
|
-
expand: () => collectSubtreeElements(sibling)
|
|
153
|
-
});
|
|
154
|
-
}
|
|
155
|
-
sibling =
|
|
156
|
-
direction === "previous"
|
|
157
|
-
? sibling.previousElementSibling
|
|
158
|
-
: sibling.nextElementSibling;
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
return nodes;
|
|
54
|
+
const getCachedFilteredText = (element) => {
|
|
55
|
+
const cached = filteredTextCache.get(element);
|
|
56
|
+
if (cached !== undefined)
|
|
57
|
+
return cached;
|
|
58
|
+
const value = (0, xpathHelpers_js_1.getAiFilteredText)(element);
|
|
59
|
+
filteredTextCache.set(element, value);
|
|
60
|
+
return value;
|
|
162
61
|
};
|
|
163
|
-
const
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
return true;
|
|
167
|
-
const text = node.textContent?.trim();
|
|
168
|
-
return (!node.id &&
|
|
169
|
-
!node.className &&
|
|
170
|
-
node.attributes.length === 0 &&
|
|
171
|
-
(!text || text.length > 60) &&
|
|
172
|
-
node.children.length > 2);
|
|
173
|
-
};
|
|
174
|
-
const buildAxisXpathsForNodes = (nodes, axis, targetElement, docmt, isTarget, key, isIndex, platform) => {
|
|
175
|
-
const targetNodeTest = (0, xpathHelpers_js_1.getAxisNodeTest)(targetElement, platform);
|
|
176
|
-
const MAX_INDEX_TRY = 3;
|
|
177
|
-
const MAX_CANDIDATES = 5;
|
|
178
|
-
const candidates = [];
|
|
179
|
-
let processed = 0;
|
|
180
|
-
const MAX_PROCESS = axis.includes("descendant") ? 10 : 20;
|
|
181
|
-
for (const nodeItem of nodes) {
|
|
182
|
-
if (processed++ > MAX_PROCESS)
|
|
183
|
-
break;
|
|
184
|
-
if (candidates.length >= MAX_CANDIDATES)
|
|
185
|
-
break;
|
|
186
|
-
const node = "node" in nodeItem ? nodeItem.node : nodeItem;
|
|
187
|
-
const view = node.ownerDocument?.defaultView;
|
|
188
|
-
if (!view || !(node instanceof view.Element))
|
|
189
|
-
continue;
|
|
190
|
-
if (isLowQualityNode(node))
|
|
191
|
-
continue;
|
|
192
|
-
const anchorStages = [
|
|
193
|
-
() => (0, xpathHelpers_js_1.getUniqueNodeAnchorXpaths)(node, docmt, isTarget, platform),
|
|
194
|
-
() => {
|
|
195
|
-
const anchors = [];
|
|
196
|
-
const element = node;
|
|
197
|
-
const attributes = Array.from(element.attributes || []).filter((attr) => attr.value &&
|
|
198
|
-
!/\d/.test(attr.value) &&
|
|
199
|
-
(0, xpathHelpers_js_1.checkBlockedAttributes)(attr, element, isTarget));
|
|
200
|
-
for (const attr of attributes) {
|
|
201
|
-
const value = attr.value;
|
|
202
|
-
if (!value)
|
|
203
|
-
continue;
|
|
204
|
-
const containsXpath = (0, xpathHelpers_js_1.getContainsPropertyXPath)(node, `@${attr.name}`, value, platform);
|
|
205
|
-
if (containsXpath) {
|
|
206
|
-
anchors.push({ key: "contains", value: containsXpath });
|
|
207
|
-
}
|
|
208
|
-
const startsWithXpath = (0, xpathHelpers_js_1.getStartsWithPropertyXPath)(node, `@${attr.name}`, value, platform);
|
|
209
|
-
if (startsWithXpath) {
|
|
210
|
-
anchors.push({ key: "starts-with", value: startsWithXpath });
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
return anchors;
|
|
214
|
-
},
|
|
215
|
-
() => [{ key: "tag", value: (0, xpathHelpers_js_1.getTagOnlyXPath)(node, platform, docmt) }]
|
|
216
|
-
];
|
|
217
|
-
for (let stageIndex = 0; stageIndex < anchorStages.length; stageIndex++) {
|
|
218
|
-
let anchors = anchorStages[stageIndex]();
|
|
219
|
-
if (!anchors.length)
|
|
220
|
-
continue;
|
|
221
|
-
if (!isIndex) {
|
|
222
|
-
anchors = anchors.filter((a) => !/\[\d+\]/.test(a.value));
|
|
223
|
-
}
|
|
224
|
-
const seen = new Set();
|
|
225
|
-
anchors = anchors.filter((a) => {
|
|
226
|
-
if (seen.has(a.value))
|
|
227
|
-
return false;
|
|
228
|
-
seen.add(a.value);
|
|
229
|
-
return true;
|
|
230
|
-
});
|
|
231
|
-
anchors = anchors.slice(0, 5);
|
|
232
|
-
for (const anchor of anchors) {
|
|
233
|
-
const xpath = `${anchor.value}/${axis}::${targetNodeTest}`;
|
|
234
|
-
if ((0, xpathHelpers_js_1.isExactUniqueXpath)(xpath, targetElement, docmt)) {
|
|
235
|
-
candidates.push({ key, value: xpath });
|
|
236
|
-
if (candidates.length >= 2) {
|
|
237
|
-
return candidates;
|
|
238
|
-
}
|
|
239
|
-
if (candidates.length >= MAX_CANDIDATES) {
|
|
240
|
-
return candidates;
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
if (isIndex && stageIndex === anchorStages.length - 1) {
|
|
245
|
-
for (const anchor of anchors) {
|
|
246
|
-
const count = (0, xpathHelpers_js_1.getCountOfXPath)(anchor.value, node, docmt);
|
|
247
|
-
for (let i = 1; i <= Math.min(count, MAX_INDEX_TRY); i++) {
|
|
248
|
-
const xpath = `(${anchor.value})[${i}]/${axis}::${targetNodeTest}`;
|
|
249
|
-
if ((0, xpathHelpers_js_1.isExactUniqueXpath)(xpath, targetElement, docmt)) {
|
|
250
|
-
candidates.push({ key, value: xpath });
|
|
251
|
-
if (candidates.length >= 2) {
|
|
252
|
-
return candidates;
|
|
253
|
-
}
|
|
254
|
-
if (candidates.length >= MAX_CANDIDATES) {
|
|
255
|
-
return candidates;
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
if ("expand" in nodeItem && nodeItem.expand) {
|
|
263
|
-
const expanded = nodeItem.expand();
|
|
264
|
-
let childCount = 0;
|
|
265
|
-
for (const child of expanded) {
|
|
266
|
-
if (childCount++ > 15)
|
|
267
|
-
break;
|
|
268
|
-
if (candidates.length >= MAX_CANDIDATES)
|
|
269
|
-
break;
|
|
270
|
-
const view = child.ownerDocument?.defaultView;
|
|
271
|
-
if (!view || !(child instanceof view.Element))
|
|
272
|
-
continue;
|
|
273
|
-
if (isLowQualityNode(child))
|
|
274
|
-
continue;
|
|
275
|
-
const anchors = (0, xpathHelpers_js_1.getUniqueNodeAnchorXpaths)(child, docmt, isTarget, platform);
|
|
276
|
-
for (const anchor of anchors.slice(0, 5)) {
|
|
277
|
-
const xpath = `${anchor.value}/${axis}::${targetNodeTest}`;
|
|
278
|
-
if ((0, xpathHelpers_js_1.isExactUniqueXpath)(xpath, targetElement, docmt)) {
|
|
279
|
-
candidates.push({ key, value: xpath });
|
|
280
|
-
if (candidates.length >= 2) {
|
|
281
|
-
return candidates;
|
|
282
|
-
}
|
|
283
|
-
if (candidates.length >= MAX_CANDIDATES) {
|
|
284
|
-
return candidates;
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
return candidates;
|
|
292
|
-
};
|
|
293
|
-
const buildAxesStrategyXpaths = (element, docmt, isTarget, isIndex, platform) => {
|
|
294
|
-
const ancestors = [];
|
|
295
|
-
for (let currentNode = element.parentElement; currentNode; currentNode = currentNode.parentElement) {
|
|
296
|
-
ancestors.push(currentNode);
|
|
297
|
-
}
|
|
298
|
-
const descendants = collectSubtreeElements(element);
|
|
299
|
-
const previousSiblings = getSiblingNodes(element, "previous");
|
|
300
|
-
const nextSiblings = getSiblingNodes(element, "next");
|
|
301
|
-
const precedingSeeds = getDirectionalAxisSeedNodes(element, "previous");
|
|
302
|
-
const followingSeeds = getDirectionalAxisSeedNodes(element, "next");
|
|
303
|
-
const limitNodes = (nodes, limit = 20) => {
|
|
304
|
-
return nodes.length > limit ? nodes.slice(0, limit) : nodes;
|
|
305
|
-
};
|
|
306
|
-
const tiers = [
|
|
307
|
-
[
|
|
308
|
-
{
|
|
309
|
-
nodes: limitNodes(nextSiblings),
|
|
310
|
-
axis: "preceding-sibling",
|
|
311
|
-
key: "preceding-sibling"
|
|
312
|
-
},
|
|
313
|
-
{
|
|
314
|
-
nodes: limitNodes(previousSiblings),
|
|
315
|
-
axis: "following-sibling",
|
|
316
|
-
key: "following-sibling"
|
|
317
|
-
}
|
|
318
|
-
],
|
|
319
|
-
[
|
|
320
|
-
{ nodes: limitNodes(ancestors), axis: "child", key: "child" },
|
|
321
|
-
{
|
|
322
|
-
nodes: limitNodes(descendants, 15),
|
|
323
|
-
axis: "parent",
|
|
324
|
-
key: "parent"
|
|
325
|
-
}
|
|
326
|
-
],
|
|
327
|
-
[
|
|
328
|
-
{ nodes: limitNodes(ancestors), axis: "descendant", key: "descendant" },
|
|
329
|
-
{
|
|
330
|
-
nodes: limitNodes(ancestors),
|
|
331
|
-
axis: "descendant-or-self",
|
|
332
|
-
key: "descendant-or-self"
|
|
333
|
-
},
|
|
334
|
-
{
|
|
335
|
-
nodes: limitNodes(descendants, 10),
|
|
336
|
-
axis: "ancestor",
|
|
337
|
-
key: "ancestor"
|
|
338
|
-
},
|
|
339
|
-
{
|
|
340
|
-
nodes: limitNodes(descendants, 10),
|
|
341
|
-
axis: "ancestor-or-self",
|
|
342
|
-
key: "ancestor-or-self"
|
|
343
|
-
}
|
|
344
|
-
],
|
|
345
|
-
[
|
|
346
|
-
{
|
|
347
|
-
nodes: limitNodes(precedingSeeds),
|
|
348
|
-
axis: "following",
|
|
349
|
-
key: "following"
|
|
350
|
-
},
|
|
351
|
-
{ nodes: limitNodes(followingSeeds), axis: "preceding", key: "preceding" }
|
|
352
|
-
]
|
|
353
|
-
];
|
|
354
|
-
for (const tier of tiers) {
|
|
355
|
-
for (const strategy of tier) {
|
|
356
|
-
const results = buildAxisXpathsForNodes(strategy.nodes, strategy.axis, element, docmt, isTarget, strategy.key, isIndex, platform);
|
|
357
|
-
if (results.length > 0) {
|
|
358
|
-
return results;
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
return [];
|
|
363
|
-
};
|
|
364
|
-
const generateIndexedXpaths = (element, docmt, platform) => {
|
|
365
|
-
const results = [];
|
|
366
|
-
const tag = platform === "web"
|
|
367
|
-
? element.tagName.toLowerCase()
|
|
368
|
-
: element.tagName;
|
|
369
|
-
const globalList = Array.from(docmt.querySelectorAll(tag));
|
|
370
|
-
const idx = globalList.indexOf(element) + 1;
|
|
371
|
-
if (idx <= 0)
|
|
372
|
-
return [];
|
|
373
|
-
results.push({
|
|
374
|
-
key: "xpath by index",
|
|
375
|
-
value: `(//${tag})[${idx}]`
|
|
376
|
-
});
|
|
377
|
-
let current = element.parentElement;
|
|
378
|
-
while (current && current !== docmt.body) {
|
|
379
|
-
if (current.id || current.className) {
|
|
380
|
-
const cls = current.className
|
|
381
|
-
?.toString()
|
|
382
|
-
.split(" ")
|
|
383
|
-
.map((name) => name.trim())
|
|
384
|
-
.find(Boolean);
|
|
385
|
-
const tagName = platform === "web"
|
|
386
|
-
? current.tagName.toLowerCase()
|
|
387
|
-
: current.tagName;
|
|
388
|
-
const scopeXpath = current.id
|
|
389
|
-
? `//${tagName}[@id='${current.id}']`
|
|
390
|
-
: cls
|
|
391
|
-
? `//${tagName}[contains(@class,'${cls}')]`
|
|
392
|
-
: "";
|
|
393
|
-
if (!scopeXpath) {
|
|
394
|
-
current = current.parentElement;
|
|
395
|
-
continue;
|
|
396
|
-
}
|
|
397
|
-
const scopedDescendants = Array.from(current.querySelectorAll(tag));
|
|
398
|
-
const scopedIdx = scopedDescendants.indexOf(element) + 1;
|
|
399
|
-
if (scopedIdx > 0) {
|
|
400
|
-
results.push({
|
|
401
|
-
key: "xpath by index",
|
|
402
|
-
value: `(${scopeXpath}//${tag})[${scopedIdx}]`
|
|
403
|
-
});
|
|
404
|
-
break;
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
current = current.parentElement;
|
|
408
|
-
}
|
|
409
|
-
return results;
|
|
410
|
-
};
|
|
411
|
-
exports.generateIndexedXpaths = generateIndexedXpaths;
|
|
412
|
-
const buildStrategyXpaths = (element, docmt, isTarget, strategy, platform) => {
|
|
413
|
-
const strategyName = getStrategyName(strategy);
|
|
414
|
-
if (strategyName === "text") {
|
|
415
|
-
return withStrategyKey(strategy, buildTextStrategyXpaths(element, docmt, strategyName, platform));
|
|
416
|
-
}
|
|
417
|
-
if (["contains", "startsWith", "normalizeSpace"].includes(strategyName)) {
|
|
418
|
-
return withStrategyKey(strategy, buildPropertyStrategyXpaths(element, isTarget, strategyName, platform));
|
|
419
|
-
}
|
|
420
|
-
if (["and", "or"].includes(strategyName)) {
|
|
421
|
-
return withStrategyKey(strategy, buildConditionStrategyXpaths(element, docmt, isTarget, strategyName, platform));
|
|
422
|
-
}
|
|
423
|
-
if (strategyName === "axes") {
|
|
424
|
-
return withStrategyKey(strategy, buildAxesStrategyXpaths(element, docmt, isTarget, false, platform));
|
|
425
|
-
}
|
|
426
|
-
if (strategyName === "index") {
|
|
427
|
-
return withStrategyKey(strategy, (0, exports.generateIndexedXpaths)(element, docmt, platform));
|
|
428
|
-
}
|
|
429
|
-
if (strategyName === "tag") {
|
|
430
|
-
return withStrategyKey(strategy, [
|
|
431
|
-
{ key: "xpath till tag", value: (0, xpathHelpers_js_1.getTagOnlyXPath)(element, platform, docmt) }
|
|
432
|
-
]);
|
|
62
|
+
const checkAiRelativeXpathRelation = (nodeXpath1, nodeXpath2, targetElemt, docmt, relationType) => {
|
|
63
|
+
if (hasReachedRelativeXpathLimit()) {
|
|
64
|
+
return;
|
|
433
65
|
}
|
|
434
|
-
return [];
|
|
435
|
-
};
|
|
436
|
-
const checkRelativeXpathRelation = (nodeXpath1, nodeXpath2, targetElemt, docmt, isIndex, relationType) => {
|
|
437
66
|
if (nodeXpath1 && !referenceElementMode) {
|
|
438
67
|
let xpaths;
|
|
439
68
|
if (relationType === "parent") {
|
|
@@ -453,49 +82,18 @@ const checkRelativeXpathRelation = (nodeXpath1, nodeXpath2, targetElemt, docmt,
|
|
|
453
82
|
// Check if result is already cached to avoid recomputation
|
|
454
83
|
if (!xpathCache?.get(xpath)) {
|
|
455
84
|
// Compute and store result in cache
|
|
456
|
-
xpathCache.set(xpath, (
|
|
85
|
+
xpathCache.set(xpath, getCachedXPathCount(xpath, targetElemt, docmt));
|
|
457
86
|
}
|
|
458
87
|
const count = xpathCache?.get(xpath);
|
|
459
88
|
// Short-circuit: Return the first valid XPath result found
|
|
460
89
|
if (count === 1) {
|
|
461
90
|
return xpath;
|
|
462
91
|
}
|
|
463
|
-
if (count > 1) {
|
|
464
|
-
if (xpathDataWithIndex.length) {
|
|
465
|
-
if (count < xpathDataWithIndex[0].count) {
|
|
466
|
-
xpathDataWithIndex.pop();
|
|
467
|
-
xpathDataWithIndex.push({
|
|
468
|
-
key: `relative xpath by unique parent ${isIndex ? "index" : ""}`,
|
|
469
|
-
value: xpath,
|
|
470
|
-
count
|
|
471
|
-
});
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
else {
|
|
475
|
-
xpathDataWithIndex.push({
|
|
476
|
-
key: `relative xpath by unique parent ${isIndex ? "index" : ""}`,
|
|
477
|
-
value: xpath,
|
|
478
|
-
count
|
|
479
|
-
});
|
|
480
|
-
}
|
|
481
|
-
}
|
|
482
|
-
if (count > 1 && isIndex && !xpathData.length) {
|
|
483
|
-
// Try finding XPath with index if count is greater than 1
|
|
484
|
-
const indexedXpath = (0, xpathHelpers_js_1.findXpathWithIndex)(xpath, targetElemt, docmt, count);
|
|
485
|
-
// Cache the indexed XPath result
|
|
486
|
-
if (indexedXpath &&
|
|
487
|
-
(0, xpathHelpers_js_1.getCountOfXPath)(indexedXpath, targetElemt, docmt) === 1) {
|
|
488
|
-
xpathData.push({
|
|
489
|
-
key: `relative xpath by unique parent ${isIndex ? "index" : ""}`,
|
|
490
|
-
value: indexedXpath
|
|
491
|
-
});
|
|
492
|
-
}
|
|
493
|
-
}
|
|
494
92
|
}
|
|
495
93
|
}
|
|
496
94
|
return null;
|
|
497
95
|
};
|
|
498
|
-
const
|
|
96
|
+
const getAiUniqueParentXpath = (domNode, docmt, node, isTarget, nodeXpath, _platform) => {
|
|
499
97
|
try {
|
|
500
98
|
if (parentXpathCache.has(domNode)) {
|
|
501
99
|
return parentXpathCache.get(domNode);
|
|
@@ -504,19 +102,38 @@ const getUniqueParentXpath = (domNode, docmt, node, isTarget, nodeXpath, isIndex
|
|
|
504
102
|
const xpathParts = [];
|
|
505
103
|
let currentNode = domNode;
|
|
506
104
|
while (currentNode && currentNode.nodeType === 1) {
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
105
|
+
if (hasReachedRelativeXpathLimit()) {
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
const PRIORITY = [
|
|
109
|
+
"id",
|
|
110
|
+
"name",
|
|
111
|
+
"data-testid",
|
|
112
|
+
"data-test",
|
|
113
|
+
"aria-label",
|
|
114
|
+
"placeholder",
|
|
115
|
+
"class"
|
|
116
|
+
];
|
|
117
|
+
const attrs = Array
|
|
118
|
+
.from(currentNode.attributes)
|
|
119
|
+
.sort((a, b) => {
|
|
120
|
+
const ai = PRIORITY.indexOf(a.name);
|
|
121
|
+
const bi = PRIORITY.indexOf(b.name);
|
|
122
|
+
return (ai == -1 ? 999 : ai) - (bi == -1 ? 999 : bi);
|
|
123
|
+
})
|
|
124
|
+
.slice(0, 3);
|
|
125
|
+
for (const attrName of attrs) {
|
|
126
|
+
if ((0, xpathHelpers_js_1.checkAiBlockedAttributes)(attrName, currentNode, isTarget)) {
|
|
127
|
+
const attrValue = (0, xpathHelpers_js_1.sanitizeAiAttributeValue)(attrName.name, attrName.nodeValue);
|
|
511
128
|
const elementName = attrName.name;
|
|
512
|
-
const xpathe = (0, xpathHelpers_js_1.
|
|
129
|
+
const xpathe = (0, xpathHelpers_js_1.getAiXpathString)(currentNode, elementName, attrValue);
|
|
513
130
|
let othersWithAttr;
|
|
514
131
|
// If the XPath does not parse, move to the next unique attribute
|
|
515
132
|
try {
|
|
516
|
-
othersWithAttr =
|
|
133
|
+
othersWithAttr = checkAiRelativeXpathRelation(xpathe, nodeXpath, node, docmt, "parent");
|
|
517
134
|
}
|
|
518
135
|
catch (ign) {
|
|
519
|
-
logData_js_1.logger.error("error in
|
|
136
|
+
logData_js_1.logger.error("error in getAiUniqueParentXpath", ign);
|
|
520
137
|
continue;
|
|
521
138
|
}
|
|
522
139
|
// If the attribute isn't actually unique, get it's index too
|
|
@@ -525,21 +142,22 @@ const getUniqueParentXpath = (domNode, docmt, node, isTarget, nodeXpath, isIndex
|
|
|
525
142
|
}
|
|
526
143
|
}
|
|
527
144
|
}
|
|
528
|
-
|
|
145
|
+
const text = getCachedFilteredText(currentNode);
|
|
146
|
+
if (text) {
|
|
529
147
|
if (!isTarget ||
|
|
530
|
-
(isTarget && !(0, xpathHelpers_js_1.
|
|
148
|
+
(isTarget && !(0, xpathHelpers_js_1.isAiNumberExist)(text))) {
|
|
531
149
|
let xpathe;
|
|
532
150
|
if (!xpathHelpers_js_1.reWhiteSpace.test(currentNode.textContent)) {
|
|
533
|
-
xpathe = (0, xpathHelpers_js_1.
|
|
534
|
-
? `//*[local-name()='${currentNode.tagName}' and normalize-space(.)=${(0, xpathHelpers_js_1.
|
|
535
|
-
: `//${currentNode.tagName || "*"}[normalize-space(.)=${(0, xpathHelpers_js_1.
|
|
151
|
+
xpathe = (0, xpathHelpers_js_1.isAiSvg)(currentNode)
|
|
152
|
+
? `//*[local-name()='${currentNode.tagName}' and normalize-space(.)=${(0, xpathHelpers_js_1.escapeAiCharacters)(getCachedFilteredText(currentNode))}]`
|
|
153
|
+
: `//${currentNode.tagName || "*"}[normalize-space(.)=${(0, xpathHelpers_js_1.escapeAiCharacters)(getCachedFilteredText(currentNode))}]`;
|
|
536
154
|
}
|
|
537
155
|
else {
|
|
538
|
-
xpathe = (0, xpathHelpers_js_1.
|
|
539
|
-
? `//*[local-name()='${currentNode.tagName}' and .=${(0, xpathHelpers_js_1.
|
|
540
|
-
: `//${currentNode.tagName || "*"}[.=${(0, xpathHelpers_js_1.
|
|
156
|
+
xpathe = (0, xpathHelpers_js_1.isAiSvg)(currentNode)
|
|
157
|
+
? `//*[local-name()='${currentNode.tagName}' and .=${(0, xpathHelpers_js_1.escapeAiCharacters)(getCachedFilteredText(currentNode))}]`
|
|
158
|
+
: `//${currentNode.tagName || "*"}[.=${(0, xpathHelpers_js_1.escapeAiCharacters)(getCachedFilteredText(currentNode))}]`;
|
|
541
159
|
}
|
|
542
|
-
const othersWithAttr =
|
|
160
|
+
const othersWithAttr = checkAiRelativeXpathRelation(xpathe, nodeXpath, node, docmt, "parent");
|
|
543
161
|
if (othersWithAttr) {
|
|
544
162
|
return othersWithAttr;
|
|
545
163
|
}
|
|
@@ -547,26 +165,26 @@ const getUniqueParentXpath = (domNode, docmt, node, isTarget, nodeXpath, isIndex
|
|
|
547
165
|
else {
|
|
548
166
|
const combinePattern = [];
|
|
549
167
|
const contentRes = [
|
|
550
|
-
...new Set((
|
|
168
|
+
...new Set(getCachedFilteredText(currentNode).match(/([^0-9]+)/g))
|
|
551
169
|
];
|
|
552
170
|
const reWhiteSpace = new RegExp(/^[\S]+( [\S]+)*$/gi);
|
|
553
171
|
if (contentRes?.length) {
|
|
554
172
|
for (let i = 0; i < contentRes?.length; i++) {
|
|
555
|
-
if (contentRes[i] && (0, xpathHelpers_js_1.
|
|
173
|
+
if (contentRes[i] && (0, xpathHelpers_js_1.aiReplaceWhiteSpaces)(contentRes[i].trim())) {
|
|
556
174
|
if (!reWhiteSpace.test(contentRes[i])) {
|
|
557
|
-
combinePattern.push(`contains(.,${(0, xpathHelpers_js_1.
|
|
175
|
+
combinePattern.push(`contains(.,${(0, xpathHelpers_js_1.escapeAiCharacters)((0, xpathHelpers_js_1.aiReplaceWhiteSpaces)(contentRes[i])).trim()})`);
|
|
558
176
|
}
|
|
559
177
|
else {
|
|
560
|
-
combinePattern.push(`contains(.,${(0, xpathHelpers_js_1.
|
|
178
|
+
combinePattern.push(`contains(.,${(0, xpathHelpers_js_1.escapeAiCharacters)(contentRes[i].trim()).trim()})`);
|
|
561
179
|
}
|
|
562
180
|
}
|
|
563
181
|
}
|
|
564
182
|
}
|
|
565
183
|
if (combinePattern?.length) {
|
|
566
|
-
const xpathe = (0, xpathHelpers_js_1.
|
|
184
|
+
const xpathe = (0, xpathHelpers_js_1.isAiSvg)(currentNode)
|
|
567
185
|
? `//*[local-name()='${currentNode.tagName}' and ${combinePattern.join(" and ")}]`
|
|
568
186
|
: `//${currentNode.tagName || "*"}[${combinePattern.join(" and ")}]`;
|
|
569
|
-
const othersWithAttr =
|
|
187
|
+
const othersWithAttr = checkAiRelativeXpathRelation(xpathe, nodeXpath, node, docmt, "parent");
|
|
570
188
|
if (othersWithAttr) {
|
|
571
189
|
return othersWithAttr;
|
|
572
190
|
}
|
|
@@ -574,28 +192,16 @@ const getUniqueParentXpath = (domNode, docmt, node, isTarget, nodeXpath, isIndex
|
|
|
574
192
|
}
|
|
575
193
|
}
|
|
576
194
|
// Construct the XPath based on the tag name
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
if (xpath) {
|
|
582
|
-
return xpath;
|
|
583
|
-
}
|
|
584
|
-
}
|
|
585
|
-
const xpathe = (0, xpathHelpers_js_1.isSvg)(currentNode)
|
|
586
|
-
? `/*[local-name()='${currentNode.tagName}']`
|
|
587
|
-
: `/${currentNode.tagName}`;
|
|
588
|
-
xpathParts.unshift(xpathe);
|
|
589
|
-
}
|
|
590
|
-
else {
|
|
591
|
-
break;
|
|
592
|
-
}
|
|
195
|
+
const xpathe = (0, xpathHelpers_js_1.isAiSvg)(currentNode)
|
|
196
|
+
? `/*[local-name()='${currentNode.tagName}']`
|
|
197
|
+
: `/${currentNode.tagName}`;
|
|
198
|
+
xpathParts.unshift(xpathe);
|
|
593
199
|
// Move to the parent node for the next iteration
|
|
594
200
|
currentNode = currentNode.parentElement;
|
|
595
201
|
}
|
|
596
202
|
// Final constructed XPath
|
|
597
203
|
const finalXPath = xpathParts.join("") + nodeXpath;
|
|
598
|
-
const count = (
|
|
204
|
+
const count = getCachedXPathCount(finalXPath, domNode, docmt);
|
|
599
205
|
if (count === 1) {
|
|
600
206
|
parentXpathCache.set(domNode, finalXPath); // Cache final result
|
|
601
207
|
return finalXPath;
|
|
@@ -606,33 +212,52 @@ const getUniqueParentXpath = (domNode, docmt, node, isTarget, nodeXpath, isIndex
|
|
|
606
212
|
return null;
|
|
607
213
|
}
|
|
608
214
|
};
|
|
609
|
-
const
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
return cache.get(domNode); // Return cached result if available
|
|
215
|
+
const getAiParentRelativeXpath = (domNode, docmt, node, isTarget, _platform) => {
|
|
216
|
+
if (parentRelativeCache.has(domNode)) {
|
|
217
|
+
return parentRelativeCache.get(domNode); // Return cached result if available
|
|
613
218
|
}
|
|
614
219
|
const xpathParts = []; // Initialize an array to hold parts of the XPath
|
|
615
220
|
let currentNode = domNode; // Start with the provided DOM node
|
|
616
221
|
try {
|
|
617
222
|
while (currentNode && currentNode.nodeType === 1) {
|
|
223
|
+
if (hasReachedRelativeXpathLimit()) {
|
|
224
|
+
return null;
|
|
225
|
+
}
|
|
618
226
|
// BASE CASE #1: If this isn't an element, we're above the root, return empty string
|
|
619
227
|
if (!currentNode.tagName) {
|
|
620
228
|
return "";
|
|
621
229
|
}
|
|
622
230
|
// BASE CASE #2: Check for unique attributes
|
|
623
231
|
let uniqueAttrFound = false;
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
232
|
+
const PRIORITY = [
|
|
233
|
+
"id",
|
|
234
|
+
"name",
|
|
235
|
+
"data-testid",
|
|
236
|
+
"data-test",
|
|
237
|
+
"aria-label",
|
|
238
|
+
"placeholder",
|
|
239
|
+
"class"
|
|
240
|
+
];
|
|
241
|
+
const attrs = Array
|
|
242
|
+
.from(currentNode.attributes)
|
|
243
|
+
.sort((a, b) => {
|
|
244
|
+
const ai = PRIORITY.indexOf(a.name);
|
|
245
|
+
const bi = PRIORITY.indexOf(b.name);
|
|
246
|
+
return (ai == -1 ? 999 : ai) - (bi == -1 ? 999 : bi);
|
|
247
|
+
})
|
|
248
|
+
.slice(0, 3);
|
|
249
|
+
for (const attr of attrs) {
|
|
250
|
+
if ((0, xpathHelpers_js_1.checkAiBlockedAttributes)(attr, currentNode, isTarget)) {
|
|
251
|
+
const attrValue = (0, xpathHelpers_js_1.sanitizeAiAttributeValue)(attr.name, attr.nodeValue);
|
|
627
252
|
const elementName = attr.name;
|
|
628
|
-
const xpathe = (0, xpathHelpers_js_1.
|
|
253
|
+
const xpathe = (0, xpathHelpers_js_1.getAiXpathString)(currentNode, elementName, attrValue);
|
|
629
254
|
let othersWithAttr;
|
|
630
255
|
// If the XPath does not parse, move to the next unique attribute
|
|
631
256
|
try {
|
|
632
|
-
othersWithAttr = (
|
|
257
|
+
othersWithAttr = getCachedXPathCount(xpathe, currentNode, docmt);
|
|
633
258
|
}
|
|
634
259
|
catch (ign) {
|
|
635
|
-
logData_js_1.logger.error("error in
|
|
260
|
+
logData_js_1.logger.error("error in getAiParentRelativeXpath", ign);
|
|
636
261
|
continue;
|
|
637
262
|
}
|
|
638
263
|
// If the attribute is unique, return its XPath
|
|
@@ -644,10 +269,10 @@ const getParentRelativeXpath = (domNode, docmt, node, isTarget, platform) => {
|
|
|
644
269
|
}
|
|
645
270
|
}
|
|
646
271
|
// If no unique attributes, check for text content
|
|
647
|
-
if (!uniqueAttrFound && currentNode.textContent && !node.textContent) {
|
|
648
|
-
const textXPath = (0, xpathHelpers_js_1.
|
|
272
|
+
if (!uniqueAttrFound && !currentNode.textContent && !node.textContent) {
|
|
273
|
+
const textXPath = (0, xpathHelpers_js_1.getAiFilteredTextXPath)(currentNode);
|
|
649
274
|
if (textXPath) {
|
|
650
|
-
const othersWithAttr = (
|
|
275
|
+
const othersWithAttr = getCachedXPathCount(textXPath, currentNode, docmt);
|
|
651
276
|
if (othersWithAttr === 1) {
|
|
652
277
|
uniqueAttrFound = true; // Mark that we found at least one unique attribute
|
|
653
278
|
xpathParts.unshift(textXPath);
|
|
@@ -656,14 +281,8 @@ const getParentRelativeXpath = (domNode, docmt, node, isTarget, platform) => {
|
|
|
656
281
|
}
|
|
657
282
|
}
|
|
658
283
|
if (!uniqueAttrFound) {
|
|
659
|
-
const fallback = (0, xpathHelpers_js_1.getPlatformFallbackXpath)(currentNode, platform);
|
|
660
|
-
if (fallback) {
|
|
661
|
-
xpathParts.push(fallback);
|
|
662
|
-
uniqueAttrFound = true;
|
|
663
|
-
break;
|
|
664
|
-
}
|
|
665
284
|
// Construct the XPath based on the tag name
|
|
666
|
-
const xpathe = (0, xpathHelpers_js_1.
|
|
285
|
+
const xpathe = (0, xpathHelpers_js_1.isAiSvg)(currentNode)
|
|
667
286
|
? `/*[local-name()='${currentNode.tagName}']`
|
|
668
287
|
: `/${currentNode.tagName}`;
|
|
669
288
|
// Prepend the current XPath part to the array
|
|
@@ -685,7 +304,7 @@ const getParentRelativeXpath = (domNode, docmt, node, isTarget, platform) => {
|
|
|
685
304
|
return null;
|
|
686
305
|
}
|
|
687
306
|
};
|
|
688
|
-
const
|
|
307
|
+
const getAiChildRelativeXpath = (domNode, docmt, node) => {
|
|
689
308
|
const xpathParts = []; // Initialize an array to hold parts of the XPath.
|
|
690
309
|
let currentNode;
|
|
691
310
|
const st = [];
|
|
@@ -700,21 +319,45 @@ const getChildRelativeXpath = (domNode, docmt, node) => {
|
|
|
700
319
|
st.unshift(m.nextElementSibling);
|
|
701
320
|
}
|
|
702
321
|
try {
|
|
322
|
+
let processedNodes = 0;
|
|
703
323
|
do {
|
|
704
324
|
let uniqueAttrFound = false;
|
|
705
325
|
for (currentNode = st.pop(); currentNode !== null;) {
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
326
|
+
if (++processedNodes > 30) {
|
|
327
|
+
return null;
|
|
328
|
+
}
|
|
329
|
+
if (hasReachedRelativeXpathLimit()) {
|
|
330
|
+
return null;
|
|
331
|
+
}
|
|
332
|
+
const PRIORITY = [
|
|
333
|
+
"id",
|
|
334
|
+
"name",
|
|
335
|
+
"data-testid",
|
|
336
|
+
"data-test",
|
|
337
|
+
"aria-label",
|
|
338
|
+
"placeholder",
|
|
339
|
+
"class"
|
|
340
|
+
];
|
|
341
|
+
const attrs = Array
|
|
342
|
+
.from(currentNode.attributes)
|
|
343
|
+
.sort((a, b) => {
|
|
344
|
+
const ai = PRIORITY.indexOf(a.name);
|
|
345
|
+
const bi = PRIORITY.indexOf(b.name);
|
|
346
|
+
return (ai == -1 ? 999 : ai) - (bi == -1 ? 999 : bi);
|
|
347
|
+
})
|
|
348
|
+
.slice(0, 3);
|
|
349
|
+
for (const attr of attrs) {
|
|
350
|
+
if ((0, xpathHelpers_js_1.checkAiBlockedAttributes)(attr, currentNode, true)) {
|
|
351
|
+
const attrValue = (0, xpathHelpers_js_1.sanitizeAiAttributeValue)(attr.name, attr.nodeValue);
|
|
709
352
|
const elementName = attr.name;
|
|
710
|
-
const xpathe = (0, xpathHelpers_js_1.
|
|
353
|
+
const xpathe = (0, xpathHelpers_js_1.getAiXpathString)(currentNode, elementName, attrValue);
|
|
711
354
|
let othersWithAttr;
|
|
712
355
|
// If the XPath does not parse, move to the next unique attribute
|
|
713
356
|
try {
|
|
714
|
-
othersWithAttr = (
|
|
357
|
+
othersWithAttr = getCachedXPathCount(xpathe, currentNode, docmt);
|
|
715
358
|
}
|
|
716
359
|
catch (ign) {
|
|
717
|
-
logData_js_1.logger.error("error in
|
|
360
|
+
logData_js_1.logger.error("error in getAiChildRelativeXpath", ign);
|
|
718
361
|
continue;
|
|
719
362
|
}
|
|
720
363
|
// If the attribute is unique, return its XPath
|
|
@@ -727,9 +370,9 @@ const getChildRelativeXpath = (domNode, docmt, node) => {
|
|
|
727
370
|
}
|
|
728
371
|
// If no unique attributes, check for text content
|
|
729
372
|
if (!uniqueAttrFound && currentNode.textContent && !node.textContent) {
|
|
730
|
-
const textXPath = (0, xpathHelpers_js_1.
|
|
373
|
+
const textXPath = (0, xpathHelpers_js_1.getAiFilteredTextXPath)(currentNode);
|
|
731
374
|
if (textXPath) {
|
|
732
|
-
const othersWithAttr = (
|
|
375
|
+
const othersWithAttr = getCachedXPathCount(textXPath, currentNode, docmt);
|
|
733
376
|
if (othersWithAttr === 1) {
|
|
734
377
|
uniqueAttrFound = true; // Mark that we found at least one unique attribute
|
|
735
378
|
xpathParts.push(textXPath);
|
|
@@ -739,7 +382,7 @@ const getChildRelativeXpath = (domNode, docmt, node) => {
|
|
|
739
382
|
}
|
|
740
383
|
if (!uniqueAttrFound) {
|
|
741
384
|
// Construct the XPath based on the tag name
|
|
742
|
-
const xpathe = (0, xpathHelpers_js_1.
|
|
385
|
+
const xpathe = (0, xpathHelpers_js_1.isAiSvg)(currentNode)
|
|
743
386
|
? `/*[local-name()='${currentNode.tagName}']`
|
|
744
387
|
: `/${currentNode.tagName}`;
|
|
745
388
|
// Prepend the current XPath part to the array
|
|
@@ -763,121 +406,114 @@ const getChildRelativeXpath = (domNode, docmt, node) => {
|
|
|
763
406
|
return finalXpath;
|
|
764
407
|
}
|
|
765
408
|
catch (error) {
|
|
766
|
-
logData_js_1.logger.error("error in
|
|
409
|
+
logData_js_1.logger.error("error in getAiChildRelativeXpath", error);
|
|
767
410
|
return null;
|
|
768
411
|
}
|
|
769
412
|
};
|
|
770
|
-
const
|
|
413
|
+
const getAiSiblingRelativeXPath = (domNode, docmt, isTarget, nodeXpath, platform) => {
|
|
771
414
|
try {
|
|
772
|
-
const markedSpan =
|
|
415
|
+
const markedSpan = domNode.ownerDocument?.querySelector(".flntooltip");
|
|
773
416
|
for (let m = domNode.nextElementSibling; m !== null && m !== markedSpan; m = m.nextElementSibling) {
|
|
774
|
-
|
|
417
|
+
if (hasReachedRelativeXpathLimit()) {
|
|
418
|
+
return xpathData;
|
|
419
|
+
}
|
|
420
|
+
processAiSibling(m, domNode, docmt, nodeXpath, "preceding-sibling", isTarget, platform);
|
|
775
421
|
}
|
|
776
422
|
for (let n = domNode.previousElementSibling; n !== null && n !== markedSpan; n = n.previousElementSibling) {
|
|
777
|
-
|
|
423
|
+
if (hasReachedRelativeXpathLimit()) {
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
426
|
+
processAiSibling(n, domNode, docmt, nodeXpath, "following-sibling", isTarget, platform);
|
|
778
427
|
}
|
|
779
428
|
}
|
|
780
|
-
catch
|
|
781
|
-
console.error("sibling error", error);
|
|
429
|
+
catch {
|
|
782
430
|
return null;
|
|
783
431
|
}
|
|
784
432
|
};
|
|
785
|
-
const
|
|
433
|
+
const processAiSibling = (sibling, domNode, docmt, nodeXpath, axis, isTarget, _platform) => {
|
|
786
434
|
try {
|
|
435
|
+
if (hasReachedRelativeXpathLimit()) {
|
|
436
|
+
return;
|
|
437
|
+
}
|
|
787
438
|
if (sibling.hasAttributes()) {
|
|
788
|
-
|
|
789
|
-
|
|
439
|
+
const PRIORITY = [
|
|
440
|
+
"id",
|
|
441
|
+
"name",
|
|
442
|
+
"data-testid",
|
|
443
|
+
"data-test",
|
|
444
|
+
"aria-label",
|
|
445
|
+
"placeholder",
|
|
446
|
+
"class"
|
|
447
|
+
];
|
|
448
|
+
const attrs = Array
|
|
449
|
+
.from(sibling.attributes)
|
|
450
|
+
.sort((a, b) => {
|
|
451
|
+
const ai = PRIORITY.indexOf(a.name);
|
|
452
|
+
const bi = PRIORITY.indexOf(b.name);
|
|
453
|
+
return (ai == -1 ? 999 : ai) - (bi == -1 ? 999 : bi);
|
|
454
|
+
})
|
|
455
|
+
.slice(0, 3);
|
|
456
|
+
for (const attr of attrs) {
|
|
457
|
+
if (hasReachedRelativeXpathLimit()) {
|
|
458
|
+
return;
|
|
459
|
+
}
|
|
460
|
+
let xpathe = (0, xpathHelpers_js_1.intermediateAiXpathStep)(sibling, {
|
|
790
461
|
name: attr.name,
|
|
791
462
|
value: attr.value
|
|
792
463
|
}, isTarget);
|
|
793
|
-
if (!xpathe) {
|
|
794
|
-
xpathe = (0, xpathHelpers_js_1.getPlatformFallbackXpath)(sibling, platform);
|
|
795
|
-
}
|
|
796
464
|
if (xpathe) {
|
|
797
465
|
xpathe += `/${axis}::${nodeXpath}`;
|
|
798
|
-
const count = (
|
|
466
|
+
const count = getCachedXPathCount(xpathe, sibling, docmt);
|
|
799
467
|
if (count === 1) {
|
|
800
|
-
xpathData
|
|
468
|
+
if (!appendXPath(xpathData, {
|
|
801
469
|
key: `xpath by ${axis}`,
|
|
802
470
|
value: xpathe
|
|
803
|
-
})
|
|
804
|
-
|
|
805
|
-
}
|
|
806
|
-
else if (count > 1) {
|
|
807
|
-
if (xpathDataWithIndex.length) {
|
|
808
|
-
if (count < xpathDataWithIndex[0].count) {
|
|
809
|
-
xpathDataWithIndex.pop();
|
|
810
|
-
xpathDataWithIndex.push({
|
|
811
|
-
key: `relative xpath by ${axis}`,
|
|
812
|
-
value: xpathe,
|
|
813
|
-
count
|
|
814
|
-
});
|
|
815
|
-
}
|
|
471
|
+
})) {
|
|
472
|
+
return;
|
|
816
473
|
}
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
key: `relative xpath by ${axis}`,
|
|
820
|
-
value: xpathe,
|
|
821
|
-
count
|
|
822
|
-
});
|
|
474
|
+
if (hasReachedRelativeXpathLimit()) {
|
|
475
|
+
return;
|
|
823
476
|
}
|
|
824
477
|
}
|
|
825
478
|
}
|
|
826
479
|
}
|
|
827
480
|
}
|
|
828
481
|
if (!isTarget) {
|
|
829
|
-
const xpathe = (0, xpathHelpers_js_1.
|
|
482
|
+
const xpathe = (0, xpathHelpers_js_1.intermediateAiXpathStep)(sibling, {
|
|
830
483
|
name: "text",
|
|
831
|
-
value: sibling
|
|
484
|
+
value: getCachedTextContent(sibling)
|
|
832
485
|
}, isTarget);
|
|
833
486
|
if (xpathe) {
|
|
834
|
-
const count = (
|
|
487
|
+
const count = getCachedXPathCount(xpathe, sibling, docmt);
|
|
835
488
|
if (count === 1) {
|
|
836
|
-
xpathData
|
|
489
|
+
if (!appendXPath(xpathData, {
|
|
837
490
|
key: `xpath by ${axis}`,
|
|
838
491
|
value: xpathe
|
|
839
|
-
})
|
|
840
|
-
|
|
841
|
-
}
|
|
842
|
-
else if (count > 1) {
|
|
843
|
-
if (xpathDataWithIndex.length) {
|
|
844
|
-
if (count < xpathDataWithIndex[0].count) {
|
|
845
|
-
xpathDataWithIndex.pop();
|
|
846
|
-
xpathDataWithIndex.push({
|
|
847
|
-
key: `relative xpath by ${axis}`,
|
|
848
|
-
value: xpathe,
|
|
849
|
-
count
|
|
850
|
-
});
|
|
851
|
-
}
|
|
852
|
-
}
|
|
853
|
-
else {
|
|
854
|
-
xpathDataWithIndex.push({
|
|
855
|
-
key: `relative xpath by ${axis}`,
|
|
856
|
-
value: xpathe,
|
|
857
|
-
count
|
|
858
|
-
});
|
|
492
|
+
})) {
|
|
493
|
+
return;
|
|
859
494
|
}
|
|
495
|
+
return;
|
|
860
496
|
}
|
|
861
497
|
}
|
|
862
498
|
}
|
|
863
499
|
}
|
|
864
500
|
catch (error) {
|
|
865
|
-
logData_js_1.logger.error(`${axis} xpath-error`, error);
|
|
501
|
+
logData_js_1.logger.error(`${axis} xpath-error`, error.message);
|
|
866
502
|
}
|
|
867
503
|
};
|
|
868
|
-
function
|
|
504
|
+
function getAiXPathUsingAttributeAndText(attributes, targetElemt, docmt, isTarget) {
|
|
869
505
|
const { tagName } = targetElemt;
|
|
870
|
-
const textContent = targetElemt
|
|
506
|
+
const textContent = getCachedTextContent(targetElemt);
|
|
871
507
|
if (!textContent) {
|
|
872
508
|
return;
|
|
873
509
|
}
|
|
874
510
|
for (const attrName of attributes) {
|
|
875
|
-
if ((0, xpathHelpers_js_1.
|
|
876
|
-
const attrValue = (0, xpathHelpers_js_1.
|
|
511
|
+
if ((0, xpathHelpers_js_1.checkAiBlockedAttributes)(attrName, targetElemt, isTarget)) {
|
|
512
|
+
const attrValue = (0, xpathHelpers_js_1.sanitizeAiAttributeValue)(attrName.name, attrName.nodeValue);
|
|
877
513
|
const elementName = attrName.name;
|
|
878
514
|
const xpath = `//${tagName}[@${elementName}='${attrValue}' and text()='${textContent}']`;
|
|
879
515
|
if (xpath) {
|
|
880
|
-
const count = (
|
|
516
|
+
const count = getCachedXPathCount(xpath, targetElemt, docmt);
|
|
881
517
|
if (count == 1) {
|
|
882
518
|
return xpath;
|
|
883
519
|
}
|
|
@@ -885,225 +521,124 @@ function getXPathUsingAttributeAndText(attributes, targetElemt, docmt, isTarget)
|
|
|
885
521
|
}
|
|
886
522
|
}
|
|
887
523
|
}
|
|
888
|
-
const
|
|
889
|
-
try {
|
|
890
|
-
const nodeXpath = [];
|
|
891
|
-
let relativeXpath, relativeChildXpath;
|
|
892
|
-
xpathData = [];
|
|
893
|
-
if (attribute) {
|
|
894
|
-
for (const attrName of attribute) {
|
|
895
|
-
const expression = (0, xpathHelpers_js_1.intermediateXpathStep)(targetElemt, {
|
|
896
|
-
name: attrName.name,
|
|
897
|
-
value: attrName.value
|
|
898
|
-
}, isTarget);
|
|
899
|
-
if (expression) {
|
|
900
|
-
nodeXpath.push(expression);
|
|
901
|
-
}
|
|
902
|
-
}
|
|
903
|
-
}
|
|
904
|
-
if (targetElemt.textContent) {
|
|
905
|
-
const expression = (0, xpathHelpers_js_1.intermediateXpathStep)(targetElemt, {
|
|
906
|
-
name: "text",
|
|
907
|
-
value: targetElemt.textContent
|
|
908
|
-
}, isTarget);
|
|
909
|
-
// console.log(expression);
|
|
910
|
-
if (expression) {
|
|
911
|
-
nodeXpath.push(expression);
|
|
912
|
-
}
|
|
913
|
-
}
|
|
914
|
-
nodeXpath.push(targetElemt.tagName);
|
|
915
|
-
if (nodeXpath?.length) {
|
|
916
|
-
for (let i = 0; i < nodeXpath.length; i++) {
|
|
917
|
-
if (!xpathData.length) {
|
|
918
|
-
getSiblingRelativeXPath(targetElemt, docmt, isTarget, nodeXpath[i], platform);
|
|
919
|
-
if (!xpathData.length) {
|
|
920
|
-
if (!relativeXpath) {
|
|
921
|
-
relativeXpath = getParentRelativeXpath(targetElemt.parentElement, docmt, targetElemt, isTarget, platform);
|
|
922
|
-
}
|
|
923
|
-
if (relativeXpath &&
|
|
924
|
-
(relativeXpath.includes("@") ||
|
|
925
|
-
relativeXpath.includes("text()") ||
|
|
926
|
-
relativeXpath.includes(".=")) &&
|
|
927
|
-
relativeXpath.match(/\//g)?.length - 2 < 5) {
|
|
928
|
-
const fullRelativeXpath = relativeXpath + `/${nodeXpath[i]}`;
|
|
929
|
-
const count = (0, xpathHelpers_js_1.getCountOfXPath)(fullRelativeXpath, targetElemt, docmt);
|
|
930
|
-
if (count === 1) {
|
|
931
|
-
xpathData.push({
|
|
932
|
-
key: "relative xpath by relative parent",
|
|
933
|
-
value: fullRelativeXpath
|
|
934
|
-
});
|
|
935
|
-
}
|
|
936
|
-
else if (count > 1 && isIndex) {
|
|
937
|
-
const relativeXpathIndex = (0, xpathHelpers_js_1.findXpathWithIndex)(fullRelativeXpath, targetElemt, docmt, count);
|
|
938
|
-
if (relativeXpathIndex &&
|
|
939
|
-
(0, xpathHelpers_js_1.getCountOfXPath)(relativeXpathIndex, targetElemt, docmt) === 1) {
|
|
940
|
-
xpathData.push({
|
|
941
|
-
key: `relative xpath by relative parent ${isIndex ? "index" : ""}`,
|
|
942
|
-
value: relativeXpathIndex
|
|
943
|
-
});
|
|
944
|
-
}
|
|
945
|
-
}
|
|
946
|
-
}
|
|
947
|
-
}
|
|
948
|
-
if (xpathData.length <= 1) {
|
|
949
|
-
if (!relativeChildXpath) {
|
|
950
|
-
relativeChildXpath = getChildRelativeXpath(targetElemt, docmt, targetElemt);
|
|
951
|
-
}
|
|
952
|
-
if (relativeChildXpath &&
|
|
953
|
-
(relativeChildXpath.includes("@") ||
|
|
954
|
-
relativeChildXpath.includes("text()") ||
|
|
955
|
-
relativeChildXpath.includes(".="))) {
|
|
956
|
-
const fullRelativeXpath = `/${nodeXpath[i] + relativeChildXpath.substring(1)}`;
|
|
957
|
-
const count = (0, xpathHelpers_js_1.getCountOfXPath)(fullRelativeXpath, targetElemt, docmt);
|
|
958
|
-
if (count === 1) {
|
|
959
|
-
xpathData.push({
|
|
960
|
-
key: "relative xpath by relative child",
|
|
961
|
-
value: fullRelativeXpath
|
|
962
|
-
});
|
|
963
|
-
}
|
|
964
|
-
else if (count > 1 && isIndex) {
|
|
965
|
-
const relativeXpathIndex = (0, xpathHelpers_js_1.findXpathWithIndex)(fullRelativeXpath, targetElemt, docmt, count);
|
|
966
|
-
if (relativeXpathIndex &&
|
|
967
|
-
(0, xpathHelpers_js_1.getCountOfXPath)(relativeXpathIndex, targetElemt, docmt) === 1) {
|
|
968
|
-
xpathData.push({
|
|
969
|
-
key: `relative xpath by relative parent ${isIndex ? "index" : ""}`,
|
|
970
|
-
value: relativeXpathIndex
|
|
971
|
-
});
|
|
972
|
-
}
|
|
973
|
-
}
|
|
974
|
-
}
|
|
975
|
-
}
|
|
976
|
-
if (xpathData?.length === 1 &&
|
|
977
|
-
(xpathData?.[0]?.value?.match(/\[([0-9]+)\]/gm)?.length || 0) > 3 &&
|
|
978
|
-
!referenceElementMode) {
|
|
979
|
-
if (targetElemt.textContent) {
|
|
980
|
-
const txtXpath = (0, exports.getTextXPath)(targetElemt, docmt, isIndex, false, platform);
|
|
981
|
-
if (txtXpath) {
|
|
982
|
-
xpathData.unshift({
|
|
983
|
-
key: `xpath by text${isIndex ? "index" : ""}`,
|
|
984
|
-
value: txtXpath
|
|
985
|
-
});
|
|
986
|
-
}
|
|
987
|
-
}
|
|
988
|
-
}
|
|
989
|
-
if (!xpathData.length) {
|
|
990
|
-
const tempRelativeXpath = getUniqueParentXpath(targetElemt.parentElement, docmt, targetElemt, isTarget, nodeXpath[i], isIndex, platform);
|
|
991
|
-
if (tempRelativeXpath) {
|
|
992
|
-
xpathData.push({
|
|
993
|
-
key: "xpath by unique parent",
|
|
994
|
-
value: tempRelativeXpath
|
|
995
|
-
});
|
|
996
|
-
}
|
|
997
|
-
}
|
|
998
|
-
}
|
|
999
|
-
}
|
|
1000
|
-
}
|
|
1001
|
-
return xpathData;
|
|
1002
|
-
}
|
|
1003
|
-
catch (error) {
|
|
1004
|
-
logData_js_1.logger.error("Error in addRelativeXpaths:", error);
|
|
1005
|
-
}
|
|
1006
|
-
};
|
|
1007
|
-
const attributesBasedXPath = (attr, targetElemt, docmt, isIndex, isTarget, platform) => {
|
|
524
|
+
const attributesAiBasedXPath = (attr, targetElemt, docmt, isTarget, platform) => {
|
|
1008
525
|
const attrName = attr.name;
|
|
1009
|
-
const xpath = (0, xpathHelpers_js_1.
|
|
526
|
+
const xpath = (0, xpathHelpers_js_1.getAiPropertyXPath)(targetElemt, docmt, `@${attrName}`, attr.value, isTarget, platform);
|
|
1010
527
|
return xpath;
|
|
1011
528
|
};
|
|
1012
|
-
exports.
|
|
1013
|
-
const
|
|
529
|
+
exports.attributesAiBasedXPath = attributesAiBasedXPath;
|
|
530
|
+
const getAiUniqueClassName = (element, docmt, isTarget, platform) => {
|
|
1014
531
|
let value = element.className;
|
|
1015
532
|
if (typeof value !== "string") {
|
|
1016
533
|
value = "";
|
|
1017
534
|
}
|
|
1018
535
|
value = value?.replace("flndisabled", "disabled");
|
|
1019
|
-
value = (0, xpathHelpers_js_1.
|
|
536
|
+
value = (0, xpathHelpers_js_1.sanitizeAiAttributeValue)("class", value);
|
|
1020
537
|
value = value?.trim();
|
|
1021
538
|
if (value) {
|
|
1022
|
-
return (0, xpathHelpers_js_1.
|
|
539
|
+
return (0, xpathHelpers_js_1.getAiPropertyXPath)(element, docmt, `@class`, value, isTarget, platform);
|
|
1023
540
|
}
|
|
1024
541
|
};
|
|
1025
|
-
exports.
|
|
1026
|
-
const
|
|
542
|
+
exports.getAiUniqueClassName = getAiUniqueClassName;
|
|
543
|
+
const getAiTextXPath = (element, docmt, isTarget, platform) => {
|
|
1027
544
|
if ((element.textContent ?? "").trim() != "") {
|
|
1028
|
-
const text = (
|
|
545
|
+
const text = getCachedTextContent(element);
|
|
1029
546
|
if (text) {
|
|
1030
|
-
return (0, xpathHelpers_js_1.
|
|
547
|
+
return (0, xpathHelpers_js_1.getAiPropertyXPath)(element, docmt, ".", text, isTarget, platform);
|
|
1031
548
|
}
|
|
1032
549
|
}
|
|
1033
550
|
};
|
|
1034
|
-
exports.
|
|
1035
|
-
const
|
|
551
|
+
exports.getAiTextXPath = getAiTextXPath;
|
|
552
|
+
const addAiAllXPathAttributes = (attributes, targetElemt, docmt, isTarget, platform) => {
|
|
1036
553
|
const attributesArray = attributes;
|
|
1037
554
|
try {
|
|
1038
555
|
attributesArray.map((attr) => {
|
|
1039
556
|
if (!(attr.name === "className" || attr.name === "class")) {
|
|
1040
|
-
if ((0, xpathHelpers_js_1.
|
|
1041
|
-
const xpth = (0, exports.
|
|
557
|
+
if ((0, xpathHelpers_js_1.checkAiBlockedAttributes)(attr, targetElemt, isTarget)) {
|
|
558
|
+
const xpth = (0, exports.attributesAiBasedXPath)(attr, targetElemt, docmt, isTarget, platform);
|
|
1042
559
|
if (xpth) {
|
|
1043
|
-
xpathData
|
|
1044
|
-
key: `xpath by ${attr.name}
|
|
560
|
+
if (!appendXPath(xpathData, {
|
|
561
|
+
key: `xpath by ${attr.name}`,
|
|
1045
562
|
value: xpth
|
|
1046
|
-
})
|
|
563
|
+
})) {
|
|
564
|
+
return;
|
|
565
|
+
}
|
|
1047
566
|
}
|
|
1048
|
-
const containsXpath = (0, xpathHelpers_js_1.
|
|
567
|
+
const containsXpath = (0, xpathHelpers_js_1.getAiContainsPropertyXPath)(targetElemt, `@${attr.name}`, attr.value, platform);
|
|
1049
568
|
if (containsXpath &&
|
|
1050
|
-
(
|
|
1051
|
-
xpathData
|
|
569
|
+
getCachedXPathCount(containsXpath, targetElemt, docmt) === 1) {
|
|
570
|
+
if (!appendXPath(xpathData, {
|
|
1052
571
|
key: `xpath by contains ${attr.name}`,
|
|
1053
572
|
value: containsXpath
|
|
1054
|
-
})
|
|
573
|
+
})) {
|
|
574
|
+
return;
|
|
575
|
+
}
|
|
1055
576
|
}
|
|
1056
|
-
const startsWithXpath = (0, xpathHelpers_js_1.
|
|
577
|
+
const startsWithXpath = (0, xpathHelpers_js_1.getAiStartsWithPropertyXPath)(targetElemt, `@${attr.name}`, attr.value, platform);
|
|
1057
578
|
if (startsWithXpath &&
|
|
1058
|
-
(
|
|
1059
|
-
xpathData
|
|
579
|
+
getCachedXPathCount(startsWithXpath, targetElemt, docmt) === 1) {
|
|
580
|
+
if (!appendXPath(xpathData, {
|
|
1060
581
|
key: `xpath by startsWith ${attr.name}`,
|
|
1061
582
|
value: startsWithXpath
|
|
1062
|
-
})
|
|
583
|
+
})) {
|
|
584
|
+
return;
|
|
585
|
+
}
|
|
1063
586
|
}
|
|
1064
587
|
}
|
|
1065
588
|
}
|
|
1066
589
|
});
|
|
1067
|
-
const txtXpath = (0, exports.
|
|
590
|
+
const txtXpath = (0, exports.getAiTextXPath)(targetElemt, docmt, isTarget, platform);
|
|
1068
591
|
if (txtXpath) {
|
|
1069
|
-
xpathData
|
|
1070
|
-
key:
|
|
592
|
+
if (!appendXPath(xpathData, {
|
|
593
|
+
key: "xpath by text",
|
|
1071
594
|
value: txtXpath
|
|
1072
|
-
})
|
|
595
|
+
})) {
|
|
596
|
+
return;
|
|
597
|
+
}
|
|
1073
598
|
}
|
|
1074
599
|
const classNameAttr = attributesArray.find((element) => element.name === "className");
|
|
1075
|
-
if (classNameAttr && (0, xpathHelpers_js_1.
|
|
1076
|
-
const xpath = (0, exports.
|
|
600
|
+
if (classNameAttr && (0, xpathHelpers_js_1.checkAiBlockedAttributes)(classNameAttr, targetElemt, isTarget)) {
|
|
601
|
+
const xpath = (0, exports.getAiUniqueClassName)(targetElemt, docmt, isTarget, platform);
|
|
1077
602
|
if (xpath) {
|
|
1078
|
-
xpathData
|
|
603
|
+
if (!appendXPath(xpathData, {
|
|
1079
604
|
key: "xpath by class",
|
|
1080
605
|
value: xpath
|
|
1081
|
-
})
|
|
606
|
+
})) {
|
|
607
|
+
return;
|
|
608
|
+
}
|
|
1082
609
|
}
|
|
1083
610
|
}
|
|
1084
611
|
if (!xpathData.length && attributesArray.length > 1) {
|
|
1085
|
-
const combinationXpath = (0, xpathHelpers_js_1.
|
|
1086
|
-
if (combinationXpath)
|
|
1087
|
-
xpathData
|
|
612
|
+
const combinationXpath = (0, xpathHelpers_js_1.getAiAttributeCombinationXpath)(targetElemt, docmt, attributesArray, isTarget, platform);
|
|
613
|
+
if (combinationXpath) {
|
|
614
|
+
if (!appendXPath(xpathData, {
|
|
1088
615
|
key: "xpath by combination",
|
|
1089
616
|
value: combinationXpath
|
|
1090
|
-
})
|
|
617
|
+
})) {
|
|
618
|
+
return;
|
|
619
|
+
}
|
|
620
|
+
}
|
|
1091
621
|
}
|
|
1092
622
|
if (!xpathData.length) {
|
|
1093
|
-
const textAttribute =
|
|
1094
|
-
if (textAttribute)
|
|
1095
|
-
xpathData
|
|
623
|
+
const textAttribute = getAiXPathUsingAttributeAndText(attributes, targetElemt, docmt, isTarget);
|
|
624
|
+
if (textAttribute) {
|
|
625
|
+
if (!appendXPath(xpathData, {
|
|
1096
626
|
key: "xpath by textAttribute",
|
|
1097
627
|
value: textAttribute
|
|
1098
|
-
})
|
|
628
|
+
})) {
|
|
629
|
+
return;
|
|
630
|
+
}
|
|
631
|
+
}
|
|
1099
632
|
}
|
|
1100
633
|
}
|
|
1101
634
|
catch (error) {
|
|
1102
|
-
logData_js_1.logger.error("Error in
|
|
635
|
+
logData_js_1.logger.error("Error in addAiAllXPathAttributes:", error);
|
|
1103
636
|
}
|
|
1104
637
|
};
|
|
1105
|
-
const
|
|
638
|
+
const aiParseDOM = (element, doc, isTarget, includedAttributes = [], platform) => {
|
|
1106
639
|
xpathData = [];
|
|
640
|
+
xpathValues.clear();
|
|
641
|
+
xpathCache.clear();
|
|
1107
642
|
const targetElemt = element;
|
|
1108
643
|
const rootNode = targetElemt?.getRootNode?.();
|
|
1109
644
|
const DOCUMENT_FRAGMENT_NODE = 11;
|
|
@@ -1112,28 +647,29 @@ const parseDOM = (element, doc, isIndex, isTarget, includedAttributes = [], stra
|
|
|
1112
647
|
const tag = targetElemt.tagName;
|
|
1113
648
|
const { attributes } = targetElemt;
|
|
1114
649
|
const attributesToUse = includedAttributes.length > 0 ? includedAttributes : Array.from(attributes);
|
|
1115
|
-
|
|
650
|
+
addAiAllXPathAttributes(attributesToUse, targetElemt, docmt, isTarget, platform);
|
|
651
|
+
if (xpathData.length >= MAX_XPATH_RESULTS) {
|
|
652
|
+
return xpathData;
|
|
653
|
+
}
|
|
1116
654
|
if (platform === "android") {
|
|
1117
|
-
xpathData.push(...(0, androidSelector_js_1.
|
|
655
|
+
xpathData.push(...(0, androidSelector_js_1.generateAiAndroidLocators)(targetElemt, docmt, isTarget));
|
|
1118
656
|
}
|
|
1119
657
|
else if (platform === "ios") {
|
|
1120
|
-
xpathData.push(...(0, iosSelector_js_1.
|
|
658
|
+
xpathData.push(...(0, iosSelector_js_1.generateAiIOSLocators)(targetElemt, docmt, isTarget));
|
|
659
|
+
}
|
|
660
|
+
if (xpathData.length >= MAX_XPATH_RESULTS) {
|
|
661
|
+
return xpathData;
|
|
1121
662
|
}
|
|
1122
|
-
if (xpathData.length
|
|
1123
|
-
const
|
|
1124
|
-
if (
|
|
1125
|
-
xpathData
|
|
1126
|
-
key: "
|
|
1127
|
-
value:
|
|
663
|
+
if (platform === "android" && !xpathData.length) {
|
|
664
|
+
const relativeXpath = (0, xpathHelpers_js_1.getAIRelativeXPath)(targetElemt, docmt, isTarget, attributesToUse, platform);
|
|
665
|
+
if (relativeXpath && getCachedXPathCount(relativeXpath, targetElemt, docmt) === 1) {
|
|
666
|
+
appendXPath(xpathData, {
|
|
667
|
+
key: "Relative xpath",
|
|
668
|
+
value: relativeXpath
|
|
1128
669
|
});
|
|
1129
670
|
}
|
|
1130
671
|
}
|
|
1131
|
-
if (
|
|
1132
|
-
const strategyXpaths = strategies.flatMap((strategy) => buildStrategyXpaths(targetElemt, docmt, isTarget, strategy, platform));
|
|
1133
|
-
xpathData = getUniqueXpathEntries(strategyXpaths.filter((xpath) => (0, xpathHelpers_js_1.getCountOfXPath)(xpath.value, targetElemt, docmt) === 1));
|
|
1134
|
-
return xpathData;
|
|
1135
|
-
}
|
|
1136
|
-
if (!referenceElementMode) {
|
|
672
|
+
if (!referenceElementMode && xpathData.length < MAX_XPATH_RESULTS) {
|
|
1137
673
|
if (xpathData.length) {
|
|
1138
674
|
const len = xpathData.length;
|
|
1139
675
|
for (let i = 0; i < len; i++) {
|
|
@@ -1141,42 +677,34 @@ const parseDOM = (element, doc, isIndex, isTarget, includedAttributes = [], stra
|
|
|
1141
677
|
if (xpth.startsWith(`//${tag}`)) {
|
|
1142
678
|
xpth = "//*" + xpth.substring(2 + tag.length);
|
|
1143
679
|
}
|
|
1144
|
-
if ((
|
|
1145
|
-
!xpathData
|
|
1146
|
-
xpathData.push({
|
|
680
|
+
if (getCachedXPathCount(xpth, element, docmt) === 1) {
|
|
681
|
+
if (!appendXPath(xpathData, {
|
|
1147
682
|
key: `${xpathData[i].key} regex`,
|
|
1148
683
|
value: xpth
|
|
1149
|
-
})
|
|
684
|
+
})) {
|
|
685
|
+
return xpathData;
|
|
686
|
+
}
|
|
687
|
+
if (xpathData.length >= MAX_XPATH_RESULTS) {
|
|
688
|
+
return xpathData;
|
|
689
|
+
}
|
|
1150
690
|
}
|
|
1151
|
-
// const count = getCountOfXPath(xpth, element, docmt);
|
|
1152
|
-
// if (count === 1) {
|
|
1153
|
-
// xpathData.push({
|
|
1154
|
-
// key: `${xpathData[i].key} regex`,
|
|
1155
|
-
// value: xpth
|
|
1156
|
-
// });
|
|
1157
|
-
// }
|
|
1158
691
|
}
|
|
1159
692
|
}
|
|
1160
693
|
}
|
|
1161
|
-
if (!xpathData.length && !isShadowScoped) {
|
|
1162
|
-
xpathData = buildAxesStrategyXpaths(targetElemt, docmt, isTarget, isIndex, platform);
|
|
1163
|
-
}
|
|
1164
694
|
return xpathData;
|
|
1165
695
|
};
|
|
1166
|
-
exports.
|
|
696
|
+
exports.aiParseDOM = aiParseDOM;
|
|
1167
697
|
const xpath = {
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
checkRelativeXpathRelation,
|
|
1180
|
-
buildAxesStrategyXpaths
|
|
698
|
+
aiParseDOM: exports.aiParseDOM,
|
|
699
|
+
getAiTextXPath: exports.getAiTextXPath,
|
|
700
|
+
getAiUniqueClassName: exports.getAiUniqueClassName,
|
|
701
|
+
attributesAiBasedXPath: exports.attributesAiBasedXPath,
|
|
702
|
+
addAiAllXPathAttributes,
|
|
703
|
+
getAiXPathUsingAttributeAndText,
|
|
704
|
+
getAiSiblingRelativeXPath,
|
|
705
|
+
getAiChildRelativeXpath,
|
|
706
|
+
getAiParentRelativeXpath,
|
|
707
|
+
getAiUniqueParentXpath,
|
|
708
|
+
checkAiRelativeXpathRelation
|
|
1181
709
|
};
|
|
1182
710
|
exports.default = xpath;
|