summaryrefslogtreecommitdiffstats
path: root/testing/mochitest
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 01:13:27 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 01:13:27 +0000
commit40a355a42d4a9444dc753c04c6608dade2f06a23 (patch)
tree871fc667d2de662f171103ce5ec067014ef85e61 /testing/mochitest
parentAdding upstream version 124.0.1. (diff)
downloadfirefox-40a355a42d4a9444dc753c04c6608dade2f06a23.tar.xz
firefox-40a355a42d4a9444dc753c04c6608dade2f06a23.zip
Adding upstream version 125.0.1.upstream/125.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/mochitest')
-rw-r--r--testing/mochitest/BrowserTestUtils/BrowserTestUtils.sys.mjs36
-rw-r--r--testing/mochitest/BrowserTestUtils/content/content-about-page-utils.js2
-rw-r--r--testing/mochitest/api.js2
-rw-r--r--testing/mochitest/baselinecoverage/browser_chrome/browser_baselinecoverage_browser-chrome.js2
-rw-r--r--testing/mochitest/browser-test.js6
-rw-r--r--testing/mochitest/leaks.py14
-rw-r--r--testing/mochitest/server.js2
-rw-r--r--testing/mochitest/static/browser.template.txt2
-rw-r--r--testing/mochitest/tests/Harness_sanity/SpecialPowersLoadChromeScript.js2
-rw-r--r--testing/mochitest/tests/Harness_sanity/test_SpecialPowersExtension.html4
-rw-r--r--testing/mochitest/tests/Harness_sanity/test_SpecialPowersLoadChromeScript.html2
-rw-r--r--testing/mochitest/tests/Harness_sanity/test_SpecialPowersLoadChromeScript_function.html2
-rw-r--r--testing/mochitest/tests/Harness_sanity/test_createFiles.html6
-rw-r--r--testing/mochitest/tests/Harness_sanity/test_sanityEventUtils.html4
-rw-r--r--testing/mochitest/tests/SimpleTest/AccessibilityUtils.js261
-rw-r--r--testing/mochitest/tests/SimpleTest/EventUtils.js360
-rw-r--r--testing/mochitest/tests/SimpleTest/LogController.js2
-rw-r--r--testing/mochitest/tests/SimpleTest/SimpleTest.js2
-rw-r--r--testing/mochitest/tests/SimpleTest/TestRunner.js2
-rw-r--r--testing/mochitest/tests/SimpleTest/paint_listener.js2
-rw-r--r--testing/mochitest/tests/SimpleTest/setup.js4
-rw-r--r--testing/mochitest/tests/browser/browser_document_builder_sjs.js5
22 files changed, 527 insertions, 197 deletions
diff --git a/testing/mochitest/BrowserTestUtils/BrowserTestUtils.sys.mjs b/testing/mochitest/BrowserTestUtils/BrowserTestUtils.sys.mjs
index 741882d9be..1793a6646f 100644
--- a/testing/mochitest/BrowserTestUtils/BrowserTestUtils.sys.mjs
+++ b/testing/mochitest/BrowserTestUtils/BrowserTestUtils.sys.mjs
@@ -704,7 +704,7 @@ export var BrowserTestUtils = {
* @resolves When STATE_START reaches the tab's progress listener
*/
browserStarted(browser, expectedURI) {
- let testFn = function (aStateFlags, aStatus) {
+ let testFn = function (aStateFlags) {
return (
aStateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK &&
aStateFlags & Ci.nsIWebProgressListener.STATE_START
@@ -763,7 +763,7 @@ export var BrowserTestUtils = {
} else {
urlMatches = urlToMatch => urlToMatch != "about:blank";
}
- return new Promise((resolve, reject) => {
+ return new Promise(resolve => {
tabbrowser.tabContainer.addEventListener(
"TabOpen",
function tabOpenListener(openEvent) {
@@ -829,15 +829,9 @@ export var BrowserTestUtils = {
* @resolves When onLocationChange fires.
*/
waitForLocationChange(tabbrowser, url) {
- return new Promise((resolve, reject) => {
+ return new Promise(resolve => {
let progressListener = {
- onLocationChange(
- aBrowser,
- aWebProgress,
- aRequest,
- aLocationURI,
- aFlags
- ) {
+ onLocationChange(aBrowser, aWebProgress, aRequest, aLocationURI) {
if (
(url && aLocationURI.spec != url) ||
(!url && aLocationURI.spec == "about:blank")
@@ -885,7 +879,7 @@ export var BrowserTestUtils = {
}
return new Promise((resolve, reject) => {
- let observe = async (win, topic, data) => {
+ let observe = async (win, topic) => {
if (topic != "domwindowopened") {
return;
}
@@ -1002,7 +996,7 @@ export var BrowserTestUtils = {
*/
domWindowOpened(win, checkFn) {
return new Promise(resolve => {
- async function observer(subject, topic, data) {
+ async function observer(subject, topic) {
if (topic == "domwindowopened" && (!win || subject === win)) {
let observedWindow = subject;
if (checkFn && !(await checkFn(observedWindow))) {
@@ -1055,7 +1049,7 @@ export var BrowserTestUtils = {
*/
domWindowClosed(win) {
return new Promise(resolve => {
- function observer(subject, topic, data) {
+ function observer(subject, topic) {
if (topic == "domwindowclosed" && (!win || subject === win)) {
Services.ww.unregisterNotification(observer);
resolve(subject);
@@ -1167,7 +1161,7 @@ export var BrowserTestUtils = {
win.gBrowser._insertBrowser(win.gBrowser.getTabForBrowser(browser));
});
- let observer = (subject, topic, data) => {
+ let observer = subject => {
if (browserSet.has(subject)) {
browserSet.delete(subject);
}
@@ -1202,7 +1196,7 @@ export var BrowserTestUtils = {
return new Promise(resolve => {
let browser = tab.linkedBrowser;
let flushTopic = "sessionstore-browser-shutdown-flush";
- let observer = (subject, topic, data) => {
+ let observer = subject => {
if (subject === browser) {
Services.obs.removeObserver(observer, flushTopic);
// Wait for the next event tick to make sure other listeners are
@@ -1615,7 +1609,7 @@ export var BrowserTestUtils = {
}
},
- observe(subject, topic, data) {
+ observe(subject, topic) {
switch (topic) {
case "test-complete":
this._cleanupContentEventListeners();
@@ -2054,7 +2048,7 @@ export var BrowserTestUtils = {
let expectedPromises = [];
let crashCleanupPromise = new Promise((resolve, reject) => {
- let observer = (subject, topic, data) => {
+ let observer = (subject, topic) => {
if (topic != "ipc:content-shutdown") {
reject("Received incorrect observer topic: " + topic);
return;
@@ -2129,7 +2123,7 @@ export var BrowserTestUtils = {
if (shouldShowTabCrashPage) {
expectedPromises.push(
- new Promise((resolve, reject) => {
+ new Promise(resolve => {
browser.addEventListener(
"AboutTabCrashedReady",
function onCrash() {
@@ -2187,7 +2181,7 @@ export var BrowserTestUtils = {
});
let sawNormalCrash = false;
- let observer = (subject, topic, data) => {
+ let observer = () => {
sawNormalCrash = true;
};
@@ -2232,7 +2226,7 @@ export var BrowserTestUtils = {
waitForAttribute(attr, element, value) {
let MutationObserver = element.ownerGlobal.MutationObserver;
return new Promise(resolve => {
- let mut = new MutationObserver(mutations => {
+ let mut = new MutationObserver(() => {
if (
(!value && element.hasAttribute(attr)) ||
(value && element.getAttribute(attr) === value)
@@ -2263,7 +2257,7 @@ export var BrowserTestUtils = {
let MutationObserver = element.ownerGlobal.MutationObserver;
return new Promise(resolve => {
dump("Waiting for removal\n");
- let mut = new MutationObserver(mutations => {
+ let mut = new MutationObserver(() => {
if (!element.hasAttribute(attr)) {
resolve();
mut.disconnect();
diff --git a/testing/mochitest/BrowserTestUtils/content/content-about-page-utils.js b/testing/mochitest/BrowserTestUtils/content/content-about-page-utils.js
index e20100db4b..759e283bcb 100644
--- a/testing/mochitest/BrowserTestUtils/content/content-about-page-utils.js
+++ b/testing/mochitest/BrowserTestUtils/content/content-about-page-utils.js
@@ -14,7 +14,7 @@ function AboutPage(aboutHost, chromeURL, uriFlags) {
AboutPage.prototype = {
QueryInterface: ChromeUtils.generateQI(["nsIAboutModule"]),
- getURIFlags(aURI) {
+ getURIFlags() {
// eslint-disable-line no-unused-vars
return this.uriFlags;
},
diff --git a/testing/mochitest/api.js b/testing/mochitest/api.js
index bd578f03b8..fa4422f290 100644
--- a/testing/mochitest/api.js
+++ b/testing/mochitest/api.js
@@ -26,7 +26,7 @@ const windowTracker = {
Services.obs.addObserver(this, "chrome-document-global-created");
},
- async observe(window, topic, data) {
+ async observe(window, topic) {
if (topic === "chrome-document-global-created") {
await new Promise(resolve =>
window.addEventListener("DOMContentLoaded", resolve, { once: true })
diff --git a/testing/mochitest/baselinecoverage/browser_chrome/browser_baselinecoverage_browser-chrome.js b/testing/mochitest/baselinecoverage/browser_chrome/browser_baselinecoverage_browser-chrome.js
index 4015bd6edf..3095934ffd 100644
--- a/testing/mochitest/baselinecoverage/browser_chrome/browser_baselinecoverage_browser-chrome.js
+++ b/testing/mochitest/baselinecoverage/browser_chrome/browser_baselinecoverage_browser-chrome.js
@@ -13,7 +13,7 @@ add_task(async function () {
gBrowser,
url: "about:blank",
},
- async function (browser) {
+ async function () {
ok(true, "Collecting baseline coverage for browser-chrome tests.");
await new Promise(c => setTimeout(c, 30 * 1000));
}
diff --git a/testing/mochitest/browser-test.js b/testing/mochitest/browser-test.js
index 98b9055605..1f9798bb36 100644
--- a/testing/mochitest/browser-test.js
+++ b/testing/mochitest/browser-test.js
@@ -45,7 +45,7 @@ var TabDestroyObserver = {
Services.obs.removeObserver(this, "message-manager-disconnect");
},
- observe(subject, topic, data) {
+ observe(subject, topic) {
if (topic == "message-manager-close") {
this.outstanding.add(subject);
} else if (topic == "message-manager-disconnect") {
@@ -516,7 +516,7 @@ Tester.prototype = {
this.SimpleTest.waitForFocus(aCallback);
},
- finish: function Tester_finish(aSkipSummary) {
+ finish: function Tester_finish() {
var passCount = this.tests.reduce((a, f) => a + f.passCount, 0);
var failCount = this.tests.reduce((a, f) => a + f.failCount, 0);
var todoCount = this.tests.reduce((a, f) => a + f.todoCount, 0);
@@ -564,7 +564,7 @@ Tester.prototype = {
this.repeat = 0;
},
- observe: function Tester_observe(aSubject, aTopic, aData) {
+ observe: function Tester_observe(aSubject, aTopic) {
if (!aTopic) {
this.onConsoleMessage(aSubject);
}
diff --git a/testing/mochitest/leaks.py b/testing/mochitest/leaks.py
index 76b6610963..08ed649a0c 100644
--- a/testing/mochitest/leaks.py
+++ b/testing/mochitest/leaks.py
@@ -8,8 +8,8 @@
import re
from operator import itemgetter
-RE_DOCSHELL = re.compile("I\/DocShellAndDOMWindowLeak ([+\-]{2})DOCSHELL")
-RE_DOMWINDOW = re.compile("I\/DocShellAndDOMWindowLeak ([+\-]{2})DOMWINDOW")
+RE_DOCSHELL = re.compile(r"I\/DocShellAndDOMWindowLeak ([+\-]{2})DOCSHELL")
+RE_DOMWINDOW = re.compile(r"I\/DocShellAndDOMWindowLeak ([+\-]{2})DOMWINDOW")
class ShutdownLeaks(object):
@@ -233,7 +233,7 @@ class ShutdownLeaks(object):
self.hiddenDocShellsCount += 1
def _parseValue(self, line, name):
- match = re.search("\[%s = (.+?)\]" % name, line)
+ match = re.search(r"\[%s = (.+?)\]" % name, line)
if match:
return match.group(1)
return None
@@ -329,17 +329,17 @@ class LSANLeaks(object):
)
self.startRegExp = re.compile(
- "==\d+==ERROR: LeakSanitizer: detected memory leaks"
+ r"==\d+==ERROR: LeakSanitizer: detected memory leaks"
)
self.fatalErrorRegExp = re.compile(
- "==\d+==LeakSanitizer has encountered a fatal error."
+ r"==\d+==LeakSanitizer has encountered a fatal error."
)
self.symbolizerOomRegExp = re.compile(
"LLVMSymbolizer: error reading file: Cannot allocate memory"
)
- self.stackFrameRegExp = re.compile(" #\d+ 0x[0-9a-f]+ in ([^(</]+)")
+ self.stackFrameRegExp = re.compile(r" #\d+ 0x[0-9a-f]+ in ([^(</]+)")
self.sysLibStackFrameRegExp = re.compile(
- " #\d+ 0x[0-9a-f]+ \(([^+]+)\+0x[0-9a-f]+\)"
+ r" #\d+ 0x[0-9a-f]+ \(([^+]+)\+0x[0-9a-f]+\)"
)
def log(self, line, path=""):
diff --git a/testing/mochitest/server.js b/testing/mochitest/server.js
index 740404d94e..934f0b281c 100644
--- a/testing/mochitest/server.js
+++ b/testing/mochitest/server.js
@@ -215,7 +215,7 @@ function createMochitestServer(serverBasePath) {
});
return file;
},
- QueryInterface(aIID) {
+ QueryInterface() {
return this;
},
};
diff --git a/testing/mochitest/static/browser.template.txt b/testing/mochitest/static/browser.template.txt
index fe4f2080b2..2f889d19d7 100644
--- a/testing/mochitest/static/browser.template.txt
+++ b/testing/mochitest/static/browser.template.txt
@@ -1,5 +1,5 @@
/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
+ https://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
diff --git a/testing/mochitest/tests/Harness_sanity/SpecialPowersLoadChromeScript.js b/testing/mochitest/tests/Harness_sanity/SpecialPowersLoadChromeScript.js
index 9591f3bca4..92a84e1ffa 100644
--- a/testing/mochitest/tests/Harness_sanity/SpecialPowersLoadChromeScript.js
+++ b/testing/mochitest/tests/Harness_sanity/SpecialPowersLoadChromeScript.js
@@ -6,7 +6,7 @@ addMessageListener("foo", function (message) {
sendAsyncMessage("bar", message);
});
-addMessageListener("valid-assert", function (message) {
+addMessageListener("valid-assert", function () {
assert.ok(true, "valid assertion");
assert.equal(1, 1, "another valid assertion");
sendAsyncMessage("valid-assert-done");
diff --git a/testing/mochitest/tests/Harness_sanity/test_SpecialPowersExtension.html b/testing/mochitest/tests/Harness_sanity/test_SpecialPowersExtension.html
index 34b75933a0..3d374735a6 100644
--- a/testing/mochitest/tests/Harness_sanity/test_SpecialPowersExtension.html
+++ b/testing/mochitest/tests/Harness_sanity/test_SpecialPowersExtension.html
@@ -14,11 +14,11 @@
<script class="testbody" type="text/javascript">
var eventCount = 0;
-function testEventListener(e) {
+function testEventListener() {
++eventCount;
}
-function testEventListener2(e) {
+function testEventListener2() {
++eventCount;
}
diff --git a/testing/mochitest/tests/Harness_sanity/test_SpecialPowersLoadChromeScript.html b/testing/mochitest/tests/Harness_sanity/test_SpecialPowersLoadChromeScript.html
index 7242bd19f5..3c9bbf3913 100644
--- a/testing/mochitest/tests/Harness_sanity/test_SpecialPowersLoadChromeScript.html
+++ b/testing/mochitest/tests/Harness_sanity/test_SpecialPowersLoadChromeScript.html
@@ -37,7 +37,7 @@ function endOfFirstTest() {
// that is used to run the chrome script.
script2 = SpecialPowers.loadChromeScript(_ => {
/* eslint-env mozilla/chrome-script */
- addMessageListener("valid-assert", function (message) {
+ addMessageListener("valid-assert", function () {
assert.equal(typeof XMLHttpRequest, "function", "XMLHttpRequest is defined");
assert.equal(typeof CSS, "undefined", "CSS is not defined");
sendAsyncMessage("valid-assert-done");
diff --git a/testing/mochitest/tests/Harness_sanity/test_SpecialPowersLoadChromeScript_function.html b/testing/mochitest/tests/Harness_sanity/test_SpecialPowersLoadChromeScript_function.html
index af31d7b25a..4de074800f 100644
--- a/testing/mochitest/tests/Harness_sanity/test_SpecialPowersLoadChromeScript_function.html
+++ b/testing/mochitest/tests/Harness_sanity/test_SpecialPowersLoadChromeScript_function.html
@@ -22,7 +22,7 @@ var script = SpecialPowers.loadChromeScript(function loadChromeScriptTest() {
sendAsyncMessage("bar", message);
});
- addMessageListener("valid-assert", function (message) {
+ addMessageListener("valid-assert", function () {
assert.ok(true, "valid assertion");
assert.equal(1, 1, "another valid assertion");
sendAsyncMessage("valid-assert-done");
diff --git a/testing/mochitest/tests/Harness_sanity/test_createFiles.html b/testing/mochitest/tests/Harness_sanity/test_createFiles.html
index 0e0637a230..7a06a2ad11 100644
--- a/testing/mochitest/tests/Harness_sanity/test_createFiles.html
+++ b/testing/mochitest/tests/Harness_sanity/test_createFiles.html
@@ -23,7 +23,7 @@
is(f.type, fileType, "File should have the specified type");
test2();
},
- function (msg) { ok(false, "Should be able to create a file without an error"); test2(); }
+ function () { ok(false, "Should be able to create a file without an error"); test2(); }
);
}
@@ -36,7 +36,7 @@
SpecialPowers.createFiles([{name: "/\/\/\/\/\/\/\/\/\/\/\invalidname",}],
function () { test3Check(false); },
- function (msg) { test3Check(true); }
+ function () { test3Check(true); }
);
}
@@ -75,7 +75,7 @@
ok(f.name, "test4 test file should have a name");
SimpleTest.finish();
},
- function (msg) {
+ function () {
ok(false, "Should be able to create a file without a name without an error");
SimpleTest.finish();
}
diff --git a/testing/mochitest/tests/Harness_sanity/test_sanityEventUtils.html b/testing/mochitest/tests/Harness_sanity/test_sanityEventUtils.html
index b24251b227..4a9abb2305 100644
--- a/testing/mochitest/tests/Harness_sanity/test_sanityEventUtils.html
+++ b/testing/mochitest/tests/Harness_sanity/test_sanityEventUtils.html
@@ -247,7 +247,7 @@ function starttest() {
/* test synthesizeMouse* */
//focus trick enables us to run this in iframes
- $("radioTarget1").addEventListener('focus', function (aEvent) {
+ $("radioTarget1").addEventListener('focus', function () {
synthesizeMouse($("radioTarget1"), 1, 1, {});
is($("radioTarget1").checked, true, "synthesizeMouse should work")
$("radioTarget1").checked = false;
@@ -260,7 +260,7 @@ function starttest() {
$("radioTarget1").focus();
//focus trick enables us to run this in iframes
- $("textBoxA").addEventListener("focus", function (aEvent) {
+ $("textBoxA").addEventListener("focus", function () {
check = false;
$("textBoxA").addEventListener("click", function() { check = true; }, { once: true });
synthesizeMouseAtCenter($("textBoxA"), {});
diff --git a/testing/mochitest/tests/SimpleTest/AccessibilityUtils.js b/testing/mochitest/tests/SimpleTest/AccessibilityUtils.js
index 0e95565019..cf4daaf416 100644
--- a/testing/mochitest/tests/SimpleTest/AccessibilityUtils.js
+++ b/testing/mochitest/tests/SimpleTest/AccessibilityUtils.js
@@ -388,19 +388,23 @@ this.AccessibilityUtils = (function () {
if (accessible.role != Ci.nsIAccessibleRole.ROLE_PAGETAB) {
return false; // Not a tab.
}
- // ToDo: We may eventually need to support intervening generics between
- // a tab and its tablist here.
- const tablist = accessible.parent;
+ const tablist = findNonGenericParentAccessible(accessible);
if (!tablist || tablist.role != Ci.nsIAccessibleRole.ROLE_PAGETABLIST) {
return false; // The tab isn't inside a tablist.
}
// ToDo: We may eventually need to support tablists which use
// aria-activedescendant here.
// Check that there is only one keyboard reachable tab.
- const childCount = tablist.childCount;
let foundFocusable = false;
- for (let c = 0; c < childCount; c++) {
- const tab = tablist.getChildAt(c);
+ for (const tab of findNonGenericChildrenAccessible(tablist)) {
+ // Allow whitespaces to be included in the tablist for styling purposes
+ const isWhitespace =
+ tab.role == Ci.nsIAccessibleRole.ROLE_TEXT_LEAF &&
+ tab.DOMNode.textContent.trim().length === 0;
+ if (tab.role != Ci.nsIAccessibleRole.ROLE_PAGETAB && !isWhitespace) {
+ // The tablist includes children other than tabs or whitespaces
+ a11yFail("Only tabs should be included in a tablist", accessible);
+ }
// Use tabIndex rather than a11y focusable state because all tabs might
// have tabindex="-1".
if (tab.DOMNode.tabIndex == 0) {
@@ -461,6 +465,72 @@ this.AccessibilityUtils = (function () {
}
/**
+ * The gridcells are not expected to be interactive and focusable
+ * individually, but it is allowed to manually manage focus within the grid
+ * per ARIA Grid pattern (https://www.w3.org/WAI/ARIA/apg/patterns/grid/).
+ * Example of such grid would be a datepicker where one gridcell can be
+ * selected and the focus is moved with arrow keys once the user tabbed into
+ * the grid. In grids like a calendar, only one element would be included in
+ * the focus order and the rest of grid cells may not have an interactive
+ * accessible created. We need to special case the check for these gridcells.
+ */
+ function isAccessibleGridcell(node) {
+ if (!node || !node.ownerGlobal) {
+ return false;
+ }
+ const accessible = getAccessible(node);
+
+ if (!accessible || accessible.role != Ci.nsIAccessibleRole.ROLE_GRID_CELL) {
+ return false; // Not a grid cell.
+ }
+ // ToDo: We may eventually need to support intervening generics between
+ // a grid cell and its grid container here.
+ const gridRow = accessible.parent;
+ if (!gridRow || gridRow.role != Ci.nsIAccessibleRole.ROLE_ROW) {
+ return false; // The grid cell isn't inside a row.
+ }
+ let grid = gridRow.parent;
+ if (!grid) {
+ return false; // The grid cell isn't inside a grid.
+ }
+ if (grid.role == Ci.nsIAccessibleRole.ROLE_GROUPING) {
+ // Grid built on the HTML table may include <tbody> wrapper:
+ grid = grid.parent;
+ if (!grid || grid.role != Ci.nsIAccessibleRole.ROLE_GRID) {
+ return false; // The grid cell isn't inside a grid.
+ }
+ }
+ // Check that there is only one keyboard reachable grid cell.
+ let foundFocusable = false;
+ for (const gridCell of grid.DOMNode.querySelectorAll(
+ "td, [role=gridcell]"
+ )) {
+ // Grid cells are not expected to have a "tabindex" attribute and to be
+ // included in the focus order, with the exception of the only one cell
+ // that is included in the page tab sequence to provide access to the grid.
+ if (gridCell.tabIndex == 0) {
+ if (foundFocusable) {
+ // Only one grid cell within a grid should be focusable.
+ // ToDo: Fine-tune the a11y-check error message generated in this case.
+ // Strictly speaking, it's not ideal that we're performing an action
+ // from an is function, which normally only queries something without
+ // any externally observable behaviour. That said, fixing that would
+ // involve different return values for different cases (not a grid
+ // cell, too many focusable grid cells, etc) so we could move the
+ // a11yFail call to the caller.
+ a11yFail(
+ "Only one grid cell should be focusable in a grid",
+ accessible
+ );
+ return false;
+ }
+ foundFocusable = true;
+ }
+ }
+ return foundFocusable;
+ }
+
+ /**
* XUL treecol elements currently aren't focusable, making them inaccessible.
* For now, we don't flag these as a failure to avoid breaking multiple tests.
* ToDo: We should remove this exception after this is fixed in bug 1848397.
@@ -477,7 +547,7 @@ this.AccessibilityUtils = (function () {
}
/**
- * Determine if an accessible is a combobox container of the url bar. We
+ * Determine if a DOM node is a combobox container of the url bar. We
* intentionally leave this element unlabeled, because its child is a search
* input that is the target and main control of this component. In general, we
* want to avoid duplication in the label announcement when a user focuses the
@@ -486,68 +556,125 @@ this.AccessibilityUtils = (function () {
* difficult to keep the accessible name synchronized between the combobox and
* the input. Thus, we need to special case the label check for this control.
*/
- function isUnlabeledUrlBarCombobox(accessible) {
- const node = accessible.DOMNode;
+ function isUnlabeledUrlBarCombobox(node) {
if (!node || !node.ownerGlobal) {
return false;
}
- const ariaRoles = getAriaRoles(accessible);
+ let ariaRole = node.getAttribute("role");
// There are only two cases of this pattern: <moz-input-box> and <searchbar>
const isMozInputBox =
node.tagName == "moz-input-box" &&
node.classList.contains("urlbar-input-box");
const isSearchbar = node.tagName == "searchbar" && node.id == "searchbar";
- return (isMozInputBox || isSearchbar) && ariaRoles.includes("combobox");
+ return (isMozInputBox || isSearchbar) && ariaRole == "combobox";
}
/**
- * Determine if an accessible is an option within the url bar. We know each
+ * Determine if a DOM node is an option within the url bar. We know each
* url bar option is accessible, but it disappears as soon as it is clicked
* during tests and the a11y-checks do not have time to test the label,
* because the Fluent localization is not yet completed by then. Thus, we
* need to special case the label check for these controls.
*/
- function isUnlabeledUrlBarOption(accessible) {
- const node = accessible.DOMNode;
+ function isUnlabeledUrlBarOption(node) {
if (!node || !node.ownerGlobal) {
return false;
}
- const ariaRoles = getAriaRoles(accessible);
- return (
+ const role = getAccessible(node)?.role;
+ const isOption =
node.tagName == "span" &&
- ariaRoles.includes("option") &&
- node.classList.contains("urlbarView-row-inner") &&
- node.hasAttribute("data-l10n-id")
- );
+ node.getAttribute("role") == "option" &&
+ node.classList.contains("urlbarView-row-inner");
+ const isMenuItem =
+ node.tagName == "menuitem" &&
+ role == Ci.nsIAccessibleRole.ROLE_MENUITEM &&
+ node.classList.contains("urlbarView-result-menuitem");
+ // Not all options have "data-l10n-id" attributes in the URL Bar, because
+ // some of options are autocomplete options based on the user input and
+ // they are not expected to be localized.
+ return isOption || isMenuItem;
}
/**
- * Determine if an accessible is a menuitem within the XUL menu. We know each
+ * Determine if a DOM node is a menuitem within the XUL menu. We know each
* menuitem is accessible, but it disappears as soon as it is clicked during
* tests and the a11y-checks do not have time to test the label, because the
* Fluent localization is not yet completed by then. Thus, we need to special
* case the label check for these controls.
*/
- function isUnlabeledMenuitem(accessible) {
- const node = accessible.DOMNode;
+ function isUnlabeledMenuitem(node) {
if (!node || !node.ownerGlobal) {
return false;
}
- let hasLabel = false;
- for (const child of node.childNodes) {
- if (child.tagName == "label") {
- hasLabel = true;
- }
- }
+ const hasLabel = node.querySelector("label, description");
+ const isMenuItem =
+ node.getAttribute("role") == "menuitem" ||
+ (node.tagName == "richlistitem" &&
+ node.classList.contains("autocomplete-richlistitem")) ||
+ (node.tagName == "menuitem" &&
+ node.classList.contains("urlbarView-result-menuitem"));
+
+ const isParentMenu =
+ node.parentNode.getAttribute("role") == "menu" ||
+ (node.parentNode.tagName == "richlistbox" &&
+ node.parentNode.classList.contains("autocomplete-richlistbox")) ||
+ (node.parentNode.tagName == "menupopup" &&
+ node.parentNode.classList.contains("urlbarView-result-menu"));
return (
- accessible.role == Ci.nsIAccessibleRole.ROLE_MENUITEM &&
- accessible.parent.role == Ci.nsIAccessibleRole.ROLE_MENUPOPUP &&
+ isMenuItem &&
+ isParentMenu &&
hasLabel &&
- node.hasAttribute("data-l10n-id")
+ (node.hasAttribute("data-l10n-id") || node.tagName == "richlistitem")
+ );
+ }
+
+ /**
+ * Determine if the node is a "Show All" or one of image buttons on the
+ * about:config page, or a "X" close button on moz-message-bar. We know these
+ * buttons are accessible, but they disappear/are replaced as soon as they
+ * are clicked during tests and the a11y-checks do not have time to test the
+ * label, because the Fluent localization is not yet completed by then.
+ * Thus, we need to special case the label check for these controls.
+ */
+ function isUnlabeledImageButton(node) {
+ if (!node || !node.ownerGlobal) {
+ return false;
+ }
+ const isShowAllButton = node.id == "show-all";
+ const isReplacedImageButton =
+ node.classList.contains("button-add") ||
+ node.classList.contains("button-delete") ||
+ node.classList.contains("button-reset");
+ const isCloseMozMessageBarButton =
+ node.classList.contains("close") &&
+ node.getAttribute("data-l10n-id") == "moz-message-bar-close-button";
+ return (
+ node.tagName.toLowerCase() == "button" &&
+ node.hasAttribute("data-l10n-id") &&
+ (isShowAllButton || isReplacedImageButton || isCloseMozMessageBarButton)
);
}
/**
+ * Determine if a node is a XUL:button on a prompt popup. We know this button
+ * is accessible, but it disappears as soon as it is clicked during tests and
+ * the a11y-checks do not have time to test the label, because the Fluent
+ * localization is not yet completed by then. Thus, we need to special case
+ * the label check for these controls.
+ */
+ function isUnlabeledXulButton(node) {
+ if (!node || !node.ownerGlobal) {
+ return false;
+ }
+ const hasLabel = node.querySelector("label, xul\\:label");
+ const isButton =
+ node.getAttribute("role") == "button" ||
+ node.tagName == "button" ||
+ node.tagName == "xul:button";
+ return isButton && hasLabel && node.hasAttribute("data-l10n-id");
+ }
+
+ /**
* Determine if a node is a XUL element for which tabIndex should be ignored.
* Some XUL elements report -1 for the .tabIndex property, even though they
* are in fact keyboard focusable.
@@ -758,13 +885,6 @@ this.AccessibilityUtils = (function () {
const { DOMNode } = accessible;
let name = accessible.name;
if (!name) {
- if (
- isUnlabeledUrlBarCombobox(accessible) ||
- isUnlabeledUrlBarOption(accessible) ||
- isUnlabeledMenuitem(accessible)
- ) {
- return;
- }
// If text has just been inserted into the tree, the a11y engine might not
// have picked it up yet.
forceRefreshDriverTick(DOMNode);
@@ -773,6 +893,21 @@ this.AccessibilityUtils = (function () {
} catch (e) {
// The Accessible died because the DOM node was removed or hidden.
if (gEnv.labelRule) {
+ // Some elements disappear as soon as they are clicked during tests,
+ // their accessible dies before the Fluent localization is completed.
+ // We want to exclude these groups of nodes from the label check.
+ // Note: In other cases, this first block isn't necessarily hit
+ // because Fluent isn't finished yet. This might happen if a text
+ // node was inserted (whether by Fluent or something else) but a11y
+ // hasn't picked it up yet, but the node gets hidden before a11y
+ // can pick it up.
+ if (
+ isUnlabeledUrlBarOption(DOMNode) ||
+ isUnlabeledMenuitem(DOMNode) ||
+ isUnlabeledImageButton(DOMNode)
+ ) {
+ return;
+ }
a11yWarn("Unlabeled element removed before l10n finished", {
DOMNode,
});
@@ -795,6 +930,13 @@ this.AccessibilityUtils = (function () {
accessible.name;
} catch (e) {
// The Accessible died because the DOM node was removed or hidden.
+ if (
+ isUnlabeledUrlBarOption(DOMNode) ||
+ isUnlabeledImageButton(DOMNode) ||
+ isUnlabeledXulButton(DOMNode)
+ ) {
+ return;
+ }
a11yWarn("Unlabeled element removed before l10n finished", {
DOMNode,
});
@@ -811,6 +953,15 @@ this.AccessibilityUtils = (function () {
name = name.trim();
}
if (gEnv.labelRule && !name) {
+ // The URL and Search Bar comboboxes are purposefully unlabeled,
+ // since they include labeled inputs that are receiving focus.
+ // Or the Accessible died because the DOM node was removed or hidden.
+ if (
+ isUnlabeledUrlBarCombobox(DOMNode) ||
+ isUnlabeledUrlBarOption(DOMNode)
+ ) {
+ return;
+ }
a11yFail("Interactive elements must be labeled", accessible);
return;
@@ -935,6 +1086,36 @@ this.AccessibilityUtils = (function () {
return null;
}
+ /**
+ * Find the nearest non-generic ancestor for a node to account for generic
+ * containers to intervene between the ancestor and it child.
+ */
+ function findNonGenericParentAccessible(childAcc) {
+ for (let acc = childAcc.parent; acc; acc = acc.parent) {
+ if (acc.computedARIARole != "generic") {
+ return acc;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Find the nearest non-generic children for a node to account for generic
+ * containers to intervene between the ancestor and its children.
+ */
+ function* findNonGenericChildrenAccessible(parentAcc) {
+ const count = parentAcc.childCount;
+ for (let c = 0; c < count; ++c) {
+ const child = parentAcc.getChildAt(c);
+ // When Gecko will consider only one role as generic, we'd use child.role
+ if (child.computedARIARole == "generic") {
+ yield* findNonGenericChildrenAccessible(child);
+ } else {
+ yield child;
+ }
+ }
+ }
+
function runIfA11YChecks(task) {
return (...args) => (gA11YChecks ? task(...args) : null);
}
@@ -956,7 +1137,7 @@ this.AccessibilityUtils = (function () {
// node might be the image.
const acc = findInteractiveAccessible(node);
if (!acc) {
- if (isInaccessibleXulTreecol(node)) {
+ if (isAccessibleGridcell(node) || isInaccessibleXulTreecol(node)) {
return;
}
if (gEnv.mustHaveAccessibleRule) {
diff --git a/testing/mochitest/tests/SimpleTest/EventUtils.js b/testing/mochitest/tests/SimpleTest/EventUtils.js
index 739c7052ea..8833b8bc59 100644
--- a/testing/mochitest/tests/SimpleTest/EventUtils.js
+++ b/testing/mochitest/tests/SimpleTest/EventUtils.js
@@ -1,3 +1,4 @@
+/* eslint-disable no-nested-ternary */
/**
* EventUtils provides some utility methods for creating and sending DOM events.
*
@@ -569,14 +570,86 @@ function synthesizeMouse(aTarget, aOffsetX, aOffsetY, aEvent, aWindow) {
aWindow
);
}
-function synthesizeTouch(aTarget, aOffsetX, aOffsetY, aEvent, aWindow) {
- var rect = aTarget.getBoundingClientRect();
- return synthesizeTouchAtPoint(
- rect.left + aOffsetX,
- rect.top + aOffsetY,
- aEvent,
- aWindow
- );
+
+/**
+ * Synthesize one or more touches on aTarget. aTarget can be either Element
+ * or Array of Elements. aOffsetX, aOffsetY, aEvent.id, aEvent.rx, aEvent.ry,
+ * aEvent.angle, aEvent.force, aEvent.tiltX, aEvent.tiltY and aEvent.twist can
+ * be either Number or Array of Numbers (can be mixed). If you specify array
+ * to synthesize a multi-touch, you need to specify same length arrays. If
+ * you don't specify array to them, same values (or computed default values for
+ * aEvent.id) are used for all touches.
+ *
+ * @param {Element | Element[]} aTarget The target element which you specify
+ * relative offset from its top-left.
+ * @param {Number | Number[]} aOffsetX The relative offset from left of aTarget.
+ * @param {Number | Number[]} aOffsetY The relative offset from top of aTarget.
+ * @param {Object} aEvent
+ * type: The touch event type. If undefined, "touchstart" and "touchend" will
+ * be synthesized at same point.
+ *
+ * id: The touch id. If you don't specify this, default touch id will be used
+ * for first touch and further touch ids are the values incremented from the
+ * first id.
+ *
+ * rx, ry: The radii of the touch.
+ *
+ * angle: The angle in degree.
+ *
+ * force: The force of the touch. If the type is "touchend", this should be 0.
+ * If unspecified, this is default to 0 for "touchend" or 1 for the others.
+ *
+ * tiltX, tiltY: The tilt of the touch.
+ *
+ * twist: The twist of the touch.
+ * @param {Window} aWindow Default to `window`.
+ * @returns true if and only if aEvent.type is specified and default of the
+ * event is prevented.
+ */
+function synthesizeTouch(
+ aTarget,
+ aOffsetX,
+ aOffsetY,
+ aEvent = {},
+ aWindow = window
+) {
+ let rectX, rectY;
+ if (Array.isArray(aTarget)) {
+ let lastTarget, lastTargetRect;
+ aTarget.forEach(target => {
+ const rect =
+ target == lastTarget ? lastTargetRect : target.getBoundingClientRect();
+ rectX.push(rect.left);
+ rectY.push(rect.top);
+ lastTarget = target;
+ lastTargetRect = rect;
+ });
+ } else {
+ const rect = aTarget.getBoundingClientRect();
+ rectX = [rect.left];
+ rectY = [rect.top];
+ }
+ const offsetX = (() => {
+ if (Array.isArray(aOffsetX)) {
+ let ret = [];
+ aOffsetX.forEach((value, index) => {
+ ret.push(value + rectX[Math.min(index, rectX.length - 1)]);
+ });
+ return ret;
+ }
+ return aOffsetX + rectX[0];
+ })();
+ const offsetY = (() => {
+ if (Array.isArray(aOffsetY)) {
+ let ret = [];
+ aOffsetY.forEach((value, index) => {
+ ret.push(value + rectY[Math.min(index, rectY.length - 1)]);
+ });
+ return ret;
+ }
+ return aOffsetY + rectY[0];
+ })();
+ return synthesizeTouchAtPoint(offsetX, offsetY, aEvent, aWindow);
}
/**
@@ -776,68 +849,160 @@ function synthesizeMouseAtPoint(left, top, aEvent, aWindow = window) {
return defaultPrevented;
}
-function synthesizeTouchAtPoint(left, top, aEvent, aWindow = window) {
- var utils = _getDOMWindowUtils(aWindow);
- let defaultPrevented = false;
+/**
+ * Synthesize one or more touches at the points. aLeft, aTop, aEvent.id,
+ * aEvent.rx, aEvent.ry, aEvent.angle, aEvent.force, aEvent.tiltX, aEvent.tiltY
+ * and aEvent.twist can be either Number or Array of Numbers (can be mixed).
+ * If you specify array to synthesize a multi-touch, you need to specify same
+ * length arrays. If you don't specify array to them, same values are used for
+ * all touches.
+ *
+ * @param {Element | Element[]} aTarget The target element which you specify
+ * relative offset from its top-left.
+ * @param {Number | Number[]} aOffsetX The relative offset from left of aTarget.
+ * @param {Number | Number[]} aOffsetY The relative offset from top of aTarget.
+ * @param {Object} aEvent
+ * type: The touch event type. If undefined, "touchstart" and "touchend" will
+ * be synthesized at same point.
+ *
+ * id: The touch id. If you don't specify this, default touch id will be used
+ * for first touch and further touch ids are the values incremented from the
+ * first id.
+ *
+ * rx, ry: The radii of the touch.
+ *
+ * angle: The angle in degree.
+ *
+ * force: The force of the touch. If the type is "touchend", this should be 0.
+ * If unspecified, this is default to 0 for "touchend" or 1 for the others.
+ *
+ * tiltX, tiltY: The tilt of the touch.
+ *
+ * twist: The twist of the touch.
+ * @param {Window} aWindow Default to `window`.
+ * @returns true if and only if aEvent.type is specified and default of the
+ * event is prevented.
+ */
+function synthesizeTouchAtPoint(aLeft, aTop, aEvent = {}, aWindow = window) {
+ let utils = _getDOMWindowUtils(aWindow);
+ if (!utils) {
+ return false;
+ }
- if (utils) {
- var id = aEvent.id || utils.DEFAULT_TOUCH_POINTER_ID;
- var rx = aEvent.rx || 1;
- var ry = aEvent.ry || 1;
- var angle = aEvent.angle || 0;
- var force = aEvent.force || (aEvent.type === "touchend" ? 0 : 1);
- var tiltX = aEvent.tiltX || 0;
- var tiltY = aEvent.tiltY || 0;
- var twist = aEvent.twist || 0;
- var modifiers = _parseModifiers(aEvent, aWindow);
+ if (
+ Array.isArray(aLeft) &&
+ Array.isArray(aTop) &&
+ aLeft.length != aTop.length
+ ) {
+ throw new Error(`aLeft and aTop should be same length array`);
+ }
- if ("type" in aEvent && aEvent.type) {
- defaultPrevented = utils.sendTouchEvent(
- aEvent.type,
- [id],
- [left],
- [top],
- [rx],
- [ry],
- [angle],
- [force],
- [tiltX],
- [tiltY],
- [twist],
- modifiers
- );
- } else {
- utils.sendTouchEvent(
- "touchstart",
- [id],
- [left],
- [top],
- [rx],
- [ry],
- [angle],
- [force],
- [tiltX],
- [tiltY],
- [twist],
- modifiers
- );
- utils.sendTouchEvent(
- "touchend",
- [id],
- [left],
- [top],
- [rx],
- [ry],
- [angle],
- [force],
- [tiltX],
- [tiltY],
- [twist],
- modifiers
+ const arrayLength = Array.isArray(aLeft)
+ ? aLeft.length
+ : Array.isArray(aTop)
+ ? aTop.length
+ : 1;
+
+ function throwExceptionIfDifferentLengthArray(aArray, aName) {
+ if (Array.isArray(aArray) && arrayLength !== aArray.length) {
+ throw new Error(`${aName} is different length array`);
+ }
+ }
+ const leftArray = (() => {
+ if (Array.isArray(aLeft)) {
+ return aLeft;
+ }
+ return new Array(arrayLength).fill(aLeft);
+ })();
+ const topArray = (() => {
+ if (Array.isArray(aTop)) {
+ throwExceptionIfDifferentLengthArray(aTop, "aTop");
+ return aTop;
+ }
+ return new Array(arrayLength).fill(aTop);
+ })();
+ const idArray = (() => {
+ if ("id" in aEvent && Array.isArray(aEvent.id)) {
+ throwExceptionIfDifferentLengthArray(aEvent.id, "aEvent.id");
+ return aEvent.id;
+ }
+ let id = aEvent.id || utils.DEFAULT_TOUCH_POINTER_ID;
+ let ret = [];
+ for (let i = 0; i < arrayLength; i++) {
+ ret.push(id++);
+ }
+ return ret;
+ })();
+ function getSameLengthArrayOfEventProperty(aProperty, aDefaultValue) {
+ if (aProperty in aEvent && Array.isArray(aEvent[aProperty])) {
+ throwExceptionIfDifferentLengthArray(
+ aEvent.rx,
+ arrayLength,
+ `aEvent.${aProperty}`
);
+ return aEvent[aProperty];
}
+ return new Array(arrayLength).fill(aEvent[aProperty] || aDefaultValue);
}
- return defaultPrevented;
+ const rxArray = getSameLengthArrayOfEventProperty("rx", 1);
+ const ryArray = getSameLengthArrayOfEventProperty("ry", 1);
+ const angleArray = getSameLengthArrayOfEventProperty("angle", 0);
+ const forceArray = getSameLengthArrayOfEventProperty(
+ "force",
+ aEvent.type === "touchend" ? 0 : 1
+ );
+ const tiltXArray = getSameLengthArrayOfEventProperty("tiltX", 0);
+ const tiltYArray = getSameLengthArrayOfEventProperty("tiltY", 0);
+ const twistArray = getSameLengthArrayOfEventProperty("twist", 0);
+
+ const modifiers = _parseModifiers(aEvent, aWindow);
+
+ if ("type" in aEvent && aEvent.type) {
+ return utils.sendTouchEvent(
+ aEvent.type,
+ idArray,
+ leftArray,
+ topArray,
+ rxArray,
+ ryArray,
+ angleArray,
+ forceArray,
+ tiltXArray,
+ tiltYArray,
+ twistArray,
+ modifiers
+ );
+ }
+
+ utils.sendTouchEvent(
+ "touchstart",
+ idArray,
+ leftArray,
+ topArray,
+ rxArray,
+ ryArray,
+ angleArray,
+ forceArray,
+ tiltXArray,
+ tiltYArray,
+ twistArray,
+ modifiers
+ );
+ utils.sendTouchEvent(
+ "touchend",
+ idArray,
+ leftArray,
+ topArray,
+ rxArray,
+ ryArray,
+ angleArray,
+ forceArray,
+ tiltXArray,
+ tiltYArray,
+ twistArray,
+ modifiers
+ );
+ return false;
}
// Call synthesizeMouse with coordinates at the center of aTarget.
@@ -851,7 +1016,7 @@ function synthesizeMouseAtCenter(aTarget, aEvent, aWindow) {
aWindow
);
}
-function synthesizeTouchAtCenter(aTarget, aEvent, aWindow) {
+function synthesizeTouchAtCenter(aTarget, aEvent = {}, aWindow = window) {
var rect = aTarget.getBoundingClientRect();
synthesizeTouchAtPoint(
rect.left + rect.width / 2,
@@ -1020,7 +1185,9 @@ function _sendWheelAndPaint(
}
var onwheel = function () {
- SpecialPowers.removeSystemEventListener(window, "wheel", onwheel);
+ SpecialPowers.wrap(window).removeEventListener("wheel", onwheel, {
+ mozSystemGroup: true,
+ });
// Wait one frame since the wheel event has not caused a refresh observer
// to be added yet.
@@ -1055,7 +1222,9 @@ function _sendWheelAndPaint(
// Listen for the system wheel event, because it happens after all of
// the other wheel events, including legacy events.
- SpecialPowers.addSystemEventListener(aWindow, "wheel", onwheel);
+ SpecialPowers.wrap(aWindow).addEventListener("wheel", onwheel, {
+ mozSystemGroup: true,
+ });
if (aFlushMode === _FlushModes.FLUSH) {
synthesizeWheel(aTarget, aOffsetX, aOffsetY, aEvent, aWindow);
} else {
@@ -1405,13 +1574,10 @@ function synthesizeAndWaitNativeMouseMove(
);
let eventRegisteredPromise = new Promise(resolve => {
- mm.addMessageListener(
- "Test:MouseMoveRegistered",
- function processed(message) {
- mm.removeMessageListener("Test:MouseMoveRegistered", processed);
- resolve();
- }
- );
+ mm.addMessageListener("Test:MouseMoveRegistered", function processed() {
+ mm.removeMessageListener("Test:MouseMoveRegistered", processed);
+ resolve();
+ });
});
let eventReceivedPromise = ContentTask.spawn(
browser,
@@ -1579,7 +1745,7 @@ function synthesizeAndWaitKey(
);
let keyRegisteredPromise = new Promise(resolve => {
- mm.addMessageListener("Test:KeyRegistered", function processed(message) {
+ mm.addMessageListener("Test:KeyRegistered", function processed() {
mm.removeMessageListener("Test:KeyRegistered", processed);
resolve();
});
@@ -3853,21 +4019,19 @@ async function synthesizePlainDragAndCancel(
aExpectedDataTransferItems
);
}
- SpecialPowers.addSystemEventListener(
- srcElement.ownerDocument,
+ SpecialPowers.wrap(srcElement.ownerDocument).addEventListener(
"dragstart",
onDragStart,
- { capture: true }
+ { capture: true, mozSystemGroup: true }
);
try {
aParams.expectCancelDragStart = true;
await synthesizePlainDragAndDrop(aParams);
} finally {
- SpecialPowers.removeSystemEventListener(
- srcElement.ownerDocument,
+ SpecialPowers.wrap(srcElement.ownerDocument).removeEventListener(
"dragstart",
onDragStart,
- { capture: true }
+ { capture: true, mozSystemGroup: true }
);
}
return result;
@@ -3884,33 +4048,23 @@ class EventCounter {
// SpecialPowers is picky and needs to be passed an explicit reference to
// the function to be called. To avoid having to bind "this", we therefore
// define the method this way, via a property.
- this.handleEvent = aEvent => {
+ this.handleEvent = () => {
this.eventCount++;
};
- if (aOptions.mozSystemGroup) {
- SpecialPowers.addSystemEventListener(
- aTarget,
- aType,
- this.handleEvent,
- aOptions.capture
- );
- } else {
- aTarget.addEventListener(aType, this, aOptions);
- }
+ SpecialPowers.wrap(aTarget).addEventListener(
+ aType,
+ this.handleEvent,
+ aOptions
+ );
}
unregister() {
- if (this.options.mozSystemGroup) {
- SpecialPowers.removeSystemEventListener(
- this.target,
- this.type,
- this.handleEvent,
- this.options.capture
- );
- } else {
- this.target.removeEventListener(this.type, this, this.options);
- }
+ SpecialPowers.wrap(this.target).removeEventListener(
+ this.type,
+ this.handleEvent,
+ this.options
+ );
}
get count() {
diff --git a/testing/mochitest/tests/SimpleTest/LogController.js b/testing/mochitest/tests/SimpleTest/LogController.js
index 29580022f8..d0888d6032 100644
--- a/testing/mochitest/tests/SimpleTest/LogController.js
+++ b/testing/mochitest/tests/SimpleTest/LogController.js
@@ -48,7 +48,7 @@ LogController.extend = function (args, skip) {
};
/* logs message with given level. Currently used locally by log() and error() */
-LogController.logWithLevel = function (level, message /*, ...*/) {
+LogController.logWithLevel = function (level /*, ...*/) {
var msg = LogController.createLogMessage(
level,
LogController.extend(arguments, 1)
diff --git a/testing/mochitest/tests/SimpleTest/SimpleTest.js b/testing/mochitest/tests/SimpleTest/SimpleTest.js
index a237c25103..16f5c3ae8a 100644
--- a/testing/mochitest/tests/SimpleTest/SimpleTest.js
+++ b/testing/mochitest/tests/SimpleTest/SimpleTest.js
@@ -384,7 +384,7 @@ function usesFailurePatterns() {
* @return {boolean} Whether a matched failure pattern is found.
*/
function recordIfMatchesFailurePattern(name, diag) {
- let index = SimpleTest.expected.findIndex(([pat, count]) => {
+ let index = SimpleTest.expected.findIndex(([pat]) => {
return (
pat == null ||
(typeof name == "string" && name.includes(pat)) ||
diff --git a/testing/mochitest/tests/SimpleTest/TestRunner.js b/testing/mochitest/tests/SimpleTest/TestRunner.js
index 5f305a176b..2e48969d8d 100644
--- a/testing/mochitest/tests/SimpleTest/TestRunner.js
+++ b/testing/mochitest/tests/SimpleTest/TestRunner.js
@@ -63,7 +63,7 @@ function extend(obj, /* optional */ skip) {
return ret;
}
-function flattenArguments(lst /* ...*/) {
+function flattenArguments(/* ...*/) {
var res = [];
var args = extend(arguments);
while (args.length) {
diff --git a/testing/mochitest/tests/SimpleTest/paint_listener.js b/testing/mochitest/tests/SimpleTest/paint_listener.js
index 2fc6ab425a..89740454f2 100644
--- a/testing/mochitest/tests/SimpleTest/paint_listener.js
+++ b/testing/mochitest/tests/SimpleTest/paint_listener.js
@@ -100,7 +100,7 @@
window.promiseAllPaintsDone = function (subdoc = null, flush = false) {
var flushmode = flush ? FlushModes.FLUSH : FlushModes.NOFLUSH;
- return new Promise(function (resolve, reject) {
+ return new Promise(function (resolve) {
// The callback is given the components of the rect, but resolve() can
// only be given one arg, so we turn it back into an array.
waitForPaints((l, r, t, b) => resolve([l, r, t, b]), subdoc, flushmode);
diff --git a/testing/mochitest/tests/SimpleTest/setup.js b/testing/mochitest/tests/SimpleTest/setup.js
index 05ba8066a1..2a8509bc0a 100644
--- a/testing/mochitest/tests/SimpleTest/setup.js
+++ b/testing/mochitest/tests/SimpleTest/setup.js
@@ -247,7 +247,7 @@ TestRunner.logger.addListener(
var gTestList = [];
var RunSet = {};
-RunSet.runall = function (e) {
+RunSet.runall = function () {
// Filter tests to include|exclude tests based on data in params.filter.
// This allows for including or excluding tests from the gTestList
// TODO Only used by ipc tests, remove once those are implemented sanely
@@ -265,7 +265,7 @@ RunSet.runall = function (e) {
}
};
-RunSet.runtests = function (e) {
+RunSet.runtests = function () {
// Which tests we're going to run
var my_tests = gTestList;
diff --git a/testing/mochitest/tests/browser/browser_document_builder_sjs.js b/testing/mochitest/tests/browser/browser_document_builder_sjs.js
index 4b653a792d..fdf1691b7f 100644
--- a/testing/mochitest/tests/browser/browser_document_builder_sjs.js
+++ b/testing/mochitest/tests/browser/browser_document_builder_sjs.js
@@ -23,8 +23,9 @@ add_task(async function assertHtmlParam() {
const duration = performance.now() - startTime;
is(response.status, 200, "Response is a 200");
- ok(
- duration > delay,
+ Assert.greater(
+ duration,
+ delay,
`The delay parameter works as expected (took ${duration}ms)`
);