@@ -54,7 +54,7 @@ async function cleanStructuralNodes(
54
54
cleanStructuralNodes ( child , page , logger ) ,
55
55
) ;
56
56
const resolvedChildren = await Promise . all ( cleanedChildrenPromises ) ;
57
- const cleanedChildren = resolvedChildren . filter (
57
+ let cleanedChildren = resolvedChildren . filter (
58
58
( child ) : child is AccessibilityNode => child !== null ,
59
59
) ;
60
60
@@ -136,6 +136,17 @@ async function cleanStructuralNodes(
136
136
}
137
137
}
138
138
139
+ // rm redundant StaticText children
140
+ cleanedChildren = removeRedundantStaticTextChildren ( node , cleanedChildren ) ;
141
+
142
+ if ( cleanedChildren . length === 0 ) {
143
+ if ( node . role === "generic" || node . role === "none" ) {
144
+ return null ;
145
+ } else {
146
+ return { ...node , children : [ ] } ;
147
+ }
148
+ }
149
+
139
150
// 6) Return the updated node.
140
151
// If it has children, update them; otherwise keep it as-is.
141
152
return cleanedChildren . length > 0
@@ -448,6 +459,40 @@ export async function findScrollableElementIds(
448
459
return scrollableBackendIds ;
449
460
}
450
461
462
+ /**
463
+ * Removes any StaticText children whose combined text equals the parent's name.
464
+ * This is most often used to avoid duplicating a link's accessible name in separate child nodes.
465
+ *
466
+ * @param parent The parent accessibility node whose `.name` we check.
467
+ * @param children The parent's current children list, typically after cleaning.
468
+ * @returns A filtered list of children with redundant StaticText nodes removed.
469
+ */
470
+ function removeRedundantStaticTextChildren (
471
+ parent : AccessibilityNode ,
472
+ children : AccessibilityNode [ ] ,
473
+ ) : AccessibilityNode [ ] {
474
+ if ( ! parent . name ) {
475
+ return children ;
476
+ }
477
+
478
+ const parentName = parent . name . replace ( / \s + / g, " " ) . trim ( ) ;
479
+
480
+ // Gather all StaticText children and combine their text
481
+ const staticTextChildren = children . filter (
482
+ ( child ) => child . role === "StaticText" && child . name ,
483
+ ) ;
484
+ const combinedChildText = staticTextChildren
485
+ . map ( ( child ) => child . name ! . replace ( / \s + / g, " " ) . trim ( ) )
486
+ . join ( "" ) ;
487
+
488
+ // If the combined text exactly matches the parent's name, remove those child nodes
489
+ if ( combinedChildText === parentName ) {
490
+ return children . filter ( ( child ) => child . role !== "StaticText" ) ;
491
+ }
492
+
493
+ return children ;
494
+ }
495
+
451
496
export async function performPlaywrightMethod (
452
497
stagehandPage : Page ,
453
498
logger : ( logLine : LogLine ) => void ,
0 commit comments