diff options
Diffstat (limited to 'accessible/tests/mochitest/events/test_statechange.html')
-rw-r--r-- | accessible/tests/mochitest/events/test_statechange.html | 317 |
1 files changed, 317 insertions, 0 deletions
diff --git a/accessible/tests/mochitest/events/test_statechange.html b/accessible/tests/mochitest/events/test_statechange.html new file mode 100644 index 0000000000..9dad6ed2f8 --- /dev/null +++ b/accessible/tests/mochitest/events/test_statechange.html @@ -0,0 +1,317 @@ +<html> + +<head> + <title>Accessible state change event testing</title> + + <link rel="stylesheet" type="text/css" + href="chrome://mochikit/content/tests/SimpleTest/test.css" /> + + <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + + <script type="application/javascript" + src="../common.js"></script> + <script type="application/javascript" + src="../promisified-events.js"></script> + <script type="application/javascript" + src="../role.js"></script> + <script type="application/javascript" + src="../states.js"></script> + + <script type="application/javascript"> + function stateChange(aState, aIsExtraState, aIsEnabled, aTarget) { + return [EVENT_STATE_CHANGE, evt => { + evt.QueryInterface(nsIAccessibleStateChangeEvent); + return evt.state == aState && evt.isExtraState == aIsExtraState && + aIsEnabled == evt.isEnabled && getAccessible(aTarget) == evt.accessible; + }]; + } + + async function openNode(aIDDetails, aIDSummary, aIsOpen) { + let p = waitForEvent(...stateChange(STATE_EXPANDED, false, aIsOpen, aIDSummary)); + if (aIsOpen) { + getNode(aIDDetails).setAttribute("open", ""); + } else { + getNode(aIDDetails).removeAttribute("open"); + } + await p; + } + + async function makeEditableDoc(aDocNode, aIsEnabled) { + let p = waitForEvent(...stateChange(EXT_STATE_EDITABLE, true, true, aDocNode)); + aDocNode.designMode = "on"; + await p; + } + + async function invalidInput(aNodeOrID) { + let p = waitForEvent(...stateChange(STATE_INVALID, false, true, aNodeOrID)); + getNode(aNodeOrID).value = "I am not an email"; + await p; + } + + async function changeCheckInput(aID, aIsChecked) { + let p = waitForEvent(...stateChange(STATE_CHECKED, false, aIsChecked, aID)); + getNode(aID).checked = aIsChecked; + await p; + } + + async function changeRequiredState(aID, aIsRequired) { + let p = waitForEvent(...stateChange(STATE_REQUIRED, false, aIsRequired, aID)); + getNode(aID).required = aIsRequired; + await p; + } + + async function stateChangeOnFileInput(aID, aAttr, aValue, + aState, aIsExtraState, aIsEnabled) { + let fileControlNode = getNode(aID); + let fileControl = getAccessible(fileControlNode); + let browseButton = fileControl.firstChild; + let p = waitForEvents([ + stateChange(aState, aIsExtraState, aIsEnabled, fileControl), + stateChange(aState, aIsExtraState, aIsEnabled, browseButton)]) + fileControlNode.setAttribute(aAttr, aValue); + await p; + } + + function toggleSentinel() { + let sentinel = getNode("sentinel"); + if (sentinel.hasAttribute("aria-busy")) { + sentinel.removeAttribute("aria-busy"); + } else { + sentinel.setAttribute("aria-busy", "true"); + } + } + + async function dupeStateChange(aID, aAttr, aValue, + aState, aIsExtraState, aIsEnabled) { + let p = waitForEvents([ + stateChange(aState, aIsExtraState, aIsEnabled, aID), + [EVENT_STATE_CHANGE, "sentinel"] + ]); + getNode(aID).setAttribute(aAttr, aValue); + getNode(aID).setAttribute(aAttr, aValue); + toggleSentinel(); + await p; + } + + async function oppositeStateChange(aID, aAttr, aState, aIsExtraState) { + let p = waitForEvents({ + expected: [[EVENT_STATE_CHANGE, "sentinel"]], + unexpected: [ + stateChange(aState, aIsExtraState, false, aID), + stateChange(aState, aIsExtraState, true, aID) + ] + }); + getNode(aID).setAttribute(aAttr, "false"); + getNode(aID).setAttribute(aAttr, "true"); + toggleSentinel(); + await p; + } + + /** + * Change concomitant ARIA and native attribute at once. + */ + async function echoingStateChange(aID, aARIAAttr, aAttr, aValue, + aState, aIsExtraState, aIsEnabled) { + let p = waitForEvent(...stateChange(aState, aIsExtraState, aIsEnabled, aID)); + if (aValue == null) { + getNode(aID).removeAttribute(aARIAAttr); + getNode(aID).removeAttribute(aAttr); + } else { + getNode(aID).setAttribute(aARIAAttr, aValue); + getNode(aID).setAttribute(aAttr, aValue); + } + await p; + } + + async function testLinked() { + let p = waitForEvent(...stateChange(STATE_LINKED, false, false, "link1")); + getNode("link1").removeAttribute("href"); + await p; + + p = waitForEvent(...stateChange(STATE_LINKED, false, false, "link2")); + getNode("link2").removeAttribute("onclick"); + await p; + + p = waitForEvent(...stateChange(STATE_LINKED, false, true, "link3")); + getNode("link3").setAttribute("href", "http://example.com"); + await p; + } + + async function testHasPopup() { + let p = waitForEvent(...stateChange(STATE_HASPOPUP, false, true, "popupButton")); + getNode("popupButton").setAttribute("aria-haspopup", "true"); + await p; + + p = waitForEvent(...stateChange(STATE_HASPOPUP, false, true, "popupButton")); + getNode("popupButton").setAttribute("aria-haspopup", "tree"); + await p; + + p = waitForEvent(...stateChange(STATE_HASPOPUP, false, true, "popupButton")); + getNode("popupButton").setAttribute("aria-haspopup", "menu"); + await p; + + p = waitForEvent(...stateChange(STATE_HASPOPUP, false, true, "popupButton")); + getNode("popupButton").setAttribute("aria-haspopup", "listbox"); + await p; + + p = waitForEvent(...stateChange(STATE_HASPOPUP, false, true, "popupButton")); + getNode("popupButton").setAttribute("aria-haspopup", "grid"); + await p; + + p = waitForEvent(...stateChange(STATE_HASPOPUP, false, false, "popupButton")); + getNode("popupButton").setAttribute("aria-haspopup", "false"); + await p; + + p = waitForEvent(...stateChange(STATE_HASPOPUP, false, true, "popupButton")); + getNode("popupButton").setAttribute("aria-haspopup", "dialog"); + await p; + + p = waitForEvent(...stateChange(STATE_HASPOPUP, false, false, "popupButton")); + getNode("popupButton").removeAttribute("aria-haspopup"); + await p; + } + + async function doTests() { + // Test opening details objects + await openNode("detailsOpen", "summaryOpen", true); + await openNode("detailsOpen", "summaryOpen", false); + await openNode("detailsOpen1", "summaryOpen1", true); + await openNode("detailsOpen2", "summaryOpen2", true); + await openNode("detailsOpen3", "summaryOpen3", true); + await openNode("detailsOpen4", "summaryOpen4", true); + await openNode("detailsOpen5", "summaryOpen5", true); + await openNode("detailsOpen6", "summaryOpen6", true); + + // Test delayed editable state change + var doc = document.getElementById("iframe").contentDocument; + await makeEditableDoc(doc); + + // invalid state change + await invalidInput("email"); + + // checked state change + await changeCheckInput("checkbox", true); + await changeCheckInput("checkbox", false); + await changeCheckInput("radio", true); + await changeCheckInput("radio", false); + + // required state change + await changeRequiredState("checkbox", true); + + // file input inherited state changes + await stateChangeOnFileInput("file", "aria-busy", "true", + STATE_BUSY, false, true); + await stateChangeOnFileInput("file", "aria-required", "true", + STATE_REQUIRED, false, true); + await stateChangeOnFileInput("file", "aria-invalid", "true", + STATE_INVALID, false, true); + + await dupeStateChange("div", "aria-busy", "true", + STATE_BUSY, false, true); + await oppositeStateChange("div", "aria-busy", + STATE_BUSY, false); + + await echoingStateChange("text1", "aria-disabled", "disabled", "true", + EXT_STATE_ENABLED, true, false); + await echoingStateChange("text1", "aria-disabled", "disabled", null, + EXT_STATE_ENABLED, true, true); + + await testLinked(); + + await testHasPopup(); + + SimpleTest.finish(); + } + + SimpleTest.waitForExplicitFinish(); + addA11yLoadEvent(doTests); + </script> +</head> +<style> + details.openBefore::before{ + content: "before detail content: "; + background: blue; + } + summary.openBefore::before{ + content: "before summary content: "; + background: green; + } + details.openAfter::after{ + content: " :after detail content"; + background: blue; + } + summary.openAfter::after{ + content: " :after summary content"; + background: green; + } +</style> +<body> + + <a target="_blank" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=564471" + title="Make state change events async"> + Bug 564471 + </a> + <a target="_blank" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=555728" + title="Fire a11y event based on HTML5 constraint validation"> + Bug 555728 + </a> + <a target="_blank" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=699017" + title="File input control should be propogate states to descendants"> + Bug 699017 + </a> + <a target="_blank" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=788389" + title="Fire statechange event whenever checked state is changed not depending on focused state"> + Bug 788389 + </a> + <a target="_blank" + href="https://bugzilla.mozilla.org/show_bug.cgi?id=926812" + title="State change event not fired when both disabled and aria-disabled are toggled"> + Bug 926812 + </a> + + <p id="display"></p> + <div id="content" style="display: none"></div> + <pre id="test"> + </pre> + + <!-- open --> + <details id="detailsOpen"><summary id="summaryOpen">open</summary>details can be opened</details> + <details id="detailsOpen1">order doesn't matter<summary id="summaryOpen1">open</summary></details> + <details id="detailsOpen2"><div>additional elements don't matter</div><summary id="summaryOpen2">open</summary></details> + <details id="detailsOpen3" class="openBefore"><summary id="summaryOpen3">summary</summary>content</details> + <details id="detailsOpen4" class="openAfter"><summary id="summaryOpen4">summary</summary>content</details> + <details id="detailsOpen5"><summary id="summaryOpen5" class="openBefore">summary</summary>content</details> + <details id="detailsOpen6"><summary id="summaryOpen6" class="openAfter">summary</summary>content</details> + + + <div id="testContainer"> + <iframe id="iframe"></iframe> + </div> + + <input id="email" type='email'> + + <input id="checkbox" type="checkbox"> + <input id="radio" type="radio"> + + <input id="file" type="file"> + + <div id="div"></div> + + <!-- A sentinal guards from events of interest being fired after it emits a state change --> + <div id="sentinel"></div> + + <input id="text1"> + + <a id="link1" href="#">I am a link link</a> + <a id="link2" onclick="console.log('hi')">I am a link-ish link</a> + <a id="link3">I am a non-link link</a> + + <div id="eventdump"></div> + + <button id="popupButton">action</button> +</body> +</html> |