Bug 1388256 - improving stability of name caching test. r=eeejay
authorYura Zenevich <yura.zenevich@gmail.com>
Thu, 05 Oct 2017 16:20:48 -0400
changeset 385483 3c5cbd09b60457cc82f3483d0c27978ac700ecc8
parent 385482 bac56848856c47cc41b38e994e9fb12f0bb415de
child 385484 ea3bce8585831403a2a9b4760cf5488b5c538143
push id32656
push userarchaeopteryx@coole-files.de
push dateWed, 11 Oct 2017 09:50:40 +0000
treeherdermozilla-central@20d9ad08dd36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerseeejay
bugs1388256
milestone58.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1388256 - improving stability of name caching test. r=eeejay MozReview-Commit-ID: A6yoo3CZEyP
accessible/tests/browser/.eslintrc.js
accessible/tests/browser/e10s/browser_caching_name.js
accessible/tests/browser/events.js
accessible/tests/browser/tree/head.js
--- a/accessible/tests/browser/.eslintrc.js
+++ b/accessible/tests/browser/.eslintrc.js
@@ -1,14 +1,17 @@
 "use strict";
 
 module.exports = {
   "extends": [
     "plugin:mozilla/browser-test"
   ],
+  "globals": {
+    "gBrowser": false
+  },
   "rules": {
     "mozilla/no-aArgs": "error",
     "mozilla/no-cpows-in-tests": "error",
     "mozilla/reject-importGlobalProperties": "error",
     "mozilla/var-only-at-top-level": "error",
 
     "block-scoped-var": "error",
     "camelcase": "error",
--- a/accessible/tests/browser/e10s/browser_caching_name.js
+++ b/accessible/tests/browser/e10s/browser_caching_name.js
@@ -307,100 +307,99 @@ const markupTests = [{
     <a id="a-img"
        aria-label="test1"
        aria-labelledby="l1 l2"
        title="test4"><img alt="test5"/></a>`,
   expected: ["test2 test3", "test1", "test5", "test4"]
 }];
 
 /**
- * Wait for an accessible event to happen and, in case given accessible is
- * defunct, update it to one that is attached to the accessible event.
- * @param {Promise} onEvent      accessible event promise
- * @param {Object}  target       { acc, parent, id } structure that contains an
- *                                accessible, its parent and its content element
- *                                id.
- */
-async function updateAccessibleIfNeeded(onEvent, target) {
-  let event = await onEvent;
-  if (isDefunct(target.acc)) {
-    target.acc = findAccessibleChildByID(event.accessible, target.id);
-  }
-}
-
-/**
  * Test accessible name that is calculated from an attribute, remove the
  * attribute before proceeding to the next name test. If attribute removal
  * results in a reorder or text inserted event - wait for it. If accessible
  * becomes defunct, update its reference using the one that is attached to one
  * of the above events.
  * @param {Object} browser      current "tabbrowser" element
  * @param {Object} target       { acc, parent, id } structure that contains an
  *                               accessible, its parent and its content element
  *                               id.
  * @param {Object} rule         current attr rule for name calculation
  * @param {[type]} expected     expected name value
  */
 async function testAttrRule(browser, target, rule, expected) {
-  testName(target.acc, expected);
-  let onEvent;
-  if (rule.recreated) {
-    onEvent = waitForEvent(EVENT_REORDER, target.parent);
-  } else if (rule.textchanged) {
-    onEvent = waitForEvent(EVENT_TEXT_INSERTED, target.id);
-  }
-  await invokeSetAttribute(browser, target.id, rule.attr);
-  if (onEvent) {
-    await updateAccessibleIfNeeded(onEvent, target);
+  let {id, parent, acc} = target;
+  let {recreated, textchanged, attr} = rule;
+
+  testName(acc, expected);
+
+  if (recreated || textchanged) {
+    let [event] = await contentSpawnMutation(browser, {
+      expected: [recreated ? [EVENT_REORDER, parent] : [EVENT_TEXT_INSERTED, id]]
+    }, ([contentId, contentAttr]) =>
+      document.getElementById(contentId).removeAttribute(contentAttr), [id, attr]);
+
+    // Update accessible just in case it is now defunct.
+    target.acc = findAccessibleChildByID(event.accessible, id);
+  } else {
+    await invokeSetAttribute(browser, id, attr);
   }
 }
 
 /**
  * Test accessible name that is calculated from an element name, remove the
  * element before proceeding to the next name test. If element removal results
  * in a reorder event - wait for it. If accessible becomes defunct, update its
  * reference using the one that is attached to a possible reorder event.
  * @param {Object} browser      current "tabbrowser" element
  * @param {Object} target       { acc, parent, id } structure that contains an
  *                               accessible, its parent and its content element
  *                               id.
  * @param {Object} rule         current elm rule for name calculation
  * @param {[type]} expected     expected name value
  */
 async function testElmRule(browser, target, rule, expected) {
-  testName(target.acc, expected);
-  let onEvent = waitForEvent(EVENT_REORDER, rule.isSibling ?
-    target.parent : target.id);
-  await ContentTask.spawn(browser, rule.elm, elm =>
-    content.document.querySelector(`${elm}`).remove());
-  await updateAccessibleIfNeeded(onEvent, target);
+  let {id, parent, acc} = target;
+  let {isSibling, elm} = rule;
+
+  testName(acc, expected);
+  let [event] = await contentSpawnMutation(browser, {
+    expected: [[EVENT_REORDER, isSibling ? parent : id]]
+  }, contentElm => document.querySelector(`${contentElm}`).remove(), elm);
+
+  // Update accessible just in case it is now defunct.
+  target.acc = findAccessibleChildByID(event.accessible, id);
 }
 
 /**
  * Test accessible name that is calculated from its subtree, remove the subtree
  * and wait for a reorder event before proceeding to the next name test. If
  * accessible becomes defunct, update its reference using the one that is
  * attached to a reorder event.
  * @param {Object} browser      current "tabbrowser" element
  * @param {Object} target       { acc, parent, id } structure that contains an
  *                               accessible, its parent and its content element
  *                               id.
  * @param {Object} rule         current subtree rule for name calculation
  * @param {[type]} expected     expected name value
  */
 async function testSubtreeRule(browser, target, rule, expected) {
-  testName(target.acc, expected);
-  let onEvent = waitForEvent(EVENT_REORDER, target.id);
-  await ContentTask.spawn(browser, target.id, id => {
-    let elm = content.document.getElementById(id);
+  let {id, acc} = target;
+
+  testName(acc, expected);
+  let [event] = await contentSpawnMutation(browser, {
+    expected: [[EVENT_REORDER, id]]
+  }, contentId => {
+    let elm = document.getElementById(contentId);
     while (elm.firstChild) {
       elm.firstChild.remove();
     }
-  });
-  await updateAccessibleIfNeeded(onEvent, target);
+  }, id);
+
+  // Update accessible just in case it is now defunct.
+  target.acc = findAccessibleChildByID(event.accessible, id);
 }
 
 /**
  * Iterate over a list of rules and test accessible names for each one of the
  * rules.
  * @param {Object} browser      current "tabbrowser" element
  * @param {Object} target       { acc, parent, id } structure that contains an
  *                               accessible, its parent and its content element
--- a/accessible/tests/browser/events.js
+++ b/accessible/tests/browser/events.js
@@ -8,17 +8,17 @@
 // globals from there.
 /* import-globals-from shared-head.js */
 /* import-globals-from ../mochitest/common.js */
 
 /* exported EVENT_REORDER, EVENT_SHOW, EVENT_TEXT_INSERTED, EVENT_TEXT_REMOVED,
             EVENT_DOCUMENT_LOAD_COMPLETE, EVENT_HIDE, EVENT_TEXT_CARET_MOVED,
             EVENT_DESCRIPTION_CHANGE, EVENT_NAME_CHANGE, EVENT_STATE_CHANGE,
             EVENT_VALUE_CHANGE, EVENT_TEXT_VALUE_CHANGE, EVENT_FOCUS,
-            EVENT_DOCUMENT_RELOAD, UnexpectedEvents,
+            EVENT_DOCUMENT_RELOAD, UnexpectedEvents, contentSpawnMutation,
             waitForEvent, waitForEvents, waitForOrderedEvents */
 
 const EVENT_DOCUMENT_LOAD_COMPLETE = nsIAccessibleEvent.EVENT_DOCUMENT_LOAD_COMPLETE;
 const EVENT_HIDE = nsIAccessibleEvent.EVENT_HIDE;
 const EVENT_REORDER = nsIAccessibleEvent.EVENT_REORDER;
 const EVENT_SHOW = nsIAccessibleEvent.EVENT_SHOW;
 const EVENT_STATE_CHANGE = nsIAccessibleEvent.EVENT_STATE_CHANGE;
 const EVENT_TEXT_CARET_MOVED = nsIAccessibleEvent.EVENT_TEXT_CARET_MOVED;
@@ -178,8 +178,49 @@ function waitForEvents(events, ordered =
     unexpectedListener.stop();
     return results;
   });
 }
 
 function waitForOrderedEvents(events) {
   return waitForEvents(events, true);
 }
+
+/*
+ * This function spawns a content task and awaits expected mutation events from
+ * various content changes. It's good at catching events we did *not* expect. We
+ * do this advancing the layout refresh to flush the relocations/insertions
+ * queue.
+ */
+async function contentSpawnMutation(browser, waitFor, func, args = null) {
+  let onReorders = waitForEvents({ expected: waitFor.expected || [] });
+  let unexpectedListener = new UnexpectedEvents(waitFor.unexpected || []);
+
+  function tick() {
+    // 100ms is an arbitrary positive number to advance the clock.
+    // We don't need to advance the clock for a11y mutations, but other
+    // tick listeners may depend on an advancing clock with each refresh.
+    content.QueryInterface(Ci.nsIInterfaceRequestor)
+      .getInterface(Ci.nsIDOMWindowUtils).advanceTimeAndRefresh(100);
+  }
+
+  // This stops the refreh driver from doing its regular ticks, and leaves
+  // us in control.
+  await ContentTask.spawn(browser, null, tick);
+
+  // Perform the tree mutation.
+  await ContentTask.spawn(browser, args, func);
+
+  // Do one tick to flush our queue (insertions, relocations, etc.)
+  await ContentTask.spawn(browser, null, tick);
+
+  let events = await onReorders;
+
+  unexpectedListener.stop();
+
+  // Go back to normal refresh driver ticks.
+  await ContentTask.spawn(browser, null, function() {
+    content.QueryInterface(Ci.nsIInterfaceRequestor)
+      .getInterface(Ci.nsIDOMWindowUtils).restoreNormalRefresh();
+  });
+
+  return events;
+}
--- a/accessible/tests/browser/tree/head.js
+++ b/accessible/tests/browser/tree/head.js
@@ -1,15 +1,15 @@
 /* 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";
 
-/* exported contentSpawnMutation, testChildrenIds */
+/* exported testChildrenIds */
 
 // Load the shared-head file first.
 /* import-globals-from ../shared-head.js */
 Services.scriptloader.loadSubScript(
   "chrome://mochitests/content/browser/accessible/tests/browser/shared-head.js",
   this);
 
 // Loading and common.js from accessible/tests/mochitest/ for all tests, as
@@ -20,46 +20,8 @@ loadScripts({ name: "common.js", dir: MO
  * A test function for comparing the IDs of an accessible's children
  * with an expected array of IDs.
  */
 function testChildrenIds(acc, expectedIds) {
   let ids = arrayFromChildren(acc).map(child => getAccessibleDOMNodeID(child));
   Assert.deepEqual(ids, expectedIds,
     `Children for ${getAccessibleDOMNodeID(acc)} are wrong.`);
 }
-
-/*
- * This function spawns a content task and awaits expected mutation events from
- * aria-owns changes. It's good at catching events we did *not* expect. We do
- * this advancing the layout refresh to flush the relocations/insertions queue.
- */
-async function contentSpawnMutation(browser, waitFor, func) {
-  let onReorders = waitForEvents({ expected: waitFor.expected || [] });
-  let unexpectedListener = new UnexpectedEvents(waitFor.unexpected || []);
-
-  function tick() {
-    // 100ms is an arbitrary positive number to advance the clock.
-    // We don't need to advance the clock for a11y mutations, but other
-    // tick listeners may depend on an advancing clock with each refresh.
-    content.QueryInterface(Ci.nsIInterfaceRequestor)
-      .getInterface(Ci.nsIDOMWindowUtils).advanceTimeAndRefresh(100);
-  }
-
-  // This stops the refreh driver from doing its regular ticks, and leaves
-  // us in control.
-  await ContentTask.spawn(browser, null, tick);
-
-  // Perform the tree mutation.
-  await ContentTask.spawn(browser, null, func);
-
-  // Do one tick to flush our queue (insertions, relocations, etc.)
-  await ContentTask.spawn(browser, null, tick);
-
-  await onReorders;
-
-  unexpectedListener.stop();
-
-  // Go back to normal refresh driver ticks.
-  await ContentTask.spawn(browser, null, function() {
-    content.QueryInterface(Ci.nsIInterfaceRequestor)
-      .getInterface(Ci.nsIDOMWindowUtils).restoreNormalRefresh();
-  });
-}