Bug 1543575 - add fission specific accessibility tests. r=Jamie
authorYura Zenevich <yura.zenevich@gmail.com>
Thu, 14 Nov 2019 14:53:49 +0000
changeset 501942 14095bfec9dfb56a7e51983b196ce554e0c3eedf
parent 501941 23293a56f4790a29a30f35739c4ad72c60d74ff2
child 501943 e4d22a4ff32104f707015395dac47c8707fc1c04
push id114172
push userdluca@mozilla.com
push dateTue, 19 Nov 2019 11:31:10 +0000
treeherdermozilla-inbound@b5c5ba07d3db [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersJamie
bugs1543575
milestone72.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 1543575 - add fission specific accessibility tests. r=Jamie Differential Revision: https://phabricator.services.mozilla.com/D48583
accessible/moz.build
accessible/tests/browser/fission/browser.ini
accessible/tests/browser/fission/browser_content_tree.js
accessible/tests/browser/fission/browser_hidden_iframe.js
accessible/tests/browser/fission/browser_nested_iframe.js
accessible/tests/browser/fission/browser_reframe_root.js
accessible/tests/browser/fission/browser_reframe_visibility.js
accessible/tests/browser/fission/browser_src_change.js
accessible/tests/browser/fission/browser_take_focus.js
accessible/tests/browser/fission/head.js
accessible/tests/browser/shared-head.js
--- a/accessible/moz.build
+++ b/accessible/moz.build
@@ -31,16 +31,17 @@ if CONFIG['MOZ_XUL']:
 
 TEST_DIRS += ['tests/mochitest']
 
 BROWSER_CHROME_MANIFESTS += [
   'tests/browser/bounds/browser.ini',
   'tests/browser/browser.ini',
   'tests/browser/e10s/browser.ini',
   'tests/browser/events/browser.ini',
+  'tests/browser/fission/browser.ini',
   'tests/browser/general/browser.ini',
   'tests/browser/scroll/browser.ini',
   'tests/browser/states/browser.ini',
   'tests/browser/tree/browser.ini'
 ]
 
 with Files("**"):
     BUG_COMPONENT = ("Core", "Disability Access APIs")
new file mode 100644
--- /dev/null
+++ b/accessible/tests/browser/fission/browser.ini
@@ -0,0 +1,16 @@
+[DEFAULT]
+support-files =
+  head.js
+  !/accessible/tests/browser/shared-head.js
+  !/accessible/tests/browser/fission_document_builder.sjs
+  !/accessible/tests/browser/*.jsm
+  !/accessible/tests/mochitest/*.js
+
+[browser_content_tree.js]
+[browser_hidden_iframe.js]
+[browser_nested_iframe.js]
+[browser_reframe_root.js]
+[browser_reframe_visibility.js]
+[browser_src_change.js]
+[browser_take_focus.js]
+skip-if = fission || (os == 'win') # Bug 1556627 and 1594300 xpcAccessible::TakeFocus() is not implemented on Windows with e10s.
new file mode 100644
--- /dev/null
+++ b/accessible/tests/browser/fission/browser_content_tree.js
@@ -0,0 +1,75 @@
+/* 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 */
+loadScripts({ name: "role.js", dir: MOCHITESTS_DIR });
+
+addAccessibleTask(
+  `<table id="table">
+    <tr>
+      <td>cell1</td>
+      <td>cell2</td>
+    </tr>
+  </table>
+  <ul id="ul">
+    <li id="li">item1</li>
+  </ul>`,
+  async function(browser, fissionDocAcc, contentDocAcc) {
+    ok(fissionDocAcc, "Fission document accessible is present");
+    (gFissionBrowser ? isnot : is)(
+      browser.browsingContext.currentWindowGlobal.osPid,
+      browser.browsingContext.getChildren()[0].currentWindowGlobal.osPid,
+      `Content and fission documents are in ${
+        gFissionBrowser ? "separate processes" : "same process"
+      }.`
+    );
+
+    const tree = {
+      DOCUMENT: [
+        {
+          INTERNAL_FRAME: [
+            {
+              DOCUMENT: [
+                {
+                  TABLE: [
+                    {
+                      ROW: [
+                        { CELL: [{ TEXT_LEAF: [] }] },
+                        { CELL: [{ TEXT_LEAF: [] }] },
+                      ],
+                    },
+                  ],
+                },
+                {
+                  LIST: [
+                    {
+                      LISTITEM: [{ STATICTEXT: [] }, { TEXT_LEAF: [] }],
+                    },
+                  ],
+                },
+              ],
+            },
+          ],
+        },
+      ],
+    };
+    testAccessibleTree(contentDocAcc, tree);
+
+    const iframeAcc = contentDocAcc.getChildAt(0);
+    is(
+      iframeAcc.getChildAt(0),
+      fissionDocAcc,
+      "Fission document for the IFRAME matches."
+    );
+
+    is(
+      fissionDocAcc.parent,
+      iframeAcc,
+      "Fission document's parent matches the IFRAME."
+    );
+  },
+  { topLevel: false, iframe: true }
+);
new file mode 100644
--- /dev/null
+++ b/accessible/tests/browser/fission/browser_hidden_iframe.js
@@ -0,0 +1,81 @@
+/* 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/states.js */
+/* import-globals-from ../../mochitest/role.js */
+loadScripts({ name: "states.js", dir: MOCHITESTS_DIR });
+loadScripts({ name: "role.js", dir: MOCHITESTS_DIR });
+
+addAccessibleTask(
+  `<input id="textbox" value="hello"/>`,
+  async function(browser, contentDocAcc) {
+    info(
+      "Check that the IFRAME and the fission document are not accessible initially."
+    );
+    let iframeAcc = findAccessibleChildByID(contentDocAcc, FISSION_IFRAME_ID);
+    let fissionDocAcc = findAccessibleChildByID(
+      contentDocAcc,
+      DEFAULT_FISSION_DOC_BODY_ID
+    );
+    ok(!iframeAcc, "IFRAME is hidden and should not be accessible");
+    ok(!fissionDocAcc, "fission document is hidden and should be accessible");
+
+    info(
+      "Show the IFRAME and check that it's now available in the accessibility tree."
+    );
+
+    const events = [[EVENT_REORDER, contentDocAcc]];
+    if (!gFissionBrowser) {
+      // Until this event is fired, IFRAME accessible has no children attached.
+      events.push([
+        EVENT_STATE_CHANGE,
+        event => {
+          const scEvent = event.QueryInterface(nsIAccessibleStateChangeEvent);
+          const id = getAccessibleDOMNodeID(event.accessible);
+          return (
+            id === DEFAULT_FISSION_DOC_BODY_ID &&
+            scEvent.state === STATE_BUSY &&
+            scEvent.isEnabled === false
+          );
+        },
+      ]);
+    }
+    const onEvents = waitForEvents(events);
+    await SpecialPowers.spawn(browser, [FISSION_IFRAME_ID], contentId => {
+      content.document.getElementById(contentId).style.display = "";
+    });
+    await onEvents;
+
+    iframeAcc = findAccessibleChildByID(contentDocAcc, FISSION_IFRAME_ID);
+    fissionDocAcc = findAccessibleChildByID(
+      contentDocAcc,
+      DEFAULT_FISSION_DOC_BODY_ID
+    );
+
+    ok(!isDefunct(iframeAcc), "IFRAME should be accessible");
+    is(iframeAcc.childCount, 1, "IFRAME accessible should have a single child");
+    ok(fissionDocAcc, "fission document exists");
+    ok(!isDefunct(fissionDocAcc), "fission document should be accessible");
+    is(
+      iframeAcc.firstChild,
+      fissionDocAcc,
+      "An accessible for a fission document is the child of the IFRAME accessible"
+    );
+    is(
+      fissionDocAcc.parent,
+      iframeAcc,
+      "Fission document's parent matches the IFRAME."
+    );
+  },
+  {
+    topLevel: false,
+    iframe: true,
+    fissionIFrameAttrs: {
+      style: "display: none;",
+    },
+    skipFissionDocLoad: true,
+  }
+);
new file mode 100644
--- /dev/null
+++ b/accessible/tests/browser/fission/browser_nested_iframe.js
@@ -0,0 +1,142 @@
+/* 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 */
+loadScripts({ name: "role.js", dir: MOCHITESTS_DIR });
+
+const NESTED_FISSION_DOC_BODY_ID = "nested-fission-body";
+const NESTED_FISSION_IFRAME_ID = "nested-fission-iframe";
+const nestedURL = new URL(
+  `http://example.net${CURRENT_FILE_DIR}fission_document_builder.sjs`
+);
+nestedURL.searchParams.append(
+  "html",
+  `<html>
+      <head>
+        <meta charset="utf-8"/>
+        <title>Accessibility Nested Fission Frame Test</title>
+      </head>
+      <body id="${NESTED_FISSION_DOC_BODY_ID}">
+        <table id="table">
+          <tr>
+            <td>cell1</td>
+            <td>cell2</td>
+          </tr>
+        </table>
+        <ul id="ul">
+          <li id="li">item1</li>
+        </ul>
+      </body>
+    </html>`
+);
+
+function getOsPid(browsingContext) {
+  return browsingContext.currentWindowGlobal.osPid;
+}
+
+addAccessibleTask(
+  `<iframe id="${NESTED_FISSION_IFRAME_ID}" src="${nestedURL.href}"/>`,
+  async function(browser, fissionDocAcc, contentDocAcc) {
+    let nestedDocAcc = findAccessibleChildByID(
+      fissionDocAcc,
+      NESTED_FISSION_DOC_BODY_ID
+    );
+
+    ok(fissionDocAcc, "Fission document accessible is present");
+    ok(nestedDocAcc, "Nested fission document accessible is present");
+
+    const state = {};
+    nestedDocAcc.getState(state, {});
+    if (state.value & STATE_BUSY) {
+      nestedDocAcc = (await waitForEvent(
+        EVENT_DOCUMENT_LOAD_COMPLETE,
+        NESTED_FISSION_DOC_BODY_ID
+      )).accessible;
+    }
+
+    if (gFissionBrowser) {
+      isnot(
+        getOsPid(browser.browsingContext),
+        getOsPid(browser.browsingContext.getChildren()[0]),
+        `Content and fission documents are in separate processes.`
+      );
+      isnot(
+        getOsPid(browser.browsingContext),
+        getOsPid(browser.browsingContext.getChildren()[0].getChildren()[0]),
+        `Content and nested fission documents are in separate processes.`
+      );
+      isnot(
+        getOsPid(browser.browsingContext.getChildren()[0]),
+        getOsPid(browser.browsingContext.getChildren()[0].getChildren()[0]),
+        `Fission and nested fission documents are in separate processes.`
+      );
+    } else {
+      is(
+        getOsPid(browser.browsingContext),
+        getOsPid(browser.browsingContext.getChildren()[0]),
+        `Content and fission documents are in same processes.`
+      );
+      is(
+        getOsPid(browser.browsingContext),
+        getOsPid(browser.browsingContext.getChildren()[0].getChildren()[0]),
+        `Content and nested fission documents are in same processes.`
+      );
+    }
+
+    const tree = {
+      DOCUMENT: [
+        {
+          INTERNAL_FRAME: [
+            {
+              DOCUMENT: [
+                {
+                  INTERNAL_FRAME: [
+                    {
+                      DOCUMENT: [
+                        {
+                          TABLE: [
+                            {
+                              ROW: [
+                                { CELL: [{ TEXT_LEAF: [] }] },
+                                { CELL: [{ TEXT_LEAF: [] }] },
+                              ],
+                            },
+                          ],
+                        },
+                        {
+                          LIST: [
+                            {
+                              LISTITEM: [{ STATICTEXT: [] }, { TEXT_LEAF: [] }],
+                            },
+                          ],
+                        },
+                      ],
+                    },
+                  ],
+                },
+              ],
+            },
+          ],
+        },
+      ],
+    };
+    testAccessibleTree(contentDocAcc, tree);
+
+    const nestedIframeAcc = fissionDocAcc.getChildAt(0);
+    is(
+      nestedIframeAcc.getChildAt(0),
+      nestedDocAcc,
+      "Nested fission document for nested IFRAME matches."
+    );
+
+    is(
+      nestedDocAcc.parent,
+      nestedIframeAcc,
+      "Nested fission document's parent matches the nested IFRAME."
+    );
+  },
+  { topLevel: false, iframe: true }
+);
new file mode 100644
--- /dev/null
+++ b/accessible/tests/browser/fission/browser_reframe_root.js
@@ -0,0 +1,95 @@
+/* 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/states.js */
+/* import-globals-from ../../mochitest/role.js */
+loadScripts(
+  { name: "role.js", dir: MOCHITESTS_DIR },
+  { name: "states.js", dir: MOCHITESTS_DIR }
+);
+
+addAccessibleTask(
+  `<input id="textbox" value="hello"/>`,
+  async function(browser, fissionDocAcc, contentDocAcc) {
+    info(
+      "Check that the IFRAME and the fission document are accessible initially."
+    );
+    let iframeAcc = findAccessibleChildByID(contentDocAcc, FISSION_IFRAME_ID);
+    ok(!isDefunct(iframeAcc), "IFRAME should be accessible");
+    ok(!isDefunct(fissionDocAcc), "fission document should be accessible");
+
+    info("Move the IFRAME under a new hidden root.");
+    let onEvents = waitForEvent(EVENT_REORDER, contentDocAcc);
+    await SpecialPowers.spawn(browser, [FISSION_IFRAME_ID], id => {
+      const doc = content.document;
+      const root = doc.createElement("div");
+      root.style.display = "none";
+      doc.body.appendChild(root);
+      root.appendChild(doc.getElementById(id));
+    });
+    await onEvents;
+
+    ok(
+      isDefunct(iframeAcc),
+      "IFRAME accessible should be defunct when hidden."
+    );
+    ok(
+      isDefunct(fissionDocAcc),
+      "IFRAME document's accessible should be defunct when the IFRAME is hidden."
+    );
+    ok(
+      !findAccessibleChildByID(contentDocAcc, FISSION_IFRAME_ID),
+      "No accessible for an IFRAME present."
+    );
+    ok(
+      !findAccessibleChildByID(contentDocAcc, DEFAULT_FISSION_DOC_BODY_ID),
+      "No accessible for the fission document present."
+    );
+
+    info("Move the IFRAME back under the content document's body.");
+    onEvents = waitForEvents([
+      [EVENT_REORDER, contentDocAcc],
+      [
+        EVENT_STATE_CHANGE,
+        event => {
+          const scEvent = event.QueryInterface(nsIAccessibleStateChangeEvent);
+          const id = getAccessibleDOMNodeID(event.accessible);
+          return (
+            id === DEFAULT_FISSION_DOC_BODY_ID &&
+            scEvent.state === STATE_BUSY &&
+            scEvent.isEnabled === false
+          );
+        },
+      ],
+    ]);
+    await SpecialPowers.spawn(browser, [FISSION_IFRAME_ID], id => {
+      content.document.body.appendChild(content.document.getElementById(id));
+    });
+    await onEvents;
+
+    iframeAcc = findAccessibleChildByID(contentDocAcc, FISSION_IFRAME_ID);
+    const newFissionDocAcc = iframeAcc.firstChild;
+
+    ok(!isDefunct(iframeAcc), "IFRAME should be accessible");
+    is(iframeAcc.childCount, 1, "IFRAME accessible should have a single child");
+    ok(!isDefunct(newFissionDocAcc), "fission document should be accessible");
+    ok(
+      isDefunct(fissionDocAcc),
+      "Original IFRAME document accessible should be defunct."
+    );
+    isnot(
+      iframeAcc.firstChild,
+      fissionDocAcc,
+      "A new accessible is created for a fission document."
+    );
+    is(
+      iframeAcc.firstChild,
+      newFissionDocAcc,
+      "A new accessible for a fission document is the child of the IFRAME accessible"
+    );
+  },
+  { topLevel: false, iframe: true }
+);
new file mode 100644
--- /dev/null
+++ b/accessible/tests/browser/fission/browser_reframe_visibility.js
@@ -0,0 +1,116 @@
+/* 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/states.js */
+/* import-globals-from ../../mochitest/role.js */
+loadScripts({ name: "states.js", dir: MOCHITESTS_DIR });
+loadScripts({ name: "role.js", dir: MOCHITESTS_DIR });
+
+addAccessibleTask(
+  `<input id="textbox" value="hello"/>`,
+  async function(browser, fissionDocAcc, contentDocAcc) {
+    info(
+      "Check that the IFRAME and the fission document are accessible initially."
+    );
+    let iframeAcc = findAccessibleChildByID(contentDocAcc, FISSION_IFRAME_ID);
+    ok(!isDefunct(iframeAcc), "IFRAME should be accessible");
+    ok(!isDefunct(fissionDocAcc), "fission document should be accessible");
+
+    info(
+      "Hide the IFRAME and check that it's gone along with the fission document."
+    );
+    let onEvents = waitForEvent(EVENT_REORDER, contentDocAcc);
+    await SpecialPowers.spawn(browser, [FISSION_IFRAME_ID], contentId => {
+      content.document.getElementById(contentId).style.display = "none";
+    });
+    await onEvents;
+
+    ok(
+      isDefunct(iframeAcc),
+      "IFRAME accessible should be defunct when hidden."
+    );
+    if (gFissionBrowser) {
+      ok(
+        !isDefunct(fissionDocAcc),
+        "IFRAME document's accessible is not defunct when the IFRAME is hidden and fission is enabled."
+      );
+    } else {
+      ok(
+        isDefunct(fissionDocAcc),
+        "IFRAME document's accessible is defunct when the IFRAME is hidden and fission is not enabled."
+      );
+    }
+    ok(
+      !findAccessibleChildByID(contentDocAcc, FISSION_IFRAME_ID),
+      "No accessible for an IFRAME present."
+    );
+    ok(
+      !findAccessibleChildByID(contentDocAcc, DEFAULT_FISSION_DOC_BODY_ID),
+      "No accessible for the fission document present."
+    );
+
+    info(
+      "Show the IFRAME and check that a new accessible is created for it as " +
+        "well as the fission document."
+    );
+
+    const events = [[EVENT_REORDER, contentDocAcc]];
+    if (!gFissionBrowser) {
+      events.push([
+        EVENT_STATE_CHANGE,
+        event => {
+          const scEvent = event.QueryInterface(nsIAccessibleStateChangeEvent);
+          const id = getAccessibleDOMNodeID(event.accessible);
+          return (
+            id === DEFAULT_FISSION_DOC_BODY_ID &&
+            scEvent.state === STATE_BUSY &&
+            scEvent.isEnabled === false
+          );
+        },
+      ]);
+    }
+    onEvents = waitForEvents(events);
+    await SpecialPowers.spawn(browser, [FISSION_IFRAME_ID], contentId => {
+      content.document.getElementById(contentId).style.display = "block";
+    });
+    await onEvents;
+
+    iframeAcc = findAccessibleChildByID(contentDocAcc, FISSION_IFRAME_ID);
+    const newFissionDocAcc = iframeAcc.firstChild;
+
+    ok(!isDefunct(iframeAcc), "IFRAME should be accessible");
+    is(iframeAcc.childCount, 1, "IFRAME accessible should have a single child");
+    ok(newFissionDocAcc, "fission document exists");
+    ok(!isDefunct(newFissionDocAcc), "fission document should be accessible");
+    if (gFissionBrowser) {
+      ok(
+        !isDefunct(fissionDocAcc),
+        "Original IFRAME document accessible should not be defunct when fission is enabled."
+      );
+      is(
+        iframeAcc.firstChild,
+        fissionDocAcc,
+        "Existing accessible is used for a fission document."
+      );
+    } else {
+      ok(
+        isDefunct(fissionDocAcc),
+        "Original IFRAME document accessible should be defunct when fission is not enabled."
+      );
+      isnot(
+        iframeAcc.firstChild,
+        fissionDocAcc,
+        "A new accessible is created for a fission document."
+      );
+    }
+    is(
+      iframeAcc.firstChild,
+      newFissionDocAcc,
+      "A new accessible for a fission document is the child of the IFRAME accessible"
+    );
+  },
+  { topLevel: false, iframe: true }
+);
new file mode 100644
--- /dev/null
+++ b/accessible/tests/browser/fission/browser_src_change.js
@@ -0,0 +1,61 @@
+/* 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 */
+loadScripts({ name: "role.js", dir: MOCHITESTS_DIR });
+
+addAccessibleTask(
+  `<input id="textbox" value="hello"/>`,
+  async function(browser, fissionDocAcc, contentDocAcc) {
+    info(
+      "Check that the IFRAME and the fission document are accessible initially."
+    );
+    let iframeAcc = findAccessibleChildByID(contentDocAcc, FISSION_IFRAME_ID);
+    ok(isAccessible(iframeAcc), "IFRAME should be accessible");
+    ok(isAccessible(fissionDocAcc), "fission document should be accessible");
+
+    info("Replace src URL for the IFRAME with one with different origin.");
+    const onDocLoad = waitForEvent(
+      EVENT_DOCUMENT_LOAD_COMPLETE,
+      DEFAULT_FISSION_DOC_BODY_ID
+    );
+
+    await SpecialPowers.spawn(
+      browser,
+      [FISSION_IFRAME_ID, CURRENT_CONTENT_DIR],
+      (id, olddir) => {
+        const { src } = content.document.getElementById(id);
+        content.document.getElementById(id).src = src.replace(
+          olddir,
+          "http://example.net/browser/accessible/tests/browser/"
+        );
+      }
+    );
+    const newFissionDocAcc = (await onDocLoad).accessible;
+
+    ok(isAccessible(iframeAcc), "IFRAME should be accessible");
+    ok(
+      isAccessible(newFissionDocAcc),
+      "new fission document should be accessible"
+    );
+    isnot(
+      fissionDocAcc,
+      newFissionDocAcc,
+      "A new accessible is created for a fission document."
+    );
+    is(
+      iframeAcc.firstChild,
+      newFissionDocAcc,
+      "An IFRAME has a new accessible for a fission document as a child."
+    );
+    is(
+      newFissionDocAcc.parent,
+      iframeAcc,
+      "A new accessible for a fission document has an IFRAME as a parent."
+    );
+  },
+  { topLevel: false, iframe: true }
+);
new file mode 100644
--- /dev/null
+++ b/accessible/tests/browser/fission/browser_take_focus.js
@@ -0,0 +1,26 @@
+/* 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/states.js */
+loadScripts(
+  { name: "role.js", dir: MOCHITESTS_DIR },
+  { name: "states.js", dir: MOCHITESTS_DIR }
+);
+
+addAccessibleTask(
+  `<input id="textbox" value="hello"/>`,
+  async function(browser, fissionDocAcc, contentDocAcc) {
+    const textbox = findAccessibleChildByID(fissionDocAcc, "textbox");
+    testStates(textbox, STATE_FOCUSABLE, 0, STATE_FOCUSED);
+
+    let onFocus = waitForEvent(EVENT_FOCUS, textbox);
+    textbox.takeFocus();
+    await onFocus;
+
+    testStates(textbox, STATE_FOCUSABLE | STATE_FOCUSED, 0);
+  },
+  { topLevel: false, iframe: true }
+);
new file mode 100644
--- /dev/null
+++ b/accessible/tests/browser/fission/head.js
@@ -0,0 +1,19 @@
+/* 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";
+
+// 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
+// well as promisified-events.js.
+loadScripts(
+  { name: "common.js", dir: MOCHITESTS_DIR },
+  { name: "promisified-events.js", dir: MOCHITESTS_DIR }
+);
--- a/accessible/tests/browser/shared-head.js
+++ b/accessible/tests/browser/shared-head.js
@@ -272,16 +272,17 @@ async function loadContentScripts(target
 function attrsToString(attrs) {
   return Object.entries(attrs)
     .map(([attr, value]) => `${attr}=${JSON.stringify(value)}`)
     .join(" ");
 }
 
 function wrapWithFissionIFrame(doc, options = {}) {
   const srcURL = new URL(`${CURRENT_CONTENT_DIR}fission_document_builder.sjs`);
+  const { fissionIFrameAttrs = {} } = options;
   if (doc.endsWith("html")) {
     srcURL.searchParams.append("file", `${CURRENT_FILE_DIR}e10s/${doc}`);
   } else {
     const { fissionDocBodyAttrs = {} } = options;
     const attrs = {
       id: DEFAULT_FISSION_DOC_BODY_ID,
       ...fissionDocBodyAttrs,
     };
@@ -293,17 +294,23 @@ function wrapWithFissionIFrame(doc, opti
           <meta charset="utf-8"/>
           <title>Accessibility Fission Test</title>
         </head>
         <body ${attrsToString(attrs)}>${doc}</body>
       </html>`
     );
   }
 
-  return `<iframe id="${FISSION_IFRAME_ID}" src="${srcURL.href}"/>`;
+  const iframeAttrs = {
+    id: FISSION_IFRAME_ID,
+    src: srcURL.href,
+    ...fissionIFrameAttrs,
+  };
+
+  return `<iframe ${attrsToString(iframeAttrs)}/>`;
 }
 
 /**
  * Takes an HTML snippet or HTML doc url and returns an encoded URI for a full
  * document with the snippet or the URL as a source for the IFRAME.
  * @param {String} doc
  *        a markup snippet or url.
  * @param {Object} options
@@ -363,17 +370,17 @@ function accessibleTask(doc, task, optio
     const onContentDocLoad = waitForEvent(
       EVENT_DOCUMENT_LOAD_COMPLETE,
       DEFAULT_CONTENT_DOC_BODY_ID
     );
 
     let onFissionDocLoad;
     if (options.fission) {
       gIsFission = true;
-      if (gFissionBrowser) {
+      if (gFissionBrowser && !options.skipFissionDocLoad) {
         onFissionDocLoad = waitForEvent(
           EVENT_DOCUMENT_LOAD_COMPLETE,
           DEFAULT_FISSION_DOC_BODY_ID
         );
       }
     }
 
     await BrowserTestUtils.withNewTab(
@@ -396,17 +403,17 @@ function accessibleTask(doc, task, optio
 
         Logger.log(
           `e10s enabled: ${Services.appinfo.browserTabsRemoteAutostart}`
         );
         Logger.log(`Actually remote browser: ${browser.isRemoteBrowser}`);
 
         const { accessible: docAccessible } = await onContentDocLoad;
         let fissionDocAccessible;
-        if (options.fission) {
+        if (options.fission && !options.skipFissionDocLoad) {
           fissionDocAccessible = gFissionBrowser
             ? (await onFissionDocLoad).accessible
             : findAccessibleChildByID(docAccessible, FISSION_IFRAME_ID)
                 .firstChild;
         }
 
         await task(
           browser,
@@ -429,28 +436,31 @@ function accessibleTask(doc, task, optio
  * @param  {null|Object} options
  *         Options for running accessibility test tasks:
  *         - {Boolean} topLevel
  *           Flag to run the test with content in the top level content process.
  *           Default is true.
  *         - {Boolean} iframe
  *           Flag to run the test with content wrapped in an iframe. Default is
  *           false.
+ *         - {Object} fissionIFrameAttrs
+ *           A map of attribute/value pairs to be applied to fission IFRAME
+ *           element.
+ *         - {Boolean} skipFissionDocLoad
+ *           If true, the test will wait not for fission document document
+ *           loaded event (useful for when fission IFRAME is initially hidden).
  */
-function addAccessibleTask(
-  doc,
-  task,
-  { topLevel = true, iframe = false } = {}
-) {
+function addAccessibleTask(doc, task, options = {}) {
+  const { topLevel = true, iframe = false } = options;
   if (topLevel) {
-    add_task(accessibleTask(doc, task));
+    add_task(accessibleTask(doc, task, options));
   }
 
   if (iframe) {
-    add_task(accessibleTask(doc, task, { fission: true }));
+    add_task(accessibleTask(doc, task, { ...options, fission: true }));
   }
 }
 
 /**
  * Check if an accessible object has a defunct test.
  * @param  {nsIAccessible}  accessible object to test defunct state for
  * @return {Boolean}        flag indicating defunct state
  */