ax-role-inference-item-elementinternals.html (3059B)
1 <!DOCTYPE html> 2 <meta charset="utf-8"> 3 <title>HTML Test: focusgroup - ElementInternals item role never overridden</title> 4 <meta name="assert" content="Author supplied ElementInternals role for a focusgroup item must never be overridden by implied item role inference, even when mismatching expected mapping."> 5 <link rel="author" title="Microsoft" href="http://www.microsoft.com/"> 6 <link rel="help" href="https://open-ui.org/components/scoped-focusgroup.explainer/"> 7 <script src="/resources/testharness.js"></script> 8 <script src="/resources/testharnessreport.js"></script> 9 10 <!-- Scenario A: Owner implied tablist, item supplies expected mapped role 'tab'. --> 11 <div id="fgOwnerTablist" focusgroup="tablist"> 12 <focusgroup-item-internals-expected id="tabItem" tabindex="0"></focusgroup-item-internals-expected> 13 </div> 14 15 <!-- Scenario B: Same owner type (tablist) but item supplies a different role ('button'); ensure we do NOT coerce it to tab. --> 16 <div id="fgOwnerTablistMismatch" focusgroup="tablist"> 17 <focusgroup-item-internals-mismatch id="mismatchItem" tabindex="0"></focusgroup-item-internals-mismatch> 18 </div> 19 20 <script> 21 class FocusgroupItemInternalsExpected extends HTMLElement { 22 constructor() { 23 super(); 24 this.internals_ = this.attachInternals(); 25 // ElementInternals author supplied role should be preserved. 26 this.internals_.role = 'tab'; 27 this.textContent = 'Item'; 28 } 29 } 30 customElements.define('focusgroup-item-internals-expected', FocusgroupItemInternalsExpected); 31 32 class FocusgroupItemInternalsMismatch extends HTMLElement { 33 constructor() { 34 super(); 35 this.internals_ = this.attachInternals(); 36 // Deliberately provide a role that does NOT match the implied item role mapping. 37 this.internals_.role = 'button'; 38 this.textContent = 'Other'; 39 } 40 } 41 customElements.define('focusgroup-item-internals-mismatch', FocusgroupItemInternalsMismatch); 42 </script> 43 44 <script> 45 if (!window.accessibilityController) { 46 test(() => { assert_true(true); }, 'accessibilityController not available (noop)'); 47 } else { 48 test(() => { 49 const ownerAX = accessibilityController.accessibleElementById('fgOwnerTablist'); 50 assert_equals(ownerAX.role, 'AXRole: AXTabList'); 51 }, 'Scenario A: Owner receives implied tablist role'); 52 53 test(() => { 54 const itemAX = accessibilityController.accessibleElementById('tabItem'); 55 assert_equals(itemAX.role, 'AXRole: AXTab'); 56 }, 'Scenario A: Expected mapped ElementInternals role (tab) preserved'); 57 58 test(() => { 59 const ownerAX = accessibilityController.accessibleElementById('fgOwnerTablistMismatch'); 60 assert_equals(ownerAX.role, 'AXRole: AXTabList'); 61 }, 'Scenario B: Owner implied tablist role still inferred with mismatched child role'); 62 63 test(() => { 64 const itemAX = accessibilityController.accessibleElementById('mismatchItem'); 65 // Critical assertion: we do NOT coerce to AXTab; remains AXButton per author intent. 66 assert_equals(itemAX.role, 'AXRole: AXButton'); 67 }, 'Scenario B: Mismatched ElementInternals role (button) preserved (no coercion)'); 68 } 69 </script>