@@ -33,6 +33,11 @@ export function formatSimplifiedTree(
33
33
function cleanStructuralNodes (
34
34
node : AccessibilityNode ,
35
35
) : AccessibilityNode | null {
36
+ // Filter out nodes with negative IDs
37
+ if ( node . nodeId && parseInt ( node . nodeId ) < 0 ) {
38
+ return null ;
39
+ }
40
+
36
41
// Base case: leaf node
37
42
if ( ! node . children ) {
38
43
return node . role === "generic" || node . role === "none" ? null : node ;
@@ -181,33 +186,54 @@ export async function getAccessibilityTree(
181
186
182
187
// This function is wrapped into a string and sent as a CDP command
183
188
// It is not meant to be actually executed here
184
- const functionString = `function getNodePath(el) {
185
- if (!el || el.nodeType !== Node.ELEMENT_NODE) return "";
186
- const pathSegments = [];
189
+ const functionString = `
190
+ function getNodePath(el) {
191
+ if (!el || (el.nodeType !== Node.ELEMENT_NODE && el.nodeType !== Node.TEXT_NODE)) {
192
+ console.log("el is not a valid node type");
193
+ return "";
194
+ }
195
+
196
+ const parts = [];
187
197
let current = el;
188
- while (current && current.nodeType === Node.ELEMENT_NODE) {
189
- const tagName = current.nodeName.toLowerCase();
190
- let index = 1;
191
- let sibling = current.previousSibling;
192
- while (sibling) {
198
+
199
+ while (current && (current.nodeType === Node.ELEMENT_NODE || current.nodeType === Node.TEXT_NODE)) {
200
+ let index = 0;
201
+ let hasSameTypeSiblings = false;
202
+ const siblings = current.parentElement
203
+ ? Array.from(current.parentElement.childNodes)
204
+ : [];
205
+
206
+ for (let i = 0; i < siblings.length; i++) {
207
+ const sibling = siblings[i];
193
208
if (
194
- sibling.nodeType === Node.ELEMENT_NODE &&
195
- sibling.nodeName.toLowerCase() === tagName
209
+ sibling.nodeType === current.nodeType &&
210
+ sibling.nodeName === current.nodeName
196
211
) {
197
- index++;
212
+ index = index + 1;
213
+ hasSameTypeSiblings = true;
214
+ if (sibling.isSameNode(current)) {
215
+ break;
216
+ }
198
217
}
199
- sibling = sibling.previousSibling;
200
218
}
201
- const segment = index > 1 ? tagName + "[" + index + "]" : tagName;
202
- pathSegments.unshift(segment);
203
- current = current.parentNode;
219
+
204
220
if (!current || !current.parentNode) break;
205
- if (current.nodeName.toLowerCase() === "html") {
206
- pathSegments .unshift("html");
221
+ if (current.nodeName.toLowerCase() === "html"){
222
+ parts .unshift("html");
207
223
break;
208
224
}
225
+
226
+ // text nodes are handled differently in XPath
227
+ if (current.nodeName !== "#text") {
228
+ const tagName = current.nodeName.toLowerCase();
229
+ const pathIndex = hasSameTypeSiblings ? \`[\${index}]\` : "";
230
+ parts.unshift(\`\${tagName}\${pathIndex}\`);
231
+ }
232
+
233
+ current = current.parentElement;
209
234
}
210
- return "/" + pathSegments.join("/");
235
+
236
+ return parts.length ? \`/\${parts.join("/")}\` : "";
211
237
}` ;
212
238
213
239
export async function getXPathByResolvedObjectId (
0 commit comments