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/. */
7 const { UrlbarTestUtils } = ChromeUtils.importESModule(
8 "resource://testing-common/UrlbarTestUtils.sys.mjs"
10 /* import-globals-from ../../mochitest/role.js */
11 /* import-globals-from ../../mochitest/states.js */
13 { name: "role.js", dir: MOCHITESTS_DIR },
14 { name: "states.js", dir: MOCHITESTS_DIR }
17 function getMacAccessible(accOrElmOrID) {
18 return new Promise(resolve => {
19 let intervalId = setInterval(() => {
20 let acc = getAccessible(accOrElmOrID);
22 clearInterval(intervalId);
24 acc.nativeInterface.QueryInterface(Ci.nsIAccessibleMacInterface)
32 * Test a11yUtils announcements are exposed to VO
34 add_task(async () => {
35 const tab = await BrowserTestUtils.openNewForegroundTab(
39 const alert = document.getElementById("a11y-announcement");
40 ok(alert, "Found alert to send announcements");
42 const alerted = waitForMacEvent("AXAnnouncementRequested", (iface, data) => {
43 return data.AXAnnouncementKey == "hello world";
50 await BrowserTestUtils.removeTab(tab);
56 add_task(async () => {
57 let newTabs = await Promise.all([
58 BrowserTestUtils.openNewForegroundTab(
60 "data:text/html,<title>Two</title>"
62 BrowserTestUtils.openNewForegroundTab(
64 "data:text/html,<title>Three</title>"
66 BrowserTestUtils.openNewForegroundTab(
68 "data:text/html,<title>Four</title>"
72 // Mochitests spawn with a tab, and we've opened 3 more for a total of 4 tabs
73 is(gBrowser.tabs.length, 4, "We now have 4 open tabs");
75 let tablist = await getMacAccessible("tabbrowser-tabs");
77 tablist.getAttributeValue("AXRole"),
79 "Correct role for tablist"
82 let tabMacAccs = tablist.getAttributeValue("AXTabs");
83 is(tabMacAccs.length, 4, "4 items in AXTabs");
85 let selectedTabs = tablist.getAttributeValue("AXSelectedChildren");
86 is(selectedTabs.length, 1, "one selected tab");
88 let tab = selectedTabs[0];
89 is(tab.getAttributeValue("AXRole"), "AXRadioButton", "Correct role for tab");
91 tab.getAttributeValue("AXSubrole"),
93 "Correct subrole for tab"
95 is(tab.getAttributeValue("AXTitle"), "Four", "Correct title for tab");
97 let tabToSelect = tabMacAccs[2];
99 tabToSelect.getAttributeValue("AXTitle"),
101 "Correct title for tab"
104 let actions = tabToSelect.actionNames;
106 ok(actions.includes("AXPress"), "Has switch action");
108 // When tab is clicked selection of tab group changes,
109 // and focus goes to the web area. Wait for both.
110 let evt = Promise.all([
111 waitForMacEvent("AXSelectedChildrenChanged"),
113 "AXFocusedUIElementChanged",
114 iface => iface.getAttributeValue("AXRole") == "AXWebArea"
117 tabToSelect.performAction("AXPress");
120 selectedTabs = tablist.getAttributeValue("AXSelectedChildren");
121 is(selectedTabs.length, 1, "one selected tab");
123 selectedTabs[0].getAttributeValue("AXTitle"),
125 "Correct title for tab"
128 // Close all open tabs
129 await Promise.all(newTabs.map(t => BrowserTestUtils.removeTab(t)));
133 * Test ignored invisible items in root
135 add_task(async () => {
136 await BrowserTestUtils.withNewTab(
139 url: "about:license",
142 let root = await getMacAccessible(document);
143 let rootChildCount = () => root.getAttributeValue("AXChildren").length;
145 // With no popups, the root accessible has 5 visible children:
146 // 1. Tab bar (#TabsToolbar)
147 // 2. Navigation bar (#nav-bar)
148 // 3. Content area (#tabbrowser-tabpanels)
149 // 4. Some fullscreen pointer grabber (#fullscreen-and-pointerlock-wrapper)
150 // 5. Accessibility announcements dialog (#a11y-announcement)
151 let baseRootChildCount = 5;
155 "Root with no popups has 5 children"
158 // Open a context menu
159 const menu = document.getElementById("contentAreaContextMenu");
161 Services.prefs.getBoolPref("widget.macos.native-context-menus", false)
163 // Native context menu - do not expect accessibility notifications.
164 let popupshown = BrowserTestUtils.waitForPopupEvent(menu, "shown");
165 EventUtils.synthesizeMouseAtCenter(document.body, {
173 "Native context menus do not show up in the root children"
176 // Close context menu
177 let popuphidden = BrowserTestUtils.waitForPopupEvent(menu, "hidden");
182 EventUtils.synthesizeMouseAtCenter(document.body, {
185 await waitForMacEvent("AXMenuOpened");
187 // Now root has 1 more child
188 is(rootChildCount(), baseRootChildCount + 1, "Root has 1 more child");
190 // Close context menu
191 let closed = waitForMacEvent("AXMenuClosed", "contentAreaContextMenu");
192 EventUtils.synthesizeKey("KEY_Escape");
193 await BrowserTestUtils.waitForPopupEvent(menu, "hidden");
197 // We're back to base child count
198 is(rootChildCount(), baseRootChildCount, "Root has original child count");
200 // Open site identity popup
201 document.getElementById("identity-icon-box").click();
202 const identityPopup = document.getElementById("identity-popup");
203 await BrowserTestUtils.waitForPopupEvent(identityPopup, "shown");
205 // Now root has another child
206 is(rootChildCount(), baseRootChildCount + 1, "Root has another child");
209 let hide = waitForMacEvent("AXUIElementDestroyed");
210 EventUtils.synthesizeKey("KEY_Escape");
211 await BrowserTestUtils.waitForPopupEvent(identityPopup, "hidden");
214 // We're back to the base child count
215 is(rootChildCount(), baseRootChildCount, "Root has the base child count");
221 * Tests for location bar
223 add_task(async () => {
224 await BrowserTestUtils.withNewTab(
227 // eslint-disable-next-line @microsoft/sdl/no-insecure-url
228 url: "http://example.com",
231 let input = await getMacAccessible("urlbar-input");
233 input.getAttributeValue("AXValue"),
234 // eslint-disable-next-line @microsoft/sdl/no-insecure-url
235 UrlbarTestUtils.trimURL("http://example.com"),
236 "Location bar has correct value"
245 add_task(async () => {
246 if (Services.prefs.getBoolPref("widget.macos.native-context-menus", false)) {
247 ok(true, "We cannot inspect native context menu contents; skip this test.");
251 await BrowserTestUtils.withNewTab(
254 url: 'data:text/html,<a id="exampleLink" href="https://example.com">link</a>',
257 if (!Services.search.isInitialized) {
258 let aStatus = await Services.search.init();
259 Assert.ok(Components.isSuccessCode(aStatus));
260 Assert.ok(Services.search.isInitialized);
263 const hasContainers =
264 Services.prefs.getBoolPref("privacy.userContext.enabled") &&
265 !!ContextualIdentityService.getPublicIdentities().length;
266 info(`${hasContainers ? "Do" : "Don't"} expect containers item.`);
267 const hasInspectA11y =
268 Services.prefs.getBoolPref("devtools.everOpened", false) ||
269 Services.prefs.getIntPref("devtools.selfxss.count", 0) > 0;
270 info(`${hasInspectA11y ? "Do" : "Don't"} expect inspect a11y item.`);
272 // synthesize a right click on the link to open the link context menu
273 let menu = document.getElementById("contentAreaContextMenu");
274 await BrowserTestUtils.synthesizeMouseAtCenter(
276 { type: "contextmenu" },
279 await waitForMacEvent("AXMenuOpened");
281 menu = await getMacAccessible(menu);
282 let menuChildren = menu.getAttributeValue("AXChildren");
283 const expectedChildCount = 12 + +hasContainers + +hasInspectA11y;
287 `Context menu on link contains ${expectedChildCount} items.`
289 // items at indicies 3, 9, and 11 are the splitters when containers exist
290 // everything else should be a menu item, otherwise indicies of splitters are
292 const splitterIndicies = hasContainers ? [4, 9, 11] : [3, 8, 10];
293 for (let i = 0; i < menuChildren.length; i++) {
294 if (splitterIndicies.includes(i)) {
296 menuChildren[i].getAttributeValue("AXRole"),
298 "found splitter in menu"
302 menuChildren[i].getAttributeValue("AXRole"),
304 "found menu item in menu"
309 // check the containers sub menu in depth if it exists
312 menuChildren[1].getAttributeValue("AXVisibleChildren"),
314 "Submenu 1 has no visible chldren when hidden"
317 // focus the first submenu
318 EventUtils.synthesizeKey("KEY_ArrowDown");
319 EventUtils.synthesizeKey("KEY_ArrowDown");
320 EventUtils.synthesizeKey("KEY_ArrowRight");
321 await waitForMacEvent("AXMenuOpened");
323 // after the submenu is opened, refetch it
324 menu = document.getElementById("contentAreaContextMenu");
325 menu = await getMacAccessible(menu);
326 menuChildren = menu.getAttributeValue("AXChildren");
328 // verify submenu-menuitem's attributes
330 menuChildren[1].getAttributeValue("AXChildren").length,
332 "Submenu 1 has one child when open"
334 const subMenu = menuChildren[1].getAttributeValue("AXChildren")[0];
336 subMenu.getAttributeValue("AXRole"),
338 "submenu has role of menu"
340 const subMenuChildren = subMenu.getAttributeValue("AXChildren");
341 is(subMenuChildren.length, 4, "sub menu has 4 children");
343 subMenu.getAttributeValue("AXVisibleChildren").length,
345 "submenu has 4 visible children"
348 // close context menu
349 EventUtils.synthesizeKey("KEY_Escape");
350 await waitForMacEvent("AXMenuClosed");
353 EventUtils.synthesizeKey("KEY_Escape");
354 await waitForMacEvent("AXMenuClosed");