browser_roles_elements.js (12302B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 "use strict"; 6 7 /* import-globals-from ../../mochitest/role.js */ 8 /* import-globals-from ../../mochitest/states.js */ 9 loadScripts( 10 { name: "role.js", dir: MOCHITESTS_DIR }, 11 { name: "states.js", dir: MOCHITESTS_DIR } 12 ); 13 14 /** 15 * Test different HTML elements for their roles and subroles 16 */ 17 function testRoleAndSubRole(accDoc, id, axRole, axSubRole, axRoleDescription) { 18 let el = getNativeInterface(accDoc, id); 19 if (axRole) { 20 is( 21 el.getAttributeValue("AXRole"), 22 axRole, 23 "AXRole for " + id + " is " + axRole 24 ); 25 } 26 if (axSubRole) { 27 is( 28 el.getAttributeValue("AXSubrole"), 29 axSubRole, 30 "Subrole for " + id + " is " + axSubRole 31 ); 32 } 33 if (axRoleDescription) { 34 is( 35 el.getAttributeValue("AXRoleDescription"), 36 axRoleDescription, 37 "Subrole for " + id + " is " + axRoleDescription 38 ); 39 } 40 } 41 42 addAccessibleTask( 43 ` 44 <!-- WAI-ARIA landmark roles --> 45 <div id="application" role="application"></div> 46 <div id="banner" role="banner"></div> 47 <div id="complementary" role="complementary"></div> 48 <div id="contentinfo" role="contentinfo"></div> 49 <div id="form" role="form"></div> 50 <div id="form_label" aria-label="form" role="form"></div> 51 <div id="main" role="main"></div> 52 <div id="navigation" role="navigation"></div> 53 <div id="search" role="search"></div> 54 <div id="searchbox" role="searchbox"></div> 55 56 <!-- DPub landmarks --> 57 <div id="dPubNavigation" role="doc-index"></div> 58 <div id="dPubRegion" role="doc-introduction"></div> 59 60 <!-- Other WAI-ARIA widget roles --> 61 <div id="alert" role="alert"></div> 62 <div id="alertdialog" role="alertdialog"></div> 63 <div id="article" role="article"></div> 64 <div id="code" role="code"></div> 65 <div id="dialog" role="dialog"></div> 66 <div id="ariaDocument" role="document"></div> 67 <div id="log" role="log"></div> 68 <div id="marquee" role="marquee"></div> 69 <div id="ariaMath" role="math"></div> 70 <div id="note" role="note"></div> 71 <div id="ariaRegion" aria-label="region" role="region"></div> 72 <div id="ariaStatus" role="status"></div> 73 <div id="switch" role="switch"></div> 74 <div id="timer" role="timer"></div> 75 <div id="tooltip" role="tooltip"></div> 76 <div role="menu"><input type="radio" role="menuitemradio" id="menuitemradio"></div> 77 <div role="menu"><input type="checkbox" role="menuitemcheckbox" id="menuitemcheckbox"></div> 78 <input type="datetime-local" id="datetime"> 79 80 <!-- text entries --> 81 <div id="textbox_multiline" role="textbox" aria-multiline="true"></div> 82 <div id="textbox_singleline" role="textbox" aria-multiline="false"></div> 83 <textarea id="textArea"></textarea> 84 <input id="textInput"> 85 86 <!-- True HTML5 search box --> 87 <input type="search" id="htmlSearch" /> 88 89 <!-- Password input --> 90 <input type="password" id="password" /> 91 92 <!-- A button morphed into a toggle via ARIA --> 93 <button id="toggle" aria-pressed="false"></button> 94 95 <!-- A button with a 'banana' role description --> 96 <button id="banana" aria-roledescription="banana"></button> 97 98 <!-- Other elements --> 99 <del id="deletion">Deleted text</del> 100 <dl id="dl"><dt id="dt">term</dt><dd id="dd">definition</dd></dl> 101 <hr id="hr" /> 102 <ins id="insertion">Inserted text</ins> 103 <meter id="meter" min="0" max="100" value="24">meter text here</meter> 104 <sub id="sub">sub text here</sub> 105 <sup id="sup">sup text here</sup> 106 107 <!-- Some SVG stuff --> 108 <svg xmlns="http://www.w3.org/2000/svg" version="1.1" id="svg" 109 xmlns:xlink="http://www.w3.org/1999/xlink"> 110 <g id="g"> 111 <title>g</title> 112 </g> 113 <rect width="300" height="100" id="rect" 114 style="fill:rgb(0,0,255);stroke-width:1;stroke:rgb(0,0,0)"> 115 <title>rect</title> 116 </rect> 117 <circle cx="100" cy="50" r="40" stroke="black" id="circle" 118 stroke-width="2" fill="red"> 119 <title>circle</title> 120 </circle> 121 <ellipse cx="300" cy="80" rx="100" ry="50" id="ellipse" 122 style="fill:yellow;stroke:purple;stroke-width:2"> 123 <title>ellipse</title> 124 </ellipse> 125 <line x1="0" y1="0" x2="200" y2="200" id="line" 126 style="stroke:rgb(255,0,0);stroke-width:2"> 127 <title>line</title> 128 </line> 129 <polygon points="200,10 250,190 160,210" id="polygon" 130 style="fill:lime;stroke:purple;stroke-width:1"> 131 <title>polygon</title> 132 </polygon> 133 <polyline points="20,20 40,25 60,40 80,120 120,140 200,180" id="polyline" 134 style="fill:none;stroke:black;stroke-width:3" > 135 <title>polyline</title> 136 </polyline> 137 <path d="M150 0 L75 200 L225 200 Z" id="path"> 138 <title>path</title> 139 </path> 140 <image x1="25" y1="80" width="50" height="20" id="image" 141 xlink:href="../moz.png"> 142 <title>image</title> 143 </image> 144 </svg>`, 145 (browser, accDoc) => { 146 // WAI-ARIA landmark subroles, regardless of AXRole 147 testRoleAndSubRole(accDoc, "application", null, "AXLandmarkApplication"); 148 testRoleAndSubRole(accDoc, "banner", null, "AXLandmarkBanner"); 149 testRoleAndSubRole( 150 accDoc, 151 "complementary", 152 null, 153 "AXLandmarkComplementary" 154 ); 155 testRoleAndSubRole(accDoc, "contentinfo", null, "AXLandmarkContentInfo"); 156 testRoleAndSubRole(accDoc, "form", null, "AXApplicationGroup"); 157 testRoleAndSubRole(accDoc, "form_label", null, "AXLandmarkForm"); 158 testRoleAndSubRole(accDoc, "main", null, "AXLandmarkMain"); 159 testRoleAndSubRole(accDoc, "navigation", null, "AXLandmarkNavigation"); 160 testRoleAndSubRole(accDoc, "search", null, "AXLandmarkSearch"); 161 testRoleAndSubRole(accDoc, "searchbox", null, "AXSearchField"); 162 163 // DPub roles map into two categories, sample one of each 164 testRoleAndSubRole( 165 accDoc, 166 "dPubNavigation", 167 "AXGroup", 168 "AXLandmarkNavigation" 169 ); 170 testRoleAndSubRole(accDoc, "dPubRegion", "AXGroup", "AXLandmarkRegion"); 171 172 // ARIA widget roles 173 testRoleAndSubRole(accDoc, "alert", null, "AXApplicationAlert"); 174 testRoleAndSubRole( 175 accDoc, 176 "alertdialog", 177 "AXGroup", 178 "AXApplicationAlertDialog", 179 "alert dialog" 180 ); 181 testRoleAndSubRole(accDoc, "article", null, "AXDocumentArticle"); 182 testRoleAndSubRole(accDoc, "code", "AXGroup", "AXCodeStyleGroup"); 183 testRoleAndSubRole(accDoc, "dialog", null, "AXApplicationDialog", "dialog"); 184 testRoleAndSubRole(accDoc, "ariaDocument", null, "AXDocument"); 185 testRoleAndSubRole(accDoc, "log", null, "AXApplicationLog"); 186 testRoleAndSubRole(accDoc, "marquee", null, "AXApplicationMarquee"); 187 testRoleAndSubRole(accDoc, "ariaMath", null, "AXDocumentMath"); 188 testRoleAndSubRole(accDoc, "note", null, "AXDocumentNote"); 189 testRoleAndSubRole(accDoc, "ariaRegion", null, "AXLandmarkRegion"); 190 testRoleAndSubRole(accDoc, "ariaStatus", "AXGroup", "AXApplicationStatus"); 191 testRoleAndSubRole(accDoc, "switch", "AXCheckBox", "AXSwitch"); 192 testRoleAndSubRole(accDoc, "timer", null, "AXApplicationTimer"); 193 testRoleAndSubRole(accDoc, "tooltip", "AXGroup", "AXUserInterfaceTooltip"); 194 testRoleAndSubRole(accDoc, "menuitemradio", "AXMenuItem", null); 195 testRoleAndSubRole(accDoc, "menuitemcheckbox", "AXMenuItem", null); 196 testRoleAndSubRole(accDoc, "datetime", "AXGroup", null); 197 // XXX for datetime elements, we spoof the role via the title, since 198 // providing the correct role results in the internal elements being 199 // unreachable by VO 200 is( 201 getNativeInterface(accDoc, "datetime").getAttributeValue("AXTitle"), 202 "date field" 203 ); 204 205 // Text boxes 206 testRoleAndSubRole(accDoc, "textbox_multiline", "AXTextArea"); 207 testRoleAndSubRole(accDoc, "textbox_singleline", "AXTextField"); 208 testRoleAndSubRole(accDoc, "textArea", "AXTextArea"); 209 testRoleAndSubRole(accDoc, "textInput", "AXTextField"); 210 211 // True HTML5 search field 212 testRoleAndSubRole(accDoc, "htmlSearch", "AXTextField", "AXSearchField"); 213 214 // Password input 215 testRoleAndSubRole(accDoc, "password", "AXTextField", "AXSecureTextField"); 216 217 // A button morphed into a toggle by ARIA 218 testRoleAndSubRole(accDoc, "toggle", "AXCheckBox", "AXToggle"); 219 220 // A banana button 221 testRoleAndSubRole(accDoc, "banana", "AXButton", null, "banana"); 222 223 // Other elements 224 testRoleAndSubRole(accDoc, "deletion", "AXGroup", "AXDeleteStyleGroup"); 225 testRoleAndSubRole(accDoc, "dl", "AXList", "AXDefinitionList"); 226 testRoleAndSubRole(accDoc, "dt", "AXGroup", "AXTerm"); 227 testRoleAndSubRole(accDoc, "dd", "AXGroup", "AXDefinition"); 228 testRoleAndSubRole(accDoc, "hr", "AXSplitter", "AXContentSeparator"); 229 testRoleAndSubRole(accDoc, "insertion", "AXGroup", "AXInsertStyleGroup"); 230 testRoleAndSubRole( 231 accDoc, 232 "meter", 233 "AXLevelIndicator", 234 "AXMeter", 235 "level indicator" 236 ); 237 testRoleAndSubRole(accDoc, "sub", "AXGroup", "AXSubscriptStyleGroup"); 238 testRoleAndSubRole(accDoc, "sup", "AXGroup", "AXSuperscriptStyleGroup"); 239 240 // Some SVG stuff 241 testRoleAndSubRole(accDoc, "svg", "AXImage"); 242 testRoleAndSubRole(accDoc, "g", "AXGroup"); 243 testRoleAndSubRole(accDoc, "rect", "AXImage"); 244 testRoleAndSubRole(accDoc, "circle", "AXImage"); 245 testRoleAndSubRole(accDoc, "ellipse", "AXImage"); 246 testRoleAndSubRole(accDoc, "line", "AXImage"); 247 testRoleAndSubRole(accDoc, "polygon", "AXImage"); 248 testRoleAndSubRole(accDoc, "polyline", "AXImage"); 249 testRoleAndSubRole(accDoc, "path", "AXImage"); 250 testRoleAndSubRole(accDoc, "image", "AXImage"); 251 } 252 ); 253 254 addAccessibleTask( 255 ` 256 <figure id="figure"> 257 <img id="img" src="http://example.com/a11y/accessible/tests/mochitest/moz.png" alt="Logo"> 258 <p>Non-image figure content</p> 259 <figcaption id="figcaption">Old Mozilla logo</figcaption> 260 </figure>`, 261 (browser, accDoc) => { 262 let figure = getNativeInterface(accDoc, "figure"); 263 ok(!figure.getAttributeValue("AXTitle"), "Figure should not have a title"); 264 is( 265 figure.getAttributeValue("AXDescription"), 266 "Old Mozilla logo", 267 "Correct figure label" 268 ); 269 is(figure.getAttributeValue("AXRole"), "AXGroup", "Correct figure role"); 270 is( 271 figure.getAttributeValue("AXRoleDescription"), 272 "figure", 273 "Correct figure role description" 274 ); 275 276 let img = getNativeInterface(accDoc, "img"); 277 ok(!img.getAttributeValue("AXTitle"), "img should not have a title"); 278 is(img.getAttributeValue("AXDescription"), "Logo", "Correct img label"); 279 is(img.getAttributeValue("AXRole"), "AXImage", "Correct img role"); 280 is( 281 img.getAttributeValue("AXRoleDescription"), 282 "image", 283 "Correct img role description" 284 ); 285 286 let figcaption = getNativeInterface(accDoc, "figcaption"); 287 ok( 288 !figcaption.getAttributeValue("AXTitle"), 289 "figcaption should not have a title" 290 ); 291 ok( 292 !figcaption.getAttributeValue("AXDescription"), 293 "figcaption should not have a label" 294 ); 295 is( 296 figcaption.getAttributeValue("AXRole"), 297 "AXGroup", 298 "Correct figcaption role" 299 ); 300 is( 301 figcaption.getAttributeValue("AXRoleDescription"), 302 "group", 303 "Correct figcaption role description" 304 ); 305 } 306 ); 307 308 addAccessibleTask(`<button>hello world</button>`, async (browser, accDoc) => { 309 const webArea = accDoc.nativeInterface.QueryInterface( 310 Ci.nsIAccessibleMacInterface 311 ); 312 313 is( 314 webArea.getAttributeValue("AXRole"), 315 "AXWebArea", 316 "web area should be an AXWebArea" 317 ); 318 ok( 319 !webArea.attributeNames.includes("AXSubrole"), 320 "AXWebArea should not have a subrole" 321 ); 322 323 let roleChanged = waitForMacEvent("AXMozRoleChanged"); 324 await SpecialPowers.spawn(browser, [], () => { 325 content.document.body.setAttribute("role", "application"); 326 }); 327 await roleChanged; 328 329 is( 330 webArea.getAttributeValue("AXRole"), 331 "AXWebArea", 332 "web area should retain AXWebArea role" 333 ); 334 ok( 335 !webArea.attributeNames.includes("AXSubrole"), 336 "AXWebArea should not have a subrole" 337 ); 338 339 let rootGroup = webArea.getAttributeValue("AXChildren")[0]; 340 is(rootGroup.getAttributeValue("AXRole"), "AXGroup"); 341 is(rootGroup.getAttributeValue("AXSubrole"), "AXLandmarkApplication"); 342 });