/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ "use strict"; /* import-globals-from ../../../mochitest/role.js */ /* import-globals-from ../../../mochitest/states.js */ loadScripts( { name: "role.js", dir: MOCHITESTS_DIR }, { name: "states.js", dir: MOCHITESTS_DIR } ); /* eslint-disable camelcase */ const ExpandCollapseState_Collapsed = 0; const ExpandCollapseState_Expanded = 1; const ToggleState_Off = 0; const ToggleState_On = 1; const ToggleState_Indeterminate = 2; /* eslint-enable camelcase */ /** * Test the Invoke pattern. */ addUiaTask( `

p

`, async function testInvoke() { await definePyVar("doc", `getDocUia()`); await assignPyVarToUiaWithId("button"); await definePyVar("pattern", `getUiaPattern(button, "Invoke")`); ok(await runPython(`bool(pattern)`), "button has Invoke pattern"); info("Calling Invoke on button"); // The button will get focus when it is clicked. let focused = waitForEvent(EVENT_FOCUS, "button"); // The UIA -> IA2 proxy doesn't fire the Invoked event. if (gIsUiaEnabled) { await setUpWaitForUiaEvent("Invoke_Invoked", "button"); } await runPython(`pattern.Invoke()`); await focused; ok(true, "button got focus"); if (gIsUiaEnabled) { await waitForUiaEvent(); ok(true, "button got Invoked event"); } await testPatternAbsent("p", "Invoke"); // The Microsoft IA2 -> UIA proxy doesn't follow Microsoft's own rules. if (gIsUiaEnabled) { // Check boxes expose the Toggle pattern, so they should not expose the // Invoke pattern. await testPatternAbsent("checkbox", "Invoke"); } } ); /** * Test the Toggle pattern. */ addUiaTask( `

p

`, async function testToggle() { await definePyVar("doc", `getDocUia()`); await assignPyVarToUiaWithId("checkbox"); await definePyVar("pattern", `getUiaPattern(checkbox, "Toggle")`); ok(await runPython(`bool(pattern)`), "checkbox has Toggle pattern"); is( await runPython(`pattern.CurrentToggleState`), ToggleState_On, "checkbox has ToggleState_On" ); // The IA2 -> UIA proxy doesn't fire ToggleState prop change events. if (gIsUiaEnabled) { info("Calling Toggle on checkbox"); await setUpWaitForUiaPropEvent("ToggleToggleState", "checkbox"); await runPython(`pattern.Toggle()`); await waitForUiaEvent(); ok(true, "Got ToggleState prop change event on checkbox"); is( await runPython(`pattern.CurrentToggleState`), ToggleState_Off, "checkbox has ToggleState_Off" ); info("Calling Toggle on checkbox"); await setUpWaitForUiaPropEvent("ToggleToggleState", "checkbox"); await runPython(`pattern.Toggle()`); await waitForUiaEvent(); ok(true, "Got ToggleState prop change event on checkbox"); is( await runPython(`pattern.CurrentToggleState`), ToggleState_Indeterminate, "checkbox has ToggleState_Indeterminate" ); } await assignPyVarToUiaWithId("toggleButton"); await definePyVar("pattern", `getUiaPattern(toggleButton, "Toggle")`); ok(await runPython(`bool(pattern)`), "toggleButton has Toggle pattern"); is( await runPython(`pattern.CurrentToggleState`), ToggleState_Off, "toggleButton has ToggleState_Off" ); if (gIsUiaEnabled) { info("Calling Toggle on toggleButton"); await setUpWaitForUiaPropEvent("ToggleToggleState", "toggleButton"); await runPython(`pattern.Toggle()`); await waitForUiaEvent(); ok(true, "Got ToggleState prop change event on toggleButton"); is( await runPython(`pattern.CurrentToggleState`), ToggleState_On, "toggleButton has ToggleState_Off" ); } await testPatternAbsent("button", "Toggle"); await testPatternAbsent("p", "Toggle"); } ); /** * Test the ExpandCollapse pattern. */ addUiaTask( `
summary details
`, async function testExpandCollapse() { await definePyVar("doc", `getDocUia()`); await assignPyVarToUiaWithId("summary"); await definePyVar("pattern", `getUiaPattern(summary, "ExpandCollapse")`); ok(await runPython(`bool(pattern)`), "summary has ExpandCollapse pattern"); is( await runPython(`pattern.CurrentExpandCollapseState`), ExpandCollapseState_Collapsed, "summary has ExpandCollapseState_Collapsed" ); // The IA2 -> UIA proxy doesn't fire ToggleState prop change events, nor // does it fail when Expand/Collapse is called on a control which is // already in the desired state. if (gIsUiaEnabled) { info("Calling Expand on summary"); await setUpWaitForUiaPropEvent( "ExpandCollapseExpandCollapseState", "summary" ); await runPython(`pattern.Expand()`); await waitForUiaEvent(); ok( true, "Got ExpandCollapseExpandCollapseState prop change event on summary" ); is( await runPython(`pattern.CurrentExpandCollapseState`), ExpandCollapseState_Expanded, "summary has ExpandCollapseState_Expanded" ); info("Calling Expand on summary"); await testPythonRaises(`pattern.Expand()`, "Expand on summary failed"); info("Calling Collapse on summary"); await setUpWaitForUiaPropEvent( "ExpandCollapseExpandCollapseState", "summary" ); await runPython(`pattern.Collapse()`); await waitForUiaEvent(); ok( true, "Got ExpandCollapseExpandCollapseState prop change event on summary" ); is( await runPython(`pattern.CurrentExpandCollapseState`), ExpandCollapseState_Collapsed, "summary has ExpandCollapseState_Collapsed" ); info("Calling Collapse on summary"); await testPythonRaises( `pattern.Collapse()`, "Collapse on summary failed" ); } await assignPyVarToUiaWithId("popup"); // Initially, popup has aria-haspopup but not aria-expanded. That should // be exposed as collapsed. await definePyVar("pattern", `getUiaPattern(popup, "ExpandCollapse")`); ok(await runPython(`bool(pattern)`), "popup has ExpandCollapse pattern"); // The IA2 -> UIA proxy doesn't expose ExpandCollapseState_Collapsed for // aria-haspopup without aria-expanded. if (gIsUiaEnabled) { is( await runPython(`pattern.CurrentExpandCollapseState`), ExpandCollapseState_Collapsed, "popup has ExpandCollapseState_Collapsed" ); info("Calling Expand on popup"); await setUpWaitForUiaPropEvent( "ExpandCollapseExpandCollapseState", "popup" ); await runPython(`pattern.Expand()`); await waitForUiaEvent(); ok( true, "Got ExpandCollapseExpandCollapseState prop change event on popup" ); is( await runPython(`pattern.CurrentExpandCollapseState`), ExpandCollapseState_Expanded, "popup has ExpandCollapseState_Expanded" ); } await testPatternAbsent("button", "ExpandCollapse"); } ); /** * Test the ScrollItem pattern. */ addUiaTask( `
`, async function testScrollItem(browser, docAcc) { await definePyVar("doc", `getDocUia()`); await assignPyVarToUiaWithId("button"); await definePyVar("pattern", `getUiaPattern(button, "ScrollItem")`); ok(await runPython(`bool(pattern)`), "button has ScrollItem pattern"); const button = findAccessibleChildByID(docAcc, "button"); testStates(button, STATE_OFFSCREEN); info("Calling ScrollIntoView on button"); // UIA doesn't have an event for this. let scrolled = waitForEvent(EVENT_SCROLLING_END, docAcc); await runPython(`pattern.ScrollIntoView()`); await scrolled; ok(true, "Document scrolled"); testStates(button, 0, 0, STATE_OFFSCREEN); } ); /** * Test the Value pattern. */ addUiaTask( ` Link
before
`, async function testValue() { await definePyVar("doc", `getDocUia()`); await assignPyVarToUiaWithId("text"); await definePyVar("pattern", `getUiaPattern(text, "Value")`); ok(await runPython(`bool(pattern)`), "text has Value pattern"); ok( !(await runPython(`pattern.CurrentIsReadOnly`)), "text has IsReadOnly false" ); is( await runPython(`pattern.CurrentValue`), "before", "text has correct Value" ); info("SetValue on text"); await setUpWaitForUiaPropEvent("ValueValue", "text"); await runPython(`pattern.SetValue("after")`); await waitForUiaEvent(); is( await runPython(`pattern.CurrentValue`), "after", "text has correct Value" ); await assignPyVarToUiaWithId("textRo"); await definePyVar("pattern", `getUiaPattern(textRo, "Value")`); ok(await runPython(`bool(pattern)`), "textRo has Value pattern"); ok( await runPython(`pattern.CurrentIsReadOnly`), "textRo has IsReadOnly true" ); is( await runPython(`pattern.CurrentValue`), "textRo", "textRo has correct Value" ); info("SetValue on textRo"); await testPythonRaises( `pattern.SetValue("after")`, "SetValue on textRo failed" ); await assignPyVarToUiaWithId("textDis"); await definePyVar("pattern", `getUiaPattern(textDis, "Value")`); ok(await runPython(`bool(pattern)`), "textDis has Value pattern"); ok( !(await runPython(`pattern.CurrentIsReadOnly`)), "textDis has IsReadOnly false" ); is( await runPython(`pattern.CurrentValue`), "textDis", "textDis has correct Value" ); // The IA2 -> UIA proxy doesn't fail SetValue for a disabled element. if (gIsUiaEnabled) { info("SetValue on textDis"); await testPythonRaises( `pattern.SetValue("after")`, "SetValue on textDis failed" ); } await assignPyVarToUiaWithId("select"); await definePyVar("pattern", `getUiaPattern(select, "Value")`); ok(await runPython(`bool(pattern)`), "select has Value pattern"); ok( !(await runPython(`pattern.CurrentIsReadOnly`)), "select has IsReadOnly false" ); is( await runPython(`pattern.CurrentValue`), "a", "select has correct Value" ); info("SetValue on select"); await testPythonRaises( `pattern.SetValue("b")`, "SetValue on select failed" ); await assignPyVarToUiaWithId("progress"); await definePyVar("pattern", `getUiaPattern(progress, "Value")`); ok(await runPython(`bool(pattern)`), "progress has Value pattern"); // Gecko a11y doesn't treat progress bars as read only, but it probably // should. todo( await runPython(`pattern.CurrentIsReadOnly`), "progress has IsReadOnly true" ); is( await runPython(`pattern.CurrentValue`), "50%", "progress has correct Value" ); info("SetValue on progress"); await testPythonRaises( `pattern.SetValue("60%")`, "SetValue on progress failed" ); await assignPyVarToUiaWithId("range"); await definePyVar("pattern", `getUiaPattern(range, "Value")`); ok(await runPython(`bool(pattern)`), "range has Value pattern"); is( await runPython(`pattern.CurrentValue`), "02:00:00", "range has correct Value" ); await assignPyVarToUiaWithId("link"); await definePyVar("pattern", `getUiaPattern(link, "Value")`); ok(await runPython(`bool(pattern)`), "link has Value pattern"); is( await runPython(`pattern.CurrentValue`), "https://example.com/", "link has correct Value" ); await assignPyVarToUiaWithId("ariaTextbox"); await definePyVar("pattern", `getUiaPattern(ariaTextbox, "Value")`); ok(await runPython(`bool(pattern)`), "ariaTextbox has Value pattern"); ok( !(await runPython(`pattern.CurrentIsReadOnly`)), "ariaTextbox has IsReadOnly false" ); is( await runPython(`pattern.CurrentValue`), "before", "ariaTextbox has correct Value" ); info("SetValue on ariaTextbox"); await setUpWaitForUiaPropEvent("ValueValue", "ariaTextbox"); await runPython(`pattern.SetValue("after")`); await waitForUiaEvent(); is( await runPython(`pattern.CurrentValue`), "after", "ariaTextbox has correct Value" ); await testPatternAbsent("button", "Value"); } );