head.js (4992B)
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 /* exported gIsUiaEnabled, addUiaTask, definePyVar, assignPyVarToUiaWithId, setUpWaitForUiaEvent, setUpWaitForUiaPropEvent, waitForUiaEvent, testPatternAbsent, testPythonRaises, isUiaElementArray */ 8 9 // Load the shared-head file first. 10 Services.scriptloader.loadSubScript( 11 "chrome://mochitests/content/browser/accessible/tests/browser/shared-head.js", 12 this 13 ); 14 15 // Loading and common.js from accessible/tests/mochitest/ for all tests, as 16 // well as promisified-events.js and layout.js. 17 loadScripts( 18 { name: "common.js", dir: MOCHITESTS_DIR }, 19 { name: "promisified-events.js", dir: MOCHITESTS_DIR }, 20 { name: "layout.js", dir: MOCHITESTS_DIR } 21 ); 22 23 let gIsUiaEnabled = false; 24 25 /** 26 * This is like addAccessibleTask, but takes two additional boolean options: 27 * - uiaEnabled: Whether to run a variation of this test with Gecko UIA enabled. 28 * - uiaDisabled: Whether to run a variation of this test with UIA disabled. In 29 * this case, UIA will rely entirely on the IA2 -> UIA proxy. 30 * If both are set, the test will be run twice with different configurations. 31 * You can determine which variant is currently running using the gIsUiaEnabled 32 * variable. This is useful for conditional tests; e.g. if Gecko UIA supports 33 * something that the IA2 -> UIA proxy doesn't support. 34 */ 35 function addUiaTask(doc, task, options = {}) { 36 const { uiaEnabled = true, uiaDisabled = true } = options; 37 38 function addTask(shouldEnable) { 39 async function uiaTask(browser, docAcc, topDocAcc) { 40 await SpecialPowers.pushPrefEnv({ 41 // 1 means enable unconditionally. 2 means enable only if NVDA or JAWS 42 // isn't detected. The user could be running a screen reader while 43 // running the tests, so use 1 to enable unconditionally lest the tests 44 // fail. 45 set: [["accessibility.uia.enable", shouldEnable ? 1 : 0]], 46 }); 47 gIsUiaEnabled = shouldEnable; 48 info(shouldEnable ? "Gecko UIA enabled" : "Gecko UIA disabled"); 49 await task(browser, docAcc, topDocAcc); 50 } 51 // Propagate the name of the task function to our wrapper function so it shows 52 // up in test run output. Suffix with the test type. For example: 53 // 0:39.16 INFO Entering test bound testProtected_uiaEnabled_remoteIframe 54 // The "name" property of functions is not writable, but we can override that 55 // using Object.defineProperty. 56 let name = task.name; 57 if (name) { 58 name += shouldEnable ? "_uiaEnabled" : "_uiaDisabled"; 59 } 60 Object.defineProperty(uiaTask, "name", { value: name }); 61 addAccessibleTask(doc, uiaTask, options); 62 } 63 64 if (uiaEnabled) { 65 addTask(true); 66 } 67 if (uiaDisabled) { 68 addTask(false); 69 } 70 } 71 72 /** 73 * Define a global Python variable and assign it to a given Python expression. 74 */ 75 function definePyVar(varName, expression) { 76 return runPython(` 77 global ${varName} 78 ${varName} = ${expression} 79 `); 80 } 81 82 /** 83 * Get the UIA element with the given id and assign it to a global Python 84 * variable using the id as the variable name. 85 */ 86 function assignPyVarToUiaWithId(id) { 87 return definePyVar(id, `findUiaByDomId(doc, "${id}")`); 88 } 89 90 /** 91 * Set up to wait for a UIA event. You must await this before performing the 92 * action which fires the event. 93 */ 94 function setUpWaitForUiaEvent(eventName, id) { 95 return definePyVar( 96 "onEvent", 97 `WaitForUiaEvent(eventId=UIA_${eventName}EventId, match="${id}")` 98 ); 99 } 100 101 /** 102 * Set up to wait for a UIA property change event. You must await this before 103 * performing the action which fires the event. 104 */ 105 function setUpWaitForUiaPropEvent(propName, id) { 106 return definePyVar( 107 "onEvent", 108 `WaitForUiaEvent(property=UIA_${propName}PropertyId, match="${id}")` 109 ); 110 } 111 112 /** 113 * Wait for the event requested in setUpWaitForUia*Event. 114 */ 115 function waitForUiaEvent() { 116 return runPython(` 117 onEvent.wait() 118 `); 119 } 120 121 /** 122 * Verify that a UIA element does *not* support the given control pattern. 123 */ 124 async function testPatternAbsent(id, patternName) { 125 const hasPattern = await runPython(` 126 el = findUiaByDomId(doc, "${id}") 127 return bool(getUiaPattern(el, "${patternName}")) 128 `); 129 ok(!hasPattern, `${id} doesn't have ${patternName} pattern`); 130 } 131 132 /** 133 * Verify that a Python expression raises an exception. 134 */ 135 async function testPythonRaises(expression, message) { 136 let failed = false; 137 try { 138 await runPython(expression); 139 } catch { 140 failed = true; 141 } 142 ok(failed, message); 143 } 144 145 /** 146 * Verify that an array of UIA elements contains (only) elements with the given 147 * DOM ids. 148 */ 149 async function isUiaElementArray(pyExpr, ids, message) { 150 const result = await runPython(` 151 uias = (${pyExpr}) 152 return [uias.GetElement(i).CurrentAutomationId for i in range(uias.Length)] 153 `); 154 SimpleTest.isDeeply(result, ids, message); 155 }