browser_name_general.js (10457B)
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 requestLongerTimeout(2); 7 8 /* import-globals-from ../../mochitest/name.js */ 9 /* import-globals-from ../../mochitest/attributes.js */ 10 loadScripts( 11 { name: "name.js", dir: MOCHITESTS_DIR }, 12 { name: "attributes.js", dir: MOCHITESTS_DIR } 13 ); 14 /** 15 * Test caching of the document title. 16 */ 17 addAccessibleTask( 18 ``, 19 async function (browser, docAcc) { 20 let nameChanged = waitForEvent(EVENT_NAME_CHANGE, docAcc); 21 await invokeContentTask(browser, [], () => { 22 content.document.title = "new title"; 23 }); 24 await nameChanged; 25 testName(docAcc, "new title"); 26 }, 27 { chrome: true, topLevel: true, iframe: true, remoteIframe: true } 28 ); 29 30 /** 31 * Test that the name is updated when the content of a hidden aria-labelledby 32 * subtree changes. 33 */ 34 addAccessibleTask( 35 ` 36 <button id="button" aria-labelledby="label"></button> 37 <div id="label" hidden>a</div> 38 `, 39 async function (browser, docAcc) { 40 const button = findAccessibleChildByID(docAcc, "button"); 41 testName(button, "a"); 42 info("Changing label textContent"); 43 let nameChanged = waitForEvent(EVENT_NAME_CHANGE, button); 44 await invokeContentTask(browser, [], () => { 45 content.document.getElementById("label").textContent = "c"; 46 }); 47 await nameChanged; 48 testName(button, "c"); 49 info("Change label text node's data"); 50 nameChanged = waitForEvent(EVENT_NAME_CHANGE, button); 51 await invokeContentTask(browser, [], () => { 52 content.document.getElementById("label").firstChild.data = "d"; 53 }); 54 await nameChanged; 55 testName(button, "d"); 56 info("Prepending text node to label"); 57 nameChanged = waitForEvent(EVENT_NAME_CHANGE, button); 58 await invokeContentTask(browser, [], () => { 59 content.document 60 .getElementById("label") 61 .prepend(content.document.createTextNode("b")); 62 }); 63 await nameChanged; 64 testName(button, "bd"); 65 }, 66 { chrome: true, topLevel: true, iframe: true, remoteIframe: true } 67 ); 68 69 /** 70 * Test that the name does not include aria-actions targets of itself. 71 */ 72 addAccessibleTask( 73 `<div role="tablist"> 74 <div role="tab" id="tab" aria-actions="close pin">Title 75 <button id="close">Close</button> 76 <button id="pin">Pin</button> 77 </div> 78 </div>`, 79 async function testAriaActionInSubtree(browser, docAcc) { 80 const tab = findAccessibleChildByID(docAcc, "tab"); 81 testName(tab, "Title"); 82 83 let nameChanged = waitForEvent(EVENT_NAME_CHANGE, tab); 84 invokeSetAttribute(browser, "tab", "aria-actions", "pin"); 85 await nameChanged; 86 testName(tab, "Title Close"); 87 88 nameChanged = waitForEvent(EVENT_NAME_CHANGE, tab); 89 invokeSetAttribute(browser, "pin", "id", "broken-pin"); 90 await nameChanged; 91 testName(tab, "Title Close Pin"); 92 93 nameChanged = waitForEvent(EVENT_NAME_CHANGE, tab); 94 invokeSetAttribute(browser, "tab", "aria-actions", "close pin"); 95 await nameChanged; 96 testName(tab, "Title Pin"); 97 98 nameChanged = waitForEvent(EVENT_NAME_CHANGE, tab); 99 invokeSetAttribute(browser, "broken-pin", "id", "pin"); 100 await nameChanged; 101 testName(tab, "Title"); 102 }, 103 { chrome: true, topLevel: true } 104 ); 105 106 /** 107 * Test abbr name change notification 108 */ 109 addAccessibleTask( 110 `<abbr id="abbr" title="JavaScript Object Notation">JSON</abbr> 111 <abbr id="labelled-abbr" aria-label="YML" 112 title="Yet Another Markup Language">YAML</abbr>`, 113 async function testAbbrName(browser, docAcc) { 114 const abbr = findAccessibleChildByID(docAcc, "abbr"); 115 testName(abbr, "JavaScript Object Notation"); 116 117 let nameChanged = waitForEvent(EVENT_NAME_CHANGE, abbr); 118 invokeSetAttribute(browser, "abbr", "title", "Jason's Other Nettle"); 119 await nameChanged; 120 testName(abbr, "Jason's Other Nettle"); 121 122 nameChanged = waitForEvent(EVENT_NAME_CHANGE, abbr); 123 invokeSetAttribute(browser, "abbr", "title"); 124 await nameChanged; 125 testName(abbr, null); 126 127 const labelledAbbr = findAccessibleChildByID(docAcc, "labelled-abbr"); 128 testName(labelledAbbr, "YML"); 129 130 let events = waitForEvents({ 131 expected: [[EVENT_DESCRIPTION_CHANGE, labelledAbbr]], 132 unexpected: [[EVENT_NAME_CHANGE, labelledAbbr]], 133 }); 134 invokeSetAttribute( 135 browser, 136 "labelled-abbr", 137 "title", 138 "Your Another Marker Lye" 139 ); 140 await events; 141 testName(labelledAbbr, "YML"); 142 is(labelledAbbr.description, "Your Another Marker Lye"); 143 144 events = waitForEvents([ 145 [EVENT_NAME_CHANGE, labelledAbbr], 146 // Bug 1997464 - When losing ARIA name, we lose the description that is used 147 // now for the name. 148 // [EVENT_DESCRIPTION_CHANGE, labelledAbbr], 149 ]); 150 invokeSetAttribute(browser, "labelled-abbr", "aria-label"); 151 await events; 152 testName(labelledAbbr, "Your Another Marker Lye"); 153 }, 154 { chrome: true, topLevel: true } 155 ); 156 157 /** 158 * Test consistent doc name for remote and local docs. 159 */ 160 addAccessibleTask( 161 `<iframe id="iframe"></iframe>`, 162 async function testDocName(browser, docAcc) { 163 const iframe = findAccessibleChildByID(docAcc, "iframe"); 164 info("Setting iframe src"); 165 // This iframe won't finish loading. Thus, it will get the stale state and 166 // won't fire a document load complete event. We use the reorder event on 167 // the iframe to know when the document has been created. 168 let reordered = waitForEvent(EVENT_REORDER, iframe); 169 await invokeContentTask(browser, [], () => { 170 content.document.getElementById("iframe").src = 171 `data:text/html,<html><body>hey</body></html>`; 172 }); 173 let iframeDoc = (await reordered).accessible.firstChild; 174 is(iframeDoc.name, null, "Doc should have 'null' name"); 175 testAbsentAttrs(iframeDoc, { "explicit-name": "true" }); 176 177 reordered = waitForEvent(EVENT_REORDER, iframe); 178 await invokeContentTask(browser, [], () => { 179 content.document.getElementById("iframe").src = 180 `data:text/html,<html><title>hello</title><body>hey</body></html>`; 181 }); 182 iframeDoc = (await reordered).accessible.firstChild; 183 is(iframeDoc.name, "hello", "Doc should have name"); 184 testAttrs(iframeDoc, { "explicit-name": "true" }, true); 185 }, 186 { topLevel: true, chrome: true } 187 ); 188 189 /* 190 * All test cases taken from https://www.w3.org/TR/accname-1.1/ 191 * These were especially called out to demonstrate edge cases. 192 * (migrated from mochitest/name/test_ARIACore_examples.html) 193 */ 194 addAccessibleTask( 195 ` 196 <!-- el1 should be labeled, el2 should not. --> 197 <div id="el1" aria-labelledby="el3"></div> 198 <div id="el2" aria-labelledby="el1"></div> 199 <div id="el3"> hello </div> 200 201 <!-- The buttons should be labeled by themselves and the referenced link --> 202 <ul> 203 <li> 204 <a id="file_row1" href="./files/Documentation.pdf">Documentation.pdf</a> 205 <span role="button" tabindex="0" id="del_row1" aria-label="Delete" 206 aria-labelledby="del_row1 file_row1"></span> 207 </li> 208 <li> 209 <a id="file_row2" href="./files/HolidayLetter.pdf">HolidayLetter.pdf</a> 210 <span role="button" tabindex="0" id="del_row2" aria-label="Delete" 211 aria-labelledby="del_row2 file_row2"></span> 212 </li> 213 </ul> 214 215 <!-- Label from combined text and subtree --> 216 <div id="chkbx" role="checkbox" aria-checked="false">Flash the screen 217 <span role="textbox" aria-multiline="false"> 5 </span> times</div> 218 219 <!-- Label with name from content should include table --> 220 <input id="input_with_html_label" /> 221 <label for="input_with_html_label" id="label"> 222 <div>foo</div> 223 <table><tr><td>bar</td></tr></table> 224 <div>baz</div> 225 </label> 226 `, 227 async function testARIACoreExamples(browser, docAcc) { 228 function testName_(id, expected, cached) { 229 const acc = findAccessibleChildByID(docAcc, id); 230 if (browser.isRemoteBrowser) { 231 is( 232 acc.cache.has("name"), 233 cached, 234 `Name should ${cached ? "" : "not "}be in cache for '${id}'` 235 ); 236 } 237 testName(acc, expected); 238 } 239 // Example 1 from section 4.3.1 under 2.B. 240 // Element1 should get its name from the text in element3. 241 // Element2 should not get its name from element1 because that already 242 // gets its name from another element. 243 testName_("el1", "hello", false); 244 testName_("el2", null, false); 245 246 // Example 2 from section 4.3.1 under 2.C. 247 // The buttons should get their name from their labels and the links. 248 testName_("del_row1", "Delete Documentation.pdf", true); 249 testName_("del_row2", "Delete HolidayLetter.pdf", true); 250 251 // Example 3 from section 4.3.1 under 2.F. 252 // Name should be own content text plus the value of the input plus 253 // more own inner text, separated by 1 space. 254 testName_("chkbx", "Flash the screen 5 times", false); 255 256 // Example 4 from section 4.3.1 under 2.F. 257 // Name from content should include all the child nodes, including 258 // table cells. 259 testName_("input_with_html_label", "foo bar baz", false); 260 }, 261 { topLevel: true, chrome: true } 262 ); 263 264 /* 265 * Test labels that use ARIA naming in different ways. 266 */ 267 addAccessibleTask( 268 `<div id="label1">bye <a href="#" aria-labelledby="btn1">world</a></div> 269 <button aria-labelledby="label1" id="btn1">hello</button> 270 <div id="label2">bye <a href="#" aria-label="mars">world</a></div> 271 <button aria-labelledby="label2" id="btn2">hello</button> 272 <div id="label3" aria-label="mars">bye</div> 273 <button aria-labelledby="label3" id="btn3">hello</button>`, 274 async function testSomeInterestingLabels(browser, docAcc) { 275 const btn1 = findAccessibleChildByID(docAcc, "btn1"); 276 const btn2 = findAccessibleChildByID(docAcc, "btn2"); 277 const btn3 = findAccessibleChildByID(docAcc, "btn3"); 278 // A button whose label subtree references the button 279 testName(btn1, "bye world"); 280 // A button whose label subtree has an explicit aria-label 281 testName(btn2, "bye mars"); 282 // A button whose label has an explicit aria-label of its own 283 testName(btn3, "mars"); 284 }, 285 { topLevel: true, chrome: true } 286 ); 287 288 addAccessibleTask( 289 `<input id="input" type="text" title="title" placeholder="placeholder"></input>`, 290 async function testInputPlaceHolder(browser, docAcc) { 291 const input = findAccessibleChildByID(docAcc, "input"); 292 testName(input, "title"); 293 }, 294 { topLevel: true, chrome: true } 295 );