summaryrefslogtreecommitdiffstats
path: root/accessible/tests/browser/e10s/browser_caching_value.js
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /accessible/tests/browser/e10s/browser_caching_value.js
parentInitial commit. (diff)
downloadfirefox-upstream/124.0.1.tar.xz
firefox-upstream/124.0.1.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'accessible/tests/browser/e10s/browser_caching_value.js')
-rw-r--r--accessible/tests/browser/e10s/browser_caching_value.js457
1 files changed, 457 insertions, 0 deletions
diff --git a/accessible/tests/browser/e10s/browser_caching_value.js b/accessible/tests/browser/e10s/browser_caching_value.js
new file mode 100644
index 0000000000..2b968b5948
--- /dev/null
+++ b/accessible/tests/browser/e10s/browser_caching_value.js
@@ -0,0 +1,457 @@
+/* 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: "states.js", dir: MOCHITESTS_DIR });
+
+/**
+ * Test data has the format of:
+ * {
+ * desc {String} description for better logging
+ * id {String} given accessible DOMNode ID
+ * expected {String} expected value for a given accessible
+ * action {?AsyncFunction} an optional action that awaits a value change
+ * attrs {?Array} an optional list of attributes to update
+ * waitFor {?Number} an optional value change event to wait for
+ * }
+ */
+const valueTests = [
+ {
+ desc: "Initially value is set to 1st element of select",
+ id: "select",
+ expected: "1st",
+ },
+ {
+ desc: "Value should update to 3rd when 3 is pressed",
+ id: "select",
+ async action(browser) {
+ await invokeFocus(browser, "select");
+ await invokeContentTask(browser, [], () => {
+ const { ContentTaskUtils } = ChromeUtils.importESModule(
+ "resource://testing-common/ContentTaskUtils.sys.mjs"
+ );
+ const EventUtils = ContentTaskUtils.getEventUtils(content);
+ EventUtils.synthesizeKey("3", {}, content);
+ });
+ },
+ waitFor: EVENT_TEXT_VALUE_CHANGE,
+ expected: "3rd",
+ },
+ {
+ desc: "Initially value is set to @aria-valuenow for slider",
+ id: "slider",
+ expected: ["5", 5, 0, 7, 0],
+ },
+ {
+ desc: "Value should change when currentValue is called",
+ id: "slider",
+ async action(browser, acc) {
+ acc.QueryInterface(nsIAccessibleValue);
+ acc.currentValue = 4;
+ },
+ waitFor: EVENT_VALUE_CHANGE,
+ expected: ["4", 4, 0, 7, 0],
+ },
+ {
+ desc: "Value should change when @aria-valuenow is updated",
+ id: "slider",
+ attrs: [
+ {
+ attr: "aria-valuenow",
+ value: "6",
+ },
+ ],
+ waitFor: EVENT_VALUE_CHANGE,
+ expected: ["6", 6, 0, 7, 0],
+ },
+ {
+ desc: "Value should change when @aria-valuetext is set",
+ id: "slider",
+ attrs: [
+ {
+ attr: "aria-valuetext",
+ value: "plain",
+ },
+ ],
+ waitFor: EVENT_TEXT_VALUE_CHANGE,
+ expected: ["plain", 6, 0, 7, 0],
+ },
+ {
+ desc: "Value should change when @aria-valuetext is updated",
+ id: "slider",
+ attrs: [
+ {
+ attr: "aria-valuetext",
+ value: "hey!",
+ },
+ ],
+ waitFor: EVENT_TEXT_VALUE_CHANGE,
+ expected: ["hey!", 6, 0, 7, 0],
+ },
+ {
+ desc: "Value should change to @aria-valuetext when @aria-valuenow is removed",
+ id: "slider",
+ attrs: [
+ {
+ attr: "aria-valuenow",
+ },
+ ],
+ expected: ["hey!", 3.5, 0, 7, 0],
+ },
+ {
+ desc: "Initially value is not set for combobox",
+ id: "combobox",
+ expected: "",
+ },
+ {
+ desc: "Value should change when @value attribute is updated",
+ id: "combobox",
+ attrs: [
+ {
+ attr: "value",
+ value: "hello",
+ },
+ ],
+ waitFor: EVENT_TEXT_VALUE_CHANGE,
+ expected: "hello",
+ },
+ {
+ desc: "Initially value corresponds to @value attribute for progress",
+ id: "progress",
+ expected: "22%",
+ },
+ {
+ desc: "Value should change when @value attribute is updated",
+ id: "progress",
+ attrs: [
+ {
+ attr: "value",
+ value: "50",
+ },
+ ],
+ waitFor: EVENT_VALUE_CHANGE,
+ expected: "50%",
+ },
+ {
+ desc: "Setting currentValue on a progress accessible should fail",
+ id: "progress",
+ async action(browser, acc) {
+ acc.QueryInterface(nsIAccessibleValue);
+ try {
+ acc.currentValue = 25;
+ ok(false, "Setting currValue on progress element should fail");
+ } catch (e) {}
+ },
+ expected: "50%",
+ },
+ {
+ desc: "Initially value corresponds to @value attribute for range",
+ id: "range",
+ expected: "6",
+ },
+ {
+ desc: "Value should change when slider is moved",
+ id: "range",
+ async action(browser) {
+ await invokeFocus(browser, "range");
+ await invokeContentTask(browser, [], () => {
+ const { ContentTaskUtils } = ChromeUtils.importESModule(
+ "resource://testing-common/ContentTaskUtils.sys.mjs"
+ );
+ const EventUtils = ContentTaskUtils.getEventUtils(content);
+ EventUtils.synthesizeKey("VK_LEFT", {}, content);
+ });
+ },
+ waitFor: EVENT_VALUE_CHANGE,
+ expected: "5",
+ },
+ {
+ desc: "Value should change when currentValue is called",
+ id: "range",
+ async action(browser, acc) {
+ acc.QueryInterface(nsIAccessibleValue);
+ acc.currentValue = 4;
+ },
+ waitFor: EVENT_VALUE_CHANGE,
+ expected: "4",
+ },
+ {
+ desc: "Initially textbox value is text subtree",
+ id: "textbox",
+ expected: "Some rich text",
+ },
+ {
+ desc: "Textbox value changes when subtree changes",
+ id: "textbox",
+ async action(browser) {
+ await invokeContentTask(browser, [], () => {
+ let boldText = content.document.createElement("strong");
+ boldText.textContent = " bold";
+ content.document.getElementById("textbox").appendChild(boldText);
+ });
+ },
+ waitFor: EVENT_TEXT_VALUE_CHANGE,
+ expected: "Some rich text bold",
+ },
+];
+
+/**
+ * Like testValue in accessible/tests/mochitest/value.js, but waits for cache
+ * updates.
+ */
+async function testValue(acc, value, currValue, minValue, maxValue, minIncr) {
+ const pretty = prettyName(acc);
+ await untilCacheIs(() => acc.value, value, `Wrong value of ${pretty}`);
+
+ await untilCacheIs(
+ () => acc.currentValue,
+ currValue,
+ `Wrong current value of ${pretty}`
+ );
+ await untilCacheIs(
+ () => acc.minimumValue,
+ minValue,
+ `Wrong minimum value of ${pretty}`
+ );
+ await untilCacheIs(
+ () => acc.maximumValue,
+ maxValue,
+ `Wrong maximum value of ${pretty}`
+ );
+ await untilCacheIs(
+ () => acc.minimumIncrement,
+ minIncr,
+ `Wrong minimum increment value of ${pretty}`
+ );
+}
+
+/**
+ * Test caching of accessible object values
+ */
+addAccessibleTask(
+ `
+ <div id="slider" role="slider" aria-valuenow="5"
+ aria-valuemin="0" aria-valuemax="7">slider</div>
+ <select id="select">
+ <option>1st</option>
+ <option>2nd</option>
+ <option>3rd</option>
+ </select>
+ <input id="combobox" role="combobox" aria-autocomplete="inline">
+ <progress id="progress" value="22" max="100"></progress>
+ <input type="range" id="range" min="0" max="10" value="6">
+ <div contenteditable="yes" role="textbox" id="textbox">Some <a href="#">rich</a> text</div>`,
+ async function (browser, accDoc) {
+ for (let { desc, id, action, attrs, expected, waitFor } of valueTests) {
+ info(desc);
+ let acc = findAccessibleChildByID(accDoc, id);
+ let onUpdate;
+
+ if (waitFor) {
+ onUpdate = waitForEvent(waitFor, id);
+ }
+
+ if (action) {
+ await action(browser, acc);
+ } else if (attrs) {
+ for (let { attr, value } of attrs) {
+ await invokeSetAttribute(browser, id, attr, value);
+ }
+ }
+
+ await onUpdate;
+ if (Array.isArray(expected)) {
+ acc.QueryInterface(nsIAccessibleValue);
+ await testValue(acc, ...expected);
+ } else {
+ is(acc.value, expected, `Correct value for ${prettyName(acc)}`);
+ }
+ }
+ },
+ { iframe: true, remoteIframe: true }
+);
+
+/**
+ * Test caching of link URL values.
+ */
+addAccessibleTask(
+ `<a id="link" href="https://example.com/">Test</a>`,
+ async function (browser, docAcc) {
+ let link = findAccessibleChildByID(docAcc, "link");
+ is(link.value, "https://example.com/", "link initial value correct");
+ const textLeaf = link.firstChild;
+ is(textLeaf.value, "https://example.com/", "link initial value correct");
+
+ info("Changing link href");
+ await invokeSetAttribute(browser, "link", "href", "https://example.net/");
+ await untilCacheIs(
+ () => link.value,
+ "https://example.net/",
+ "link value correct after change"
+ );
+
+ info("Removing link href");
+ let onRecreation = waitForEvents({
+ expected: [
+ [EVENT_HIDE, link],
+ [EVENT_SHOW, "link"],
+ ],
+ });
+ await invokeSetAttribute(browser, "link", "href");
+ await onRecreation;
+ link = findAccessibleChildByID(docAcc, "link");
+ await untilCacheIs(() => link.value, "", "link value empty after removal");
+
+ info("Setting link href");
+ onRecreation = waitForEvents({
+ expected: [
+ [EVENT_HIDE, link],
+ [EVENT_SHOW, "link"],
+ ],
+ });
+ await invokeSetAttribute(browser, "link", "href", "https://example.com/");
+ await onRecreation;
+ link = findAccessibleChildByID(docAcc, "link");
+ await untilCacheIs(
+ () => link.value,
+ "https://example.com/",
+ "link value correct after change"
+ );
+ },
+ { chrome: true, topLevel: true, iframe: true, remoteIframe: true }
+);
+
+/**
+ * Test caching of active state for select options - see bug 1788143.
+ */
+addAccessibleTask(
+ `
+ <select id="select">
+ <option id="first_option">First</option>
+ <option id="second_option">Second</option>
+ </select>`,
+ async function (browser, docAcc) {
+ const select = findAccessibleChildByID(docAcc, "select");
+ is(select.value, "First", "Select initial value correct");
+
+ // Focus the combo box.
+ await invokeFocus(browser, "select");
+
+ // Select the second option (drop-down collapsed).
+ let p = waitForEvents({
+ expected: [
+ [EVENT_SELECTION, "second_option"],
+ [EVENT_TEXT_VALUE_CHANGE, "select"],
+ ],
+ unexpected: [
+ stateChangeEventArgs("second_option", EXT_STATE_ACTIVE, true, true),
+ stateChangeEventArgs("first_option", EXT_STATE_ACTIVE, false, true),
+ ],
+ });
+ await invokeContentTask(browser, [], () => {
+ content.document.getElementById("select").selectedIndex = 1;
+ });
+ await p;
+
+ is(select.value, "Second", "Select value correct after changing option");
+
+ // Expand the combobox dropdown.
+ p = waitForEvent(EVENT_STATE_CHANGE, "ContentSelectDropdown");
+ EventUtils.synthesizeKey("VK_SPACE");
+ await p;
+
+ p = waitForEvents({
+ expected: [
+ [EVENT_SELECTION, "first_option"],
+ [EVENT_TEXT_VALUE_CHANGE, "select"],
+ [EVENT_HIDE, "ContentSelectDropdown"],
+ ],
+ unexpected: [
+ stateChangeEventArgs("first_option", EXT_STATE_ACTIVE, true, true),
+ stateChangeEventArgs("second_option", EXT_STATE_ACTIVE, false, true),
+ ],
+ });
+
+ // Press the up arrow to select the first option (drop-down expanded).
+ // Then, press Enter to confirm the selection and close the dropdown.
+ // We do both of these together to unify testing across platforms, since
+ // events are not entirely consistent on Windows vs. Linux + macOS.
+ EventUtils.synthesizeKey("VK_UP");
+ EventUtils.synthesizeKey("VK_RETURN");
+ await p;
+
+ is(
+ select.value,
+ "First",
+ "Select value correct after changing option back"
+ );
+ },
+ { chrome: true, topLevel: true, iframe: true, remoteIframe: true }
+);
+
+/**
+ * Test combobox values for non-editable comboboxes.
+ */
+addAccessibleTask(
+ `
+ <div id="combo-div-1" role="combobox">value</div>
+ <div id="combo-div-2" role="combobox">
+ <div role="listbox">
+ <div role="option">value</div>
+ </div>
+ </div>
+ <div id="combo-div-3" role="combobox">
+ <div role="group">value</div>
+ </div>
+ <div id="combo-div-4" role="combobox">foo
+ <div role="listbox">
+ <div role="option">bar</div>
+ </div>
+ </div>
+
+ <input id="combo-input-1" role="combobox" value="value" disabled></input>
+ <input id="combo-input-2" role="combobox" value="value" disabled>testing</input>
+
+ <div id="combo-div-selected" role="combobox">
+ <div role="listbox">
+ <div aria-selected="true" role="option">value</div>
+ </div>
+ </div>
+`,
+ async function (browser, docAcc) {
+ const comboDiv1 = findAccessibleChildByID(docAcc, "combo-div-1");
+ const comboDiv2 = findAccessibleChildByID(docAcc, "combo-div-2");
+ const comboDiv3 = findAccessibleChildByID(docAcc, "combo-div-3");
+ const comboDiv4 = findAccessibleChildByID(docAcc, "combo-div-4");
+ const comboInput1 = findAccessibleChildByID(docAcc, "combo-input-1");
+ const comboInput2 = findAccessibleChildByID(docAcc, "combo-input-2");
+ const comboDivSelected = findAccessibleChildByID(
+ docAcc,
+ "combo-div-selected"
+ );
+
+ // Text as a descendant of the combobox: included in the value.
+ is(comboDiv1.value, "value", "Combobox value correct");
+
+ // Text as the descendant of a listbox: excluded from the value.
+ is(comboDiv2.value, "", "Combobox value correct");
+
+ // Text as the descendant of some other role that includes text in name computation.
+ // Here, the group role contains the text node with "value" in it.
+ is(comboDiv3.value, "value", "Combobox value correct");
+
+ // Some descendant text included, but text descendant of a listbox excluded.
+ is(comboDiv4.value, "foo", "Combobox value correct");
+
+ // Combobox inputs with explicit value report that value.
+ is(comboInput1.value, "value", "Combobox value correct");
+ is(comboInput2.value, "value", "Combobox value correct");
+
+ // Combobox role with aria-selected reports correct value.
+ is(comboDivSelected.value, "value", "Combobox value correct");
+ },
+ { chrome: true, iframe: true, remoteIframe: true }
+);