browser_selectionPatterns.js (8564B)
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 const SNIPPET = ` 8 <select id="selectList" size="2"> 9 <option id="sl1" selected>sl1</option> 10 <option id="sl2">sl2</option> 11 </select> 12 <select id="selectRequired" size="2" required> 13 <option id="sr1">sr1</option> 14 </select> 15 <select id="selectMulti" size="2" multiple> 16 <option id="sm1" selected>sm1</option> 17 <option id="sm2">sm2</option> 18 <option id="sm3" selected>sm3</option> 19 <option id="sm4">sm4</option> 20 <option id="sm5">sm5</option> 21 <option id="sm6">sm6</option> 22 </select> 23 <select id="selectCombo" size="1"> 24 <option>sc1</option> 25 </select> 26 <div id="ariaListbox" role="listbox"> 27 <div id="al1" role="option" aria-selected="true">al1</div> 28 <div id="al2" role="option">al2</div> 29 </div> 30 <div id="tablist" role="tablist"> 31 <div id="t1" role="tab">t1</div> 32 <div id="t2" role="tab" aria-selected="true">t2</div> 33 </div> 34 <table id="grid" role="grid" aria-multiselectable="true"> 35 <tr> 36 <td id="g1">g1</td> 37 <td id="g2" role="gridcell" aria-selected="true">g2</td> 38 </tr> 39 <tr> 40 <td id="g3">g3</td> 41 <td id="g4" role="gridcell" aria-selected="true">g4</td> 42 </tr> 43 </table> 44 <div id="radiogroup" role="radiogroup"> 45 <label><input id="r1" type="radio" name="r" checked>r1</label> 46 <label><input id="r2" type="radio" name="r">r2</label> 47 </div> 48 <div id="menu" role="menu"> 49 <div id="m1" role="menuitem">m1</div> 50 <div id="m2" role="menuitemradio">m2</div> 51 <div id="m3" role="menuitemradio" aria-checked="true">m3</div> 52 </div> 53 <button id="button">button</button> 54 `; 55 56 async function testSelectionProps(id, selection, multiple, required) { 57 await assignPyVarToUiaWithId(id); 58 await definePyVar("pattern", `getUiaPattern(${id}, "Selection")`); 59 ok(await runPython(`bool(pattern)`), `${id} has Selection pattern`); 60 await isUiaElementArray( 61 `pattern.GetCurrentSelection()`, 62 selection, 63 `${id} has correct Selection` 64 ); 65 is( 66 !!(await runPython(`pattern.CurrentCanSelectMultiple`)), 67 multiple, 68 `${id} has correct CanSelectMultiple` 69 ); 70 // The IA2 -> UIA proxy doesn't reflect the required state correctly. 71 if (gIsUiaEnabled) { 72 is( 73 !!(await runPython(`pattern.CurrentIsSelectionRequired`)), 74 required, 75 `${id} has correct IsSelectionRequired` 76 ); 77 } 78 } 79 80 async function testSelectionItemProps(id, selected, container) { 81 await assignPyVarToUiaWithId(id); 82 await definePyVar("pattern", `getUiaPattern(${id}, "SelectionItem")`); 83 ok(await runPython(`bool(pattern)`), `${id} has SelectionItem pattern`); 84 is( 85 !!(await runPython(`pattern.CurrentIsSelected`)), 86 selected, 87 `${id} has correct IsSelected` 88 ); 89 if (container) { 90 is( 91 await runPython(`pattern.CurrentSelectionContainer.CurrentAutomationId`), 92 container, 93 `${id} has correct SelectionContainer` 94 ); 95 } else { 96 ok( 97 !(await runPython(`bool(pattern.CurrentSelectionContainer)`)), 98 `${id} has no SelectionContainer` 99 ); 100 } 101 } 102 103 /** 104 * Test the Selection pattern. 105 */ 106 addUiaTask(SNIPPET, async function testSelection(browser) { 107 await definePyVar("doc", `getDocUia()`); 108 await testSelectionProps("selectList", ["sl1"], false, false); 109 await testSelectionProps("selectRequired", [], false, true); 110 111 await testSelectionProps("selectMulti", ["sm1", "sm3"], true, false); 112 // The Selection pattern only has an event for a complete invalidation of the 113 // container's selection, which only happens when there are too many selection 114 // events. Smaller selection changes fire events in the SelectionItem pattern. 115 info("Changing selectMulti selection"); 116 await setUpWaitForUiaEvent("Selection_Invalidated", "selectMulti"); 117 await invokeContentTask(browser, [], () => { 118 const multi = content.document.getElementById("selectMulti"); 119 multi[0].selected = false; 120 multi[1].selected = true; 121 multi[2].selected = false; 122 multi[3].selected = true; 123 multi[4].selected = true; 124 multi[5].selected = true; 125 }); 126 await waitForUiaEvent(); 127 ok(true, "select got Invalidated event"); 128 await testSelectionProps( 129 "selectMulti", 130 ["sm2", "sm4", "sm5", "sm6"], 131 true, 132 false 133 ); 134 135 await testPatternAbsent("selectCombo", "Selection"); 136 137 await testSelectionProps("ariaListbox", ["al1"], false, false); 138 await testSelectionProps("tablist", ["t2"], false, false); 139 // The IA2 -> UIA proxy doesn't expose the Selection pattern on grids. 140 if (gIsUiaEnabled) { 141 await testSelectionProps("grid", ["g2", "g4"], true, false); 142 } 143 144 // radio gets the SelectionItem pattern, but radiogroup doesn't get the 145 // Selection pattern for now. Same for menu/menuitemradio. 146 await testPatternAbsent("radiogroup", "Selection"); 147 await testPatternAbsent("menu", "Selection"); 148 149 await testPatternAbsent("button", "Selection"); 150 }); 151 152 /** 153 * Test the SelectionItem pattern. 154 */ 155 addUiaTask(SNIPPET, async function testSelection(browser) { 156 await definePyVar("doc", `getDocUia()`); 157 await testPatternAbsent("selectList", "SelectionItem"); 158 await testSelectionItemProps("sl1", true, "selectList"); 159 await testSelectionItemProps("sl2", false, "selectList"); 160 info("Calling Select on sl2"); 161 await setUpWaitForUiaEvent("SelectionItem_ElementSelected", "sl2"); 162 await runPython(`pattern.Select()`); 163 await waitForUiaEvent(); 164 ok(true, "sl2 got ElementSelected event"); 165 await testSelectionItemProps("sl1", false, "selectList"); 166 await testSelectionItemProps("sl2", true, "selectList"); 167 168 await testSelectionItemProps("sr1", false, "selectRequired"); 169 170 await testSelectionItemProps("sm1", true, "selectMulti"); 171 await testSelectionItemProps("sm2", false, "selectMulti"); 172 info("Calling AddToSelection on sm2"); 173 await setUpWaitForUiaEvent("SelectionItem_ElementAddedToSelection", "sm2"); 174 await runPython(`pattern.AddToSelection()`); 175 await waitForUiaEvent(); 176 ok(true, "sm2 got ElementAddedToSelection event"); 177 await testSelectionItemProps("sm2", true, "selectMulti"); 178 await testSelectionItemProps("sm3", true, "selectMulti"); 179 info("Calling RemoveFromSelection on sm3"); 180 await setUpWaitForUiaEvent( 181 "SelectionItem_ElementRemovedFromSelection", 182 "sm3" 183 ); 184 await runPython(`pattern.RemoveFromSelection()`); 185 await waitForUiaEvent(); 186 ok(true, "sm3 got ElementRemovedFromSelection event"); 187 await testSelectionItemProps("sm3", false, "selectMulti"); 188 189 await testSelectionItemProps("t2", true, "tablist"); 190 await testSelectionItemProps("t1", false, "tablist"); 191 // The IA2 -> UIA proxy gets this wrong. 192 if (gIsUiaEnabled) { 193 info("Calling Select on t1"); 194 // Select on a tab should click it. 195 await invokeContentTask(browser, [], () => { 196 content.document.getElementById("t1").addEventListener("click", evt => { 197 evt.target.ariaSelected = "true"; 198 content.document.getElementById("t2").ariaSelected = "false"; 199 }); 200 }); 201 await setUpWaitForUiaEvent("SelectionItem_ElementSelected", "t1"); 202 await runPython(`pattern.Select()`); 203 await waitForUiaEvent(); 204 ok(true, "t1 got ElementSelected event"); 205 await testSelectionItemProps("t1", true, "tablist"); 206 await testSelectionItemProps("t2", false, "tablist"); 207 } 208 209 // The IA2 -> UIA proxy doesn't expose the SelectionItem pattern on grid 210 // cells. 211 if (gIsUiaEnabled) { 212 await testSelectionItemProps("g1", false, "grid"); 213 await testSelectionItemProps("g2", true, "grid"); 214 } 215 216 await testSelectionItemProps("r1", true, null); 217 await testSelectionItemProps("r2", false, null); 218 // The IA2 -> UIA proxy doesn't fire correct events for radio buttons. 219 if (gIsUiaEnabled) { 220 info("Calling Select on r2"); 221 await setUpWaitForUiaEvent("SelectionItem_ElementSelected", "r2"); 222 await runPython(`pattern.Select()`); 223 await waitForUiaEvent(); 224 ok(true, "r2 got ElementSelected event"); 225 await testSelectionItemProps("r1", false, null); 226 await testSelectionItemProps("r2", true, null); 227 info("Calling RemoveFromSelection on r2"); 228 await testPythonRaises( 229 `pattern.RemoveFromSelection()`, 230 "RemoveFromSelection failed on r2" 231 ); 232 } 233 234 await testPatternAbsent("m1", "SelectionItem"); 235 // The IA2 -> UIA proxy doesn't expose the SelectionItem pattern for radio 236 // menu items. 237 if (gIsUiaEnabled) { 238 await testSelectionItemProps("m2", false, null); 239 await testSelectionItemProps("m3", true, null); 240 } 241 242 await testPatternAbsent("button", "SelectionItem"); 243 });