@@ -146,30 +146,42 @@ function AccessibilityDomNode({
146146 const kind = accessibilityKind ( node ) ;
147147 const role = accessibilityDomRole ( kind ) ;
148148 const tagName = accessibilityDomTagName ( node ) ;
149+ const description = accessibilityDomDescription ( node , metadata ) ;
149150
150151 return createElement ( tagName , {
151152 "aria-checked" :
152153 role === "checkbox" || role === "switch"
153154 ? ( node . checked ?? undefined )
154155 : undefined ,
155156 "aria-label" : label ,
157+ "aria-description" : description ,
156158 "aria-level" : depth + 1 ,
157159 "aria-selected" : node . selected ?? undefined ,
158160 className : "accessibility-dom-node" ,
161+ "data-test-id" : metadata . testId ,
159162 "data-testid" : `simdeck-accessibility-${ id } ` ,
160163 "data-simdeck-accessibility-id" : id ,
161164 "data-simdeck-accessibility-component" : kind ,
165+ "data-simdeck-accessibility-description" : description ,
162166 "data-simdeck-accessibility-identifier" :
163167 accessibilityIdentifier ( node ) || undefined ,
164168 "data-simdeck-accessibility-kind" : kind ,
165169 "data-simdeck-accessibility-label" : primaryAccessibilityText ( node ) ,
166170 "data-simdeck-accessibility-image" : metadata . imageName ,
171+ "data-simdeck-accessibility-source-location" : metadata . sourceLocation ,
167172 "data-simdeck-accessibility-source-file" : metadata . sourceFile ,
168173 "data-simdeck-accessibility-source-line" : metadata . sourceLine ,
169174 "data-simdeck-accessibility-source-column" : metadata . sourceColumn ,
170175 "data-simdeck-accessibility-source" : node . source || undefined ,
176+ "data-simdeck-accessibility-test-id" : metadata . testId ,
177+ "data-simdeck-accessibility-native-id" : metadata . nativeId ,
178+ "data-simdeck-accessibility-role" : role ,
171179 "data-simdeck-accessibility-state" : metadata . state ,
172180 "data-simdeck-accessibility-value" : metadata . value ,
181+ "data-simdeck-framework" : metadata . framework ,
182+ "data-simdeck-framework-id" : metadata . frameworkId ,
183+ "data-simdeck-framework-type" : metadata . frameworkType ,
184+ "data-simdeck-overlay-node" : "accessibility-representation" ,
173185 "data-simdeck-inspector-id" : node . inspectorId || undefined ,
174186 "data-simdeck-uikit-id" : node . uikitId || undefined ,
175187 role,
@@ -222,6 +234,23 @@ function accessibilityDomLabel(node: AccessibilityNode): string {
222234 return parts . join ( "; " ) ;
223235}
224236
237+ function accessibilityDomDescription (
238+ node : AccessibilityNode ,
239+ metadata : ReturnType < typeof accessibilityDomMetadata > ,
240+ ) : string | undefined {
241+ const parts = [
242+ "SimDeck overlay node representing a simulator app element, not the browser page control" ,
243+ metadata . framework ? `framework ${ metadata . framework } ` : "" ,
244+ metadata . frameworkType ? `component ${ metadata . frameworkType } ` : "" ,
245+ metadata . testId ? `test id ${ metadata . testId } ` : "" ,
246+ metadata . nativeId ? `native id ${ metadata . nativeId } ` : "" ,
247+ metadata . sourceLocation ? `source ${ metadata . sourceLocation } ` : "" ,
248+ metadata . state ? `state ${ metadata . state } ` : "" ,
249+ node . help ? `hint ${ node . help } ` : "" ,
250+ ] . filter ( Boolean ) ;
251+ return parts . length > 0 ? parts . join ( "; " ) : undefined ;
252+ }
253+
225254function accessibilityDomRole ( kind : string ) : AriaRole {
226255 const normalized = kind . toLowerCase ( ) ;
227256 if ( normalized . includes ( "button" ) ) {
@@ -275,8 +304,13 @@ function cleanTagPart(value: string | null | undefined): string | null {
275304
276305function accessibilityDomMetadata ( node : AccessibilityNode , id ?: string ) {
277306 const sourceLocation = primarySourceLocation ( node ) ;
307+ const framework = frameworkMetadata ( node ) ;
278308 return {
309+ framework : framework . framework ,
310+ frameworkId : framework . id ,
311+ frameworkType : framework . type ,
279312 imageName : cleanAccessibilityText ( node . imageName ) ,
313+ nativeId : framework . nativeId ,
280314 placeholder : cleanAccessibilityText ( node . placeholder ) ,
281315 sourceFile : sourceLocation . file || undefined ,
282316 sourceColumn :
@@ -289,10 +323,60 @@ function accessibilityDomMetadata(node: AccessibilityNode, id?: string) {
289323 : undefined ,
290324 sourceLocation : formatSourceLocation ( sourceLocation ) ,
291325 state : accessibilityStateSummary ( node , id ) ,
326+ testId : framework . testId ,
292327 value : cleanAccessibilityText ( node . AXValue ) ,
293328 } ;
294329}
295330
331+ function frameworkMetadata ( node : AccessibilityNode ) : {
332+ framework : string | undefined ;
333+ id : string | undefined ;
334+ nativeId : string | undefined ;
335+ testId : string | undefined ;
336+ type : string | undefined ;
337+ } {
338+ const nativeScript = node . nativeScript ?? { } ;
339+ const reactNative = node . reactNative ?? { } ;
340+ const flutter = node . flutter ?? { } ;
341+ const semantics = node . semantics ?? { } ;
342+ return {
343+ framework : node . source || undefined ,
344+ id :
345+ stringRecordValue ( nativeScript , "id" ) ??
346+ stringRecordValue ( reactNative , "tag" ) ??
347+ stringRecordValue ( flutter , "key" ) ??
348+ undefined ,
349+ nativeId :
350+ stringRecordValue ( reactNative , "nativeID" ) ??
351+ stringRecordValue ( nativeScript , "id" ) ??
352+ stringRecordValue ( semantics , "identifier" ) ??
353+ undefined ,
354+ testId :
355+ stringRecordValue ( nativeScript , "testID" ) ??
356+ stringRecordValue ( reactNative , "testID" ) ??
357+ undefined ,
358+ type :
359+ stringRecordValue ( nativeScript , "type" ) ??
360+ stringRecordValue ( reactNative , "displayName" ) ??
361+ stringRecordValue ( flutter , "widgetType" ) ??
362+ undefined ,
363+ } ;
364+ }
365+
366+ function stringRecordValue (
367+ record : Record < string , unknown > ,
368+ key : string ,
369+ ) : string | undefined {
370+ const value = record [ key ] ;
371+ if ( typeof value === "string" ) {
372+ return value . trim ( ) || undefined ;
373+ }
374+ if ( typeof value === "number" || typeof value === "boolean" ) {
375+ return String ( value ) ;
376+ }
377+ return undefined ;
378+ }
379+
296380function primarySourceLocation ( node : AccessibilityNode ) : {
297381 column : number | null ;
298382 file : string ;
@@ -342,13 +426,17 @@ function accessibilityStateSummary(
342426) : string {
343427 const state = [
344428 id ? `tree id ${ id } ` : "" ,
345- node . enabled === false ? "disabled" : "" ,
346- node . focused === true ? "focused" : "" ,
347- node . selected === true ? "selected" : "" ,
348- node . checked === true ? "checked" : "" ,
349- node . checked === false ? "unchecked" : "" ,
350- node . clickable === true ? "clickable" : "" ,
351- node . scrollable === true ? "scrollable" : "" ,
429+ node . enabled === false ? "simulator accessibility state enabled=false" : "" ,
430+ node . focused === true ? "simulator accessibility state focused=true" : "" ,
431+ node . selected === true ? "simulator accessibility state selected=true" : "" ,
432+ node . checked === true ? "simulator accessibility state checked=true" : "" ,
433+ node . checked === false ? "simulator accessibility state checked=false" : "" ,
434+ node . clickable === true
435+ ? "simulator accessibility action clickable=true"
436+ : "" ,
437+ node . scrollable === true
438+ ? "simulator accessibility action scrollable=true"
439+ : "" ,
352440 ] . filter ( Boolean ) ;
353441 return state . join ( ", " ) ;
354442}
0 commit comments