browser_markup_accessibility_navigation.js (7892B)
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 /* import-globals-from helper_markup_accessibility_navigation.js */ 5 6 "use strict"; 7 8 // Test keyboard navigation accessibility of inspector's markup view. 9 10 loadHelperScript("helper_markup_accessibility_navigation.js"); 11 12 /** 13 * Test data has the format of: 14 * { 15 * desc {String} description for better logging 16 * key {String} key event's key 17 * options {?Object} optional event data such as shiftKey, etc 18 * focused {String} path to expected focused element relative to 19 * its container 20 * activedescendant {String} path to expected aria-activedescendant element 21 * relative to its container 22 * waitFor {String} optional event to wait for if keyboard actions 23 * result in asynchronous updates 24 * } 25 */ 26 const TESTS = [ 27 { 28 desc: "Collapse body container", 29 focused: "root.elt", 30 activedescendant: "body.tagLine", 31 key: "VK_LEFT", 32 options: {}, 33 waitFor: "collapsed", 34 }, 35 { 36 desc: "Expand body container", 37 focused: "root.elt", 38 activedescendant: "body.tagLine", 39 key: "VK_RIGHT", 40 options: {}, 41 waitFor: "expanded", 42 }, 43 { 44 desc: "Select header container", 45 focused: "root.elt", 46 activedescendant: "header.tagLine", 47 key: "VK_DOWN", 48 options: {}, 49 waitFor: "inspector-updated", 50 }, 51 { 52 desc: "Expand header container", 53 focused: "root.elt", 54 activedescendant: "header.tagLine", 55 key: "VK_RIGHT", 56 options: {}, 57 waitFor: "expanded", 58 }, 59 { 60 desc: "Select text container", 61 focused: "root.elt", 62 activedescendant: "container-0.tagLine", 63 key: "VK_DOWN", 64 options: {}, 65 waitFor: "inspector-updated", 66 }, 67 { 68 desc: "Select header container again", 69 focused: "root.elt", 70 activedescendant: "header.tagLine", 71 key: "VK_UP", 72 options: {}, 73 waitFor: "inspector-updated", 74 }, 75 { 76 desc: "Collapse header container", 77 focused: "root.elt", 78 activedescendant: "header.tagLine", 79 key: "VK_LEFT", 80 options: {}, 81 waitFor: "collapsed", 82 }, 83 { 84 desc: "Focus on header container tag", 85 focused: "header.focusableElms.0", 86 activedescendant: "header.tagLine", 87 key: "VK_RETURN", 88 options: {}, 89 }, 90 { 91 desc: "Remove focus from header container tag", 92 focused: "root.elt", 93 activedescendant: "header.tagLine", 94 key: "VK_ESCAPE", 95 options: {}, 96 }, 97 { 98 desc: "Focus on header container tag again", 99 focused: "header.focusableElms.0", 100 activedescendant: "header.tagLine", 101 key: "VK_SPACE", 102 options: {}, 103 }, 104 { 105 desc: "Focus on header id attribute", 106 focused: "header.focusableElms.1", 107 activedescendant: "header.tagLine", 108 key: "VK_TAB", 109 options: {}, 110 }, 111 { 112 desc: "Focus on header class attribute", 113 focused: "header.focusableElms.2", 114 activedescendant: "header.tagLine", 115 key: "VK_TAB", 116 options: {}, 117 }, 118 { 119 desc: "Focus on header new attribute", 120 focused: "header.focusableElms.3", 121 activedescendant: "header.tagLine", 122 key: "VK_TAB", 123 options: {}, 124 }, 125 { 126 desc: "Circle back and focus on header tag again", 127 focused: "header.focusableElms.0", 128 activedescendant: "header.tagLine", 129 key: "VK_TAB", 130 options: {}, 131 }, 132 { 133 desc: "Circle back and focus on header new attribute again", 134 focused: "header.focusableElms.3", 135 activedescendant: "header.tagLine", 136 key: "VK_TAB", 137 options: { shiftKey: true }, 138 }, 139 { 140 desc: "Tab back and focus on header class attribute", 141 focused: "header.focusableElms.2", 142 activedescendant: "header.tagLine", 143 key: "VK_TAB", 144 options: { shiftKey: true }, 145 }, 146 { 147 desc: "Tab back and focus on header id attribute", 148 focused: "header.focusableElms.1", 149 activedescendant: "header.tagLine", 150 key: "VK_TAB", 151 options: { shiftKey: true }, 152 }, 153 { 154 desc: "Tab back and focus on header tag", 155 focused: "header.focusableElms.0", 156 activedescendant: "header.tagLine", 157 key: "VK_TAB", 158 options: { shiftKey: true }, 159 }, 160 { 161 desc: "Expand header container, ensure that focus is still on header tag", 162 focused: "header.focusableElms.0", 163 activedescendant: "header.tagLine", 164 key: "VK_RIGHT", 165 options: {}, 166 waitFor: "expanded", 167 }, 168 { 169 desc: "Activate header tag editor", 170 focused: "header.editor.tag.inplaceEditor.input", 171 activedescendant: "header.tagLine", 172 key: "VK_RETURN", 173 options: {}, 174 }, 175 { 176 desc: "Activate header id attribute editor", 177 focused: "header.editor.attrList.children.0.children.1.inplaceEditor.input", 178 activedescendant: "header.tagLine", 179 key: "VK_TAB", 180 options: {}, 181 }, 182 { 183 desc: "Deselect text in header id attribute editor", 184 focused: "header.editor.attrList.children.0.children.1.inplaceEditor.input", 185 activedescendant: "header.tagLine", 186 key: "VK_TAB", 187 options: {}, 188 }, 189 { 190 desc: "Activate header class attribute editor", 191 focused: "header.editor.attrList.children.1.children.1.inplaceEditor.input", 192 activedescendant: "header.tagLine", 193 key: "VK_TAB", 194 options: {}, 195 }, 196 { 197 desc: "Deselect text in header class attribute editor", 198 focused: "header.editor.attrList.children.1.children.1.inplaceEditor.input", 199 activedescendant: "header.tagLine", 200 key: "VK_TAB", 201 options: {}, 202 }, 203 { 204 desc: "Activate header new attribute editor", 205 focused: "header.editor.newAttr.inplaceEditor.input", 206 activedescendant: "header.tagLine", 207 key: "VK_TAB", 208 options: {}, 209 }, 210 { 211 desc: "Circle back and activate header tag editor again", 212 focused: "header.editor.tag.inplaceEditor.input", 213 activedescendant: "header.tagLine", 214 key: "VK_TAB", 215 options: {}, 216 }, 217 { 218 desc: "Circle back and activate header new attribute editor again", 219 focused: "header.editor.newAttr.inplaceEditor.input", 220 activedescendant: "header.tagLine", 221 key: "VK_TAB", 222 options: { shiftKey: true }, 223 }, 224 { 225 desc: "Exit edit mode and keep focus on header new attribute", 226 focused: "header.focusableElms.3", 227 activedescendant: "header.tagLine", 228 key: "VK_ESCAPE", 229 options: {}, 230 }, 231 { 232 desc: "Move the selection to body and reset focus to container tree", 233 focused: "docBody", 234 activedescendant: "body.tagLine", 235 key: "VK_UP", 236 options: {}, 237 waitFor: "inspector-updated", 238 }, 239 ]; 240 241 let containerID = 0; 242 let elms = {}; 243 244 add_task(async function () { 245 const { inspector } = await openInspectorForURL(`data:text/html;charset=utf-8, 246 <h1 id="some-id" class="some-class">foo<span>Child span<span></h1>`); 247 248 // Record containers that are created after inspector is initialized to be 249 // useful in testing. 250 inspector.on("container-created", memorizeContainer); 251 registerCleanupFunction(() => { 252 inspector.off("container-created", memorizeContainer); 253 }); 254 255 elms.docBody = inspector.markup.doc.body; 256 elms.root = inspector.markup.getContainer(inspector.markup._rootNode); 257 elms.header = await getContainerForSelector("h1", inspector); 258 elms.body = await getContainerForSelector("body", inspector); 259 260 // Initial focus is on root element and active descendant should be set on 261 // body tag line. 262 testNavigationState(inspector, elms, elms.docBody, elms.body.tagLine); 263 264 // Focus on the tree element. 265 elms.root.elt.focus(); 266 267 for (const testData of TESTS) { 268 await runAccessibilityNavigationTest(inspector, elms, testData); 269 } 270 271 elms = null; 272 }); 273 274 // Record all containers that are created dynamically into elms object. 275 function memorizeContainer(container) { 276 elms[`container-${containerID++}`] = container; 277 }