summaryrefslogtreecommitdiffstats
path: root/accessible/tests/mochitest/events/test_statechange.html
diff options
context:
space:
mode:
Diffstat (limited to 'accessible/tests/mochitest/events/test_statechange.html')
-rw-r--r--accessible/tests/mochitest/events/test_statechange.html317
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>