summaryrefslogtreecommitdiffstats
path: root/accessible/tests/browser/selectable
diff options
context:
space:
mode:
Diffstat (limited to 'accessible/tests/browser/selectable')
-rw-r--r--accessible/tests/browser/selectable/browser.ini12
-rw-r--r--accessible/tests/browser/selectable/browser_test_aria_select.js164
-rw-r--r--accessible/tests/browser/selectable/browser_test_select.js329
-rw-r--r--accessible/tests/browser/selectable/head.js88
4 files changed, 593 insertions, 0 deletions
diff --git a/accessible/tests/browser/selectable/browser.ini b/accessible/tests/browser/selectable/browser.ini
new file mode 100644
index 0000000000..45e34f82d3
--- /dev/null
+++ b/accessible/tests/browser/selectable/browser.ini
@@ -0,0 +1,12 @@
+[DEFAULT]
+subsuite = a11y
+support-files =
+ head.js
+ !/accessible/tests/browser/shared-head.js
+ !/accessible/tests/browser/*.jsm
+ !/accessible/tests/mochitest/*.js
+prefs =
+ javascript.options.asyncstack_capture_debuggee_only=false
+
+[browser_test_aria_select.js]
+[browser_test_select.js]
diff --git a/accessible/tests/browser/selectable/browser_test_aria_select.js b/accessible/tests/browser/selectable/browser_test_aria_select.js
new file mode 100644
index 0000000000..f52603d1cb
--- /dev/null
+++ b/accessible/tests/browser/selectable/browser_test_aria_select.js
@@ -0,0 +1,164 @@
+/* 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/selectable.js */
+
+// ////////////////////////////////////////////////////////////////////////
+// role="tablist" role="listbox" role="grid" role="tree" role="treegrid"
+addAccessibleTask(
+ `<div role="tablist" id="tablist">
+ <div role="tab">tab1</div>
+ <div role="tab">tab2</div>
+ </div>
+ <div role="listbox" id="listbox">
+ <div role="option">item1</div>
+ <div role="option">item2</div>
+ </div>
+ <div role="grid" id="grid">
+ <div role="row">
+ <span role="gridcell">cell</span>
+ <span role="gridcell">cell</span>
+ </div>
+ <div role="row">
+ <span role="gridcell">cell</span>
+ <span role="gridcell">cell</span>
+ </div>
+ </div>
+ <div role="tree" id="tree">
+ <div role="treeitem">
+ item1
+ <div role="group">
+ <div role="treeitem">item1.1</div>
+ </div>
+ </div>
+ <div>item2</div>
+ </div>
+ <div role="treegrid" id="treegrid">
+ <div role="row" aria-level="1">
+ <span role="gridcell">cell</span>
+ <span role="gridcell">cell</span>
+ </div>
+ <div role="row" aria-level="2">
+ <span role="gridcell">cell</span>
+ <span role="gridcell">cell</span>
+ </div>
+ <div role="row" aria-level="1">
+ <span role="gridcell">cell</span>
+ <span role="gridcell">cell</span>
+ </div>
+ </div>`,
+ async function (browser, docAcc) {
+ info(
+ 'role="tablist" role="listbox" role="grid" role="tree" role="treegrid"'
+ );
+ testSelectableSelection(findAccessibleChildByID(docAcc, "tablist"), []);
+ testSelectableSelection(findAccessibleChildByID(docAcc, "listbox"), []);
+ testSelectableSelection(findAccessibleChildByID(docAcc, "grid"), []);
+ testSelectableSelection(findAccessibleChildByID(docAcc, "tree"), []);
+ testSelectableSelection(findAccessibleChildByID(docAcc, "treegrid"), []);
+ },
+ {
+ chrome: true,
+ topLevel: true,
+ iframe: true,
+ remoteIframe: true,
+ }
+);
+
+// ////////////////////////////////////////////////////////////////////////
+// role="tablist" aria-multiselectable
+addAccessibleTask(
+ `<div role="tablist" id="tablist" aria-multiselectable="true">
+ <div role="tab" id="tab_multi1">tab1</div>
+ <div role="tab" id="tab_multi2">tab2</div>
+ </div>`,
+ async function (browser, docAcc) {
+ info('role="tablist" aria-multiselectable');
+ let tablist = findAccessibleChildByID(docAcc, "tablist", [
+ nsIAccessibleSelectable,
+ ]);
+
+ await testMultiSelectable(tablist, ["tab_multi1", "tab_multi2"]);
+ },
+ {
+ chrome: true,
+ topLevel: true,
+ iframe: true,
+ remoteIframe: true,
+ }
+);
+
+// ////////////////////////////////////////////////////////////////////////
+// role="listbox" aria-multiselectable
+addAccessibleTask(
+ `<div role="listbox" id="listbox" aria-multiselectable="true">
+ <div role="option" id="listbox2_item1">item1</div>
+ <div role="option" id="listbox2_item2">item2</div>
+ </div>`,
+ async function (browser, docAcc) {
+ info('role="listbox" aria-multiselectable');
+ let listbox = findAccessibleChildByID(docAcc, "listbox", [
+ nsIAccessibleSelectable,
+ ]);
+
+ await testMultiSelectable(listbox, ["listbox2_item1", "listbox2_item2"]);
+ },
+ {
+ chrome: true,
+ topLevel: true,
+ iframe: true,
+ remoteIframe: true,
+ }
+);
+
+// ////////////////////////////////////////////////////////////////////////
+// role="grid" aria-multiselectable, selectable children in subtree
+addAccessibleTask(
+ `<table tabindex="0" border="2" cellspacing="0" id="grid" role="grid"
+ aria-multiselectable="true">
+ <thead>
+ <tr>
+ <th tabindex="-1" role="columnheader" id="grid_colhead1"
+ style="width:6em">Entry #</th>
+ <th tabindex="-1" role="columnheader" id="grid_colhead2"
+ style="width:10em">Date</th>
+ <th tabindex="-1" role="columnheader" id="grid_colhead3"
+ style="width:20em">Expense</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td tabindex="-1" role="rowheader" id="grid_rowhead"
+ aria-readonly="true">1</td>
+ <td tabindex="-1" role="gridcell" id="grid_cell1"
+ aria-selected="false">03/14/05</td>
+ <td tabindex="-1" role="gridcell" id="grid_cell2"
+ aria-selected="false">Conference Fee</td>
+ </tr>
+ </tobdy>
+ </table>`,
+ async function (browser, docAcc) {
+ info('role="grid" aria-multiselectable, selectable children in subtree');
+ let grid = findAccessibleChildByID(docAcc, "grid", [
+ nsIAccessibleSelectable,
+ ]);
+
+ await testMultiSelectable(grid, [
+ "grid_colhead1",
+ "grid_colhead2",
+ "grid_colhead3",
+ "grid_rowhead",
+ "grid_cell1",
+ "grid_cell2",
+ ]);
+ },
+ {
+ chrome: true,
+ topLevel: true,
+ iframe: true,
+ remoteIframe: true,
+ }
+);
diff --git a/accessible/tests/browser/selectable/browser_test_select.js b/accessible/tests/browser/selectable/browser_test_select.js
new file mode 100644
index 0000000000..f86a371d81
--- /dev/null
+++ b/accessible/tests/browser/selectable/browser_test_select.js
@@ -0,0 +1,329 @@
+/* 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/selectable.js */
+/* import-globals-from ../../mochitest/states.js */
+
+// ////////////////////////////////////////////////////////////////////////
+// select@size="1" aka combobox
+addAccessibleTask(
+ `<select id="combobox">
+ <option id="item1">option1</option>
+ <option id="item2">option2</option>
+ </select>`,
+ async function (browser, docAcc) {
+ info("select@size='1' aka combobox");
+ let combobox = findAccessibleChildByID(docAcc, "combobox");
+ let comboboxList = combobox.firstChild;
+ ok(
+ isAccessible(comboboxList, [nsIAccessibleSelectable]),
+ "No selectable accessible for combobox"
+ );
+
+ let select = getAccessible(comboboxList, [nsIAccessibleSelectable]);
+ testSelectableSelection(select, ["item1"]);
+
+ // select 2nd item
+ let promise = Promise.all([
+ waitForStateChange("item2", STATE_SELECTED, true),
+ waitForStateChange("item1", STATE_SELECTED, false),
+ ]);
+ select.addItemToSelection(1);
+ await promise;
+ testSelectableSelection(select, ["item2"], "addItemToSelection(1): ");
+
+ // unselect 2nd item, 1st item gets selected automatically
+ promise = Promise.all([
+ waitForStateChange("item2", STATE_SELECTED, false),
+ waitForStateChange("item1", STATE_SELECTED, true),
+ ]);
+ select.removeItemFromSelection(1);
+ await promise;
+ testSelectableSelection(select, ["item1"], "removeItemFromSelection(1): ");
+
+ // doesn't change selection
+ is(select.selectAll(), false, "No way to select all items in combobox");
+ testSelectableSelection(select, ["item1"], "selectAll: ");
+
+ // doesn't change selection
+ select.unselectAll();
+ testSelectableSelection(select, ["item1"], "unselectAll: ");
+ },
+ {
+ chrome: true,
+ topLevel: true,
+ iframe: true,
+ remoteIframe: true,
+ }
+);
+
+// ////////////////////////////////////////////////////////////////////////
+// select@size="1" with optgroups
+addAccessibleTask(
+ `<select id="combobox">
+ <option id="item1">option1</option>
+ <optgroup>optgroup
+ <option id="item2">option2</option>
+ </optgroup>
+ </select>`,
+ async function (browser, docAcc) {
+ info("select@size='1' with optgroups");
+ let combobox = findAccessibleChildByID(docAcc, "combobox");
+ let comboboxList = combobox.firstChild;
+ ok(
+ isAccessible(comboboxList, [nsIAccessibleSelectable]),
+ "No selectable accessible for combobox"
+ );
+
+ let select = getAccessible(comboboxList, [nsIAccessibleSelectable]);
+ testSelectableSelection(select, ["item1"]);
+
+ let promise = Promise.all([
+ waitForStateChange("item2", STATE_SELECTED, true),
+ waitForStateChange("item1", STATE_SELECTED, false),
+ ]);
+ select.addItemToSelection(1);
+ await promise;
+ testSelectableSelection(select, ["item2"], "addItemToSelection(1): ");
+
+ promise = Promise.all([
+ waitForStateChange("item2", STATE_SELECTED, false),
+ waitForStateChange("item1", STATE_SELECTED, true),
+ ]);
+ select.removeItemFromSelection(1);
+ await promise;
+ testSelectableSelection(select, ["item1"], "removeItemFromSelection(1): ");
+
+ is(select.selectAll(), false, "No way to select all items in combobox");
+ testSelectableSelection(select, ["item1"]);
+
+ select.unselectAll();
+ testSelectableSelection(select, ["item1"]);
+ },
+ {
+ chrome: true,
+ topLevel: true,
+ iframe: true,
+ remoteIframe: true,
+ }
+);
+
+// ////////////////////////////////////////////////////////////////////////
+// select@size="4" aka single selectable listbox
+addAccessibleTask(
+ `<select id="listbox" size="4">
+ <option id="item1">option1</option>
+ <option id="item2">option2</option>
+ </select>`,
+ async function (browser, docAcc) {
+ info("select@size='4' aka single selectable listbox");
+ let select = findAccessibleChildByID(docAcc, "listbox", [
+ nsIAccessibleSelectable,
+ ]);
+ testSelectableSelection(select, []);
+
+ // select 2nd item
+ let promise = waitForStateChange("item2", STATE_SELECTED, true);
+ select.addItemToSelection(1);
+ await promise;
+ testSelectableSelection(select, ["item2"], "addItemToSelection(1): ");
+
+ // unselect 2nd item, 1st item gets selected automatically
+ promise = waitForStateChange("item2", STATE_SELECTED, false);
+ select.removeItemFromSelection(1);
+ await promise;
+ testSelectableSelection(select, [], "removeItemFromSelection(1): ");
+
+ // doesn't change selection
+ is(
+ select.selectAll(),
+ false,
+ "No way to select all items in single selectable listbox"
+ );
+ testSelectableSelection(select, [], "selectAll: ");
+
+ // doesn't change selection
+ select.unselectAll();
+ testSelectableSelection(select, [], "unselectAll: ");
+ },
+ {
+ chrome: true,
+ topLevel: true,
+ iframe: true,
+ remoteIframe: true,
+ }
+);
+
+// ////////////////////////////////////////////////////////////////////////
+// select@size="4" with optgroups, single selectable
+addAccessibleTask(
+ `<select id="listbox" size="4">
+ <option id="item1">option1</option>
+ <optgroup>optgroup>
+ <option id="item2">option2</option>
+ </optgroup>
+ </select>`,
+ async function (browser, docAcc) {
+ info("select@size='4' with optgroups, single selectable");
+ let select = findAccessibleChildByID(docAcc, "listbox", [
+ nsIAccessibleSelectable,
+ ]);
+ testSelectableSelection(select, []);
+
+ let promise = waitForStateChange("item2", STATE_SELECTED, true);
+ select.addItemToSelection(1);
+ await promise;
+ testSelectableSelection(select, ["item2"]);
+
+ promise = waitForStateChange("item2", STATE_SELECTED, false);
+ select.removeItemFromSelection(1);
+ await promise;
+ testSelectableSelection(select, []);
+
+ is(
+ select.selectAll(),
+ false,
+ "No way to select all items in single selectable listbox"
+ );
+ testSelectableSelection(select, []);
+
+ select.unselectAll();
+ testSelectableSelection(select, []);
+ },
+ {
+ chrome: true,
+ topLevel: true,
+ iframe: true,
+ remoteIframe: true,
+ }
+);
+
+// ////////////////////////////////////////////////////////////////////////
+// select@size="4" multiselect aka listbox
+addAccessibleTask(
+ `<select id="listbox" size="4" multiple="true">
+ <option id="item1">option1</option>
+ <option id="item2">option2</option>
+ </select>`,
+ async function (browser, docAcc) {
+ info("select@size='4' multiselect aka listbox");
+ let select = findAccessibleChildByID(docAcc, "listbox", [
+ nsIAccessibleSelectable,
+ ]);
+ await testMultiSelectable(
+ select,
+ ["item1", "item2"],
+ "select@size='4' multiselect aka listbox "
+ );
+ },
+ {
+ chrome: true,
+ topLevel: true,
+ iframe: true,
+ remoteIframe: true,
+ }
+);
+
+// ////////////////////////////////////////////////////////////////////////
+// select@size="4" multiselect with optgroups
+addAccessibleTask(
+ `<select id="listbox" size="4" multiple="true">
+ <option id="item1">option1</option>
+ <optgroup>optgroup>
+ <option id="item2">option2</option>
+ </optgroup>
+ </select>`,
+ async function (browser, docAcc) {
+ info("select@size='4' multiselect with optgroups");
+ let select = findAccessibleChildByID(docAcc, "listbox", [
+ nsIAccessibleSelectable,
+ ]);
+ await testMultiSelectable(
+ select,
+ ["item1", "item2"],
+ "select@size='4' multiselect aka listbox "
+ );
+ },
+ {
+ chrome: true,
+ topLevel: true,
+ iframe: true,
+ remoteIframe: true,
+ }
+);
+
+// ////////////////////////////////////////////////////////////////////////
+// multiselect with coalesced selection event
+addAccessibleTask(
+ `<select id="listbox" size="4" multiple="true">
+ <option id="item1">option1</option>
+ <option id="item2">option2</option>
+ <option id="item3">option3</option>
+ <option id="item4">option4</option>
+ <option id="item5">option5</option>
+ <option id="item6">option6</option>
+ <option id="item7">option7</option>
+ <option id="item8">option8</option>
+ <option id="item9">option9</option>
+ </select>`,
+ async function (browser, docAcc) {
+ info("select@size='4' multiselect with coalesced selection event");
+ let select = findAccessibleChildByID(docAcc, "listbox", [
+ nsIAccessibleSelectable,
+ ]);
+ await testMultiSelectable(
+ select,
+ [
+ "item1",
+ "item2",
+ "item3",
+ "item4",
+ "item5",
+ "item6",
+ "item7",
+ "item8",
+ "item9",
+ ],
+ "select@size='4' multiselect with coalesced selection event "
+ );
+ },
+ {
+ chrome: false,
+ topLevel: true,
+ iframe: false,
+ remoteIframe: false,
+ }
+);
+
+/**
+ * Ensure that we don't assert when dealing with defunct items in selection
+ * events dropped due to coalescence (bug 1800755).
+ */
+addAccessibleTask(
+ `
+<form id="form">
+ <select id="select">
+ <option>
+ <optgroup id="optgroup">
+ <option>
+ </optgroup>
+ </select>
+</form>
+ `,
+ async function (browser, docAcc) {
+ let selected = waitForEvent(EVENT_SELECTION_WITHIN, "select");
+ await invokeContentTask(browser, [], () => {
+ const form = content.document.getElementById("form");
+ const select = content.document.getElementById("select");
+ const optgroup = content.document.getElementById("optgroup");
+ form.reset();
+ select.selectedIndex = 1;
+ select.add(optgroup);
+ select.item(0).remove();
+ });
+ await selected;
+ }
+);
diff --git a/accessible/tests/browser/selectable/head.js b/accessible/tests/browser/selectable/head.js
new file mode 100644
index 0000000000..ccf9e86f77
--- /dev/null
+++ b/accessible/tests/browser/selectable/head.js
@@ -0,0 +1,88 @@
+/* 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 testMultiSelectable */
+
+// Load the shared-head file first.
+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.
+/* import-globals-from ../../mochitest/selectable.js */
+/* import-globals-from ../../mochitest/states.js */
+loadScripts(
+ { name: "common.js", dir: MOCHITESTS_DIR },
+ { name: "promisified-events.js", dir: MOCHITESTS_DIR },
+ { name: "selectable.js", dir: MOCHITESTS_DIR },
+ { name: "states.js", dir: MOCHITESTS_DIR },
+ { name: "role.js", dir: MOCHITESTS_DIR }
+);
+
+// Handle case where multiple selection change events are coalesced into
+// a SELECTION_WITHIN event. Promise resolves to true in that case.
+function multipleSelectionChanged(widget, changedChildren, selected) {
+ return Promise.race([
+ Promise.all(
+ changedChildren.map(id =>
+ waitForStateChange(id, STATE_SELECTED, selected)
+ )
+ ).then(() => false),
+ waitForEvent(EVENT_SELECTION_WITHIN, widget).then(() => true),
+ ]);
+}
+
+async function testMultiSelectable(widget, selectableChildren, msg = "") {
+ let isRemote = false;
+ try {
+ widget.DOMNode;
+ } catch (e) {
+ isRemote = true;
+ }
+
+ testSelectableSelection(widget, [], `${msg}: initial`);
+
+ let promise = waitForStateChange(selectableChildren[0], STATE_SELECTED, true);
+ widget.addItemToSelection(0);
+ await promise;
+ testSelectableSelection(
+ widget,
+ [selectableChildren[0]],
+ `${msg}: addItemToSelection(0)`
+ );
+
+ promise = waitForStateChange(selectableChildren[0], STATE_SELECTED, false);
+ widget.removeItemFromSelection(0);
+ await promise;
+ testSelectableSelection(widget, [], `${msg}: removeItemFromSelection(0)`);
+
+ promise = multipleSelectionChanged(widget, selectableChildren, true);
+ let success = widget.selectAll();
+ ok(success, `${msg}: selectAll success`);
+ await promise;
+ if (isRemote) {
+ await untilCacheIs(
+ () => widget.selectedItemCount,
+ selectableChildren.length,
+ "Selection cache updated"
+ );
+ }
+ testSelectableSelection(widget, selectableChildren, `${msg}: selectAll`);
+
+ promise = multipleSelectionChanged(widget, selectableChildren, false);
+ widget.unselectAll();
+ await promise;
+ if (isRemote) {
+ await untilCacheIs(
+ () => widget.selectedItemCount,
+ 0,
+ "Selection cache updated"
+ );
+ }
+ testSelectableSelection(widget, [], `${msg}: selectAll`);
+}