summaryrefslogtreecommitdiffstats
path: root/testing/mochitest/tests/browser
diff options
context:
space:
mode:
Diffstat (limited to 'testing/mochitest/tests/browser')
-rw-r--r--testing/mochitest/tests/browser/browser.ini56
-rw-r--r--testing/mochitest/tests/browser/browser_BrowserTestUtils.js312
-rw-r--r--testing/mochitest/tests/browser/browser_add_task.js31
-rw-r--r--testing/mochitest/tests/browser/browser_async.js9
-rw-r--r--testing/mochitest/tests/browser/browser_browserLoaded_content_loaded.js53
-rw-r--r--testing/mochitest/tests/browser/browser_document_builder_sjs.js74
-rw-r--r--testing/mochitest/tests/browser/browser_fail.js10
-rw-r--r--testing/mochitest/tests/browser/browser_fail_add_task.js27
-rw-r--r--testing/mochitest/tests/browser/browser_fail_add_task_uncaught_rejection.js29
-rw-r--r--testing/mochitest/tests/browser/browser_fail_async.js9
-rw-r--r--testing/mochitest/tests/browser/browser_fail_if.js4
-rw-r--r--testing/mochitest/tests/browser/browser_fail_throw.js5
-rw-r--r--testing/mochitest/tests/browser/browser_fail_timeout.js9
-rw-r--r--testing/mochitest/tests/browser/browser_fail_uncaught_rejection.js14
-rw-r--r--testing/mochitest/tests/browser/browser_fail_uncaught_rejection_expected.js12
-rw-r--r--testing/mochitest/tests/browser/browser_fail_uncaught_rejection_expected_multi.js11
-rw-r--r--testing/mochitest/tests/browser/browser_fail_unexpectedTimeout.js14
-rw-r--r--testing/mochitest/tests/browser/browser_getTestFile.js37
-rw-r--r--testing/mochitest/tests/browser/browser_head.js16
-rw-r--r--testing/mochitest/tests/browser/browser_parameters.js3
-rw-r--r--testing/mochitest/tests/browser/browser_pass.js13
-rw-r--r--testing/mochitest/tests/browser/browser_privileges.js17
-rw-r--r--testing/mochitest/tests/browser/browser_requestLongerTimeout.js10
-rw-r--r--testing/mochitest/tests/browser/browser_sanityException.js5
-rw-r--r--testing/mochitest/tests/browser/browser_sanityException2.js11
-rw-r--r--testing/mochitest/tests/browser/browser_setup_runs_first.js14
-rw-r--r--testing/mochitest/tests/browser/browser_setup_runs_for_only_tests.js15
-rw-r--r--testing/mochitest/tests/browser/browser_tasks_skip.js21
-rw-r--r--testing/mochitest/tests/browser/browser_tasks_skipall.js23
-rw-r--r--testing/mochitest/tests/browser/browser_uncaught_rejection_expected.js12
-rw-r--r--testing/mochitest/tests/browser/browser_waitForFocus.js160
-rw-r--r--testing/mochitest/tests/browser/browser_zz_fail_openwindow.js13
-rw-r--r--testing/mochitest/tests/browser/dummy.html7
-rw-r--r--testing/mochitest/tests/browser/head.js16
-rw-r--r--testing/mochitest/tests/browser/test-dir/test-file1
-rw-r--r--testing/mochitest/tests/browser/waitForFocusPage.html4
36 files changed, 1077 insertions, 0 deletions
diff --git a/testing/mochitest/tests/browser/browser.ini b/testing/mochitest/tests/browser/browser.ini
new file mode 100644
index 0000000000..82af0d1c46
--- /dev/null
+++ b/testing/mochitest/tests/browser/browser.ini
@@ -0,0 +1,56 @@
+[DEFAULT]
+support-files =
+ head.js
+ dummy.html
+
+[browser_add_task.js]
+[browser_async.js]
+[browser_browserLoaded_content_loaded.js]
+https_first_disabled = true
+[browser_BrowserTestUtils.js]
+skip-if = verify
+[browser_document_builder_sjs.js]
+skip-if =
+ os == "win" && os_version == "6.1" # Skip on Azure - frequent failure
+[browser_fail.js]
+skip-if = verify
+[browser_fail_add_task.js]
+skip-if = verify
+[browser_fail_add_task_uncaught_rejection.js]
+skip-if = verify
+[browser_fail_async.js]
+skip-if = verify
+[browser_fail_if.js]
+fail-if = true
+[browser_fail_throw.js]
+skip-if = verify
+[browser_fail_timeout.js]
+skip-if = true # Disabled beacuse it takes too long (bug 1178959)
+[browser_fail_uncaught_rejection.js]
+skip-if = verify
+[browser_fail_uncaught_rejection_expected.js]
+skip-if = verify
+[browser_fail_uncaught_rejection_expected_multi.js]
+skip-if = verify
+[browser_fail_unexpectedTimeout.js]
+skip-if = true # Disabled beacuse it takes too long (bug 1178959)
+[browser_getTestFile.js]
+support-files =
+ test-dir/*
+ waitForFocusPage.html
+[browser_head.js]
+[browser_pass.js]
+[browser_parameters.js]
+[browser_privileges.js]
+[browser_requestLongerTimeout.js]
+skip-if = true # Disabled beacuse it takes too long (bug 1178959)
+[browser_sanityException.js]
+[browser_sanityException2.js]
+[browser_setup_runs_first.js]
+[browser_setup_runs_for_only_tests.js]
+[browser_tasks_skip.js]
+[browser_tasks_skipall.js]
+[browser_uncaught_rejection_expected.js]
+[browser_waitForFocus.js]
+[browser_zz_fail_openwindow.js]
+skip-if = true # this catches outside of the main loop to find an extra window
diff --git a/testing/mochitest/tests/browser/browser_BrowserTestUtils.js b/testing/mochitest/tests/browser/browser_BrowserTestUtils.js
new file mode 100644
index 0000000000..cde2b8b927
--- /dev/null
+++ b/testing/mochitest/tests/browser/browser_BrowserTestUtils.js
@@ -0,0 +1,312 @@
+function getLastEventDetails(browser) {
+ return SpecialPowers.spawn(browser, [], async function () {
+ return content.document.getElementById("out").textContent;
+ });
+}
+
+add_task(async function () {
+ let onClickEvt =
+ 'document.getElementById("out").textContent = event.target.localName + "," + event.clientX + "," + event.clientY;';
+ const url =
+ "<body onclick='" +
+ onClickEvt +
+ "' style='margin: 0'>" +
+ "<button id='one' style='margin: 0; margin-left: 16px; margin-top: 14px; width: 80px; height: 40px;'>Test</button>" +
+ "<div onmousedown='event.preventDefault()' style='margin: 0; width: 80px; height: 60px;'>Other</div>" +
+ "<span id='out'></span></body>";
+ let tab = await BrowserTestUtils.openNewForegroundTab(
+ gBrowser,
+ "data:text/html," + url
+ );
+
+ let browser = tab.linkedBrowser;
+ await BrowserTestUtils.synthesizeMouseAtCenter("#one", {}, browser);
+ let details = await getLastEventDetails(browser);
+
+ is(details, "button,56,34", "synthesizeMouseAtCenter");
+
+ await BrowserTestUtils.synthesizeMouse("#one", 4, 9, {}, browser);
+ details = await getLastEventDetails(browser);
+ is(details, "button,20,23", "synthesizeMouse");
+
+ await BrowserTestUtils.synthesizeMouseAtPoint(15, 6, {}, browser);
+ details = await getLastEventDetails(browser);
+ is(details, "body,15,6", "synthesizeMouseAtPoint on body");
+
+ await BrowserTestUtils.synthesizeMouseAtPoint(
+ 20,
+ 22,
+ {},
+ browser.browsingContext
+ );
+ details = await getLastEventDetails(browser);
+ is(details, "button,20,22", "synthesizeMouseAtPoint on button");
+
+ await BrowserTestUtils.synthesizeMouseAtCenter("body > div", {}, browser);
+ details = await getLastEventDetails(browser);
+ is(details, "div,40,84", "synthesizeMouseAtCenter with complex selector");
+
+ let cancelled = await BrowserTestUtils.synthesizeMouseAtCenter(
+ "body > div",
+ { type: "mousedown" },
+ browser
+ );
+ details = await getLastEventDetails(browser);
+ is(
+ details,
+ "div,40,84",
+ "synthesizeMouseAtCenter mousedown with complex selector"
+ );
+ ok(
+ cancelled,
+ "synthesizeMouseAtCenter mousedown with complex selector not cancelled"
+ );
+
+ cancelled = await BrowserTestUtils.synthesizeMouseAtCenter(
+ "body > div",
+ { type: "mouseup" },
+ browser
+ );
+ details = await getLastEventDetails(browser);
+ is(
+ details,
+ "div,40,84",
+ "synthesizeMouseAtCenter mouseup with complex selector"
+ );
+ ok(
+ !cancelled,
+ "synthesizeMouseAtCenter mouseup with complex selector cancelled"
+ );
+
+ gBrowser.removeTab(tab);
+});
+
+add_task(async function testSynthesizeMouseAtPointsButtons() {
+ let onMouseEvt =
+ 'document.getElementById("mouselog").textContent += "/" + [event.type,event.clientX,event.clientY,event.button,event.buttons].join(",");';
+
+ let getLastMouseEventDetails = browser => {
+ return SpecialPowers.spawn(browser, [], async () => {
+ let log = content.document.getElementById("mouselog").textContent;
+ content.document.getElementById("mouselog").textContent = "";
+ return log;
+ });
+ };
+
+ const url =
+ "<body" +
+ "' onmousedown='" +
+ onMouseEvt +
+ "' onmousemove='" +
+ onMouseEvt +
+ "' onmouseup='" +
+ onMouseEvt +
+ "' style='margin: 0'>" +
+ "<div style='margin: 0; width: 80px; height: 60px;'>Mouse area</div>" +
+ "<span id='mouselog'></span>" +
+ "</body>";
+ let tab = await BrowserTestUtils.openNewForegroundTab(
+ gBrowser,
+ "data:text/html," + url
+ );
+
+ let browser = tab.linkedBrowser;
+ let details;
+
+ await BrowserTestUtils.synthesizeMouseAtPoint(
+ 21,
+ 22,
+ {
+ type: "mousemove",
+ },
+ browser.browsingContext
+ );
+ details = await getLastMouseEventDetails(browser);
+ is(details, "/mousemove,21,22,0,0", "synthesizeMouseAtPoint mousemove");
+
+ await BrowserTestUtils.synthesizeMouseAtPoint(
+ 22,
+ 23,
+ {},
+ browser.browsingContext
+ );
+ details = await getLastMouseEventDetails(browser);
+ is(
+ details,
+ "/mousedown,22,23,0,1/mouseup,22,23,0,0",
+ "synthesizeMouseAtPoint default action includes buttons on mousedown only"
+ );
+
+ await BrowserTestUtils.synthesizeMouseAtPoint(
+ 20,
+ 22,
+ {
+ type: "mousedown",
+ },
+ browser.browsingContext
+ );
+ details = await getLastMouseEventDetails(browser);
+ is(
+ details,
+ "/mousedown,20,22,0,1",
+ "synthesizeMouseAtPoint mousedown includes buttons"
+ );
+
+ await BrowserTestUtils.synthesizeMouseAtPoint(
+ 21,
+ 20,
+ {
+ type: "mouseup",
+ },
+ browser.browsingContext
+ );
+ details = await getLastMouseEventDetails(browser);
+ is(details, "/mouseup,21,20,0,0", "synthesizeMouseAtPoint mouseup");
+
+ await BrowserTestUtils.synthesizeMouseAtPoint(
+ 20,
+ 22,
+ {
+ type: "mousedown",
+ button: 2,
+ },
+ browser.browsingContext
+ );
+ details = await getLastMouseEventDetails(browser);
+ is(
+ details,
+ "/mousedown,20,22,2,2",
+
+ "synthesizeMouseAtPoint mousedown respects specified button 2"
+ );
+
+ await BrowserTestUtils.synthesizeMouseAtPoint(
+ 21,
+ 20,
+ {
+ type: "mouseup",
+ button: 2,
+ },
+ browser.browsingContext
+ );
+ details = await getLastMouseEventDetails(browser);
+ is(
+ details,
+ "/mouseup,21,20,2,0",
+ "synthesizeMouseAtPoint mouseup with button 2"
+ );
+
+ gBrowser.removeTab(tab);
+});
+
+add_task(async function mouse_in_iframe() {
+ let onClickEvt = "document.body.lastChild.textContent = event.target.id;";
+ const url = `<iframe style='margin: 30px;' src='data:text/html,<body onclick="${onClickEvt}">
+ <p><button>One</button></p><p><button id="two">Two</button></p><p id="out"></p></body>'></iframe>
+ <iframe style='margin: 10px;' src='data:text/html,<body onclick="${onClickEvt}">
+ <p><button>Three</button></p><p><button id="four">Four</button></p><p id="out"></p></body>'></iframe>`;
+ let tab = await BrowserTestUtils.openNewForegroundTab(
+ gBrowser,
+ "data:text/html," + url
+ );
+
+ let browser = tab.linkedBrowser;
+
+ await BrowserTestUtils.synthesizeMouse(
+ "#two",
+ 5,
+ 10,
+ {},
+ browser.browsingContext.children[0]
+ );
+
+ let details = await getLastEventDetails(browser.browsingContext.children[0]);
+ is(details, "two", "synthesizeMouse");
+
+ await BrowserTestUtils.synthesizeMouse(
+ "#four",
+ 5,
+ 10,
+ {},
+ browser.browsingContext.children[1]
+ );
+ details = await getLastEventDetails(browser.browsingContext.children[1]);
+ is(details, "four", "synthesizeMouse");
+
+ gBrowser.removeTab(tab);
+});
+
+add_task(async function () {
+ await BrowserTestUtils.registerAboutPage(
+ registerCleanupFunction,
+ "about-pages-are-cool",
+ getRootDirectory(gTestPath) + "dummy.html",
+ 0
+ );
+ let tab = await BrowserTestUtils.openNewForegroundTab(
+ gBrowser,
+ "about:about-pages-are-cool",
+ true
+ );
+ ok(tab, "Successfully created an about: page and loaded it.");
+ BrowserTestUtils.removeTab(tab);
+ try {
+ await BrowserTestUtils.unregisterAboutPage("about-pages-are-cool");
+ ok(true, "Successfully unregistered the about page.");
+ } catch (ex) {
+ ok(false, "Should not throw unregistering a known about: page");
+ }
+ await BrowserTestUtils.unregisterAboutPage("random-other-about-page").then(
+ () => {
+ ok(
+ false,
+ "Should not have succeeded unregistering an unknown about: page."
+ );
+ },
+ () => {
+ ok(
+ true,
+ "Should have returned a rejected promise trying to unregister an unknown about page"
+ );
+ }
+ );
+});
+
+add_task(async function testWaitForEvent() {
+ // A promise returned by BrowserTestUtils.waitForEvent should not be resolved
+ // in the same event tick as the event listener is called.
+ let eventListenerCalled = false;
+ let waitForEventResolved = false;
+ // Use capturing phase to make sure the event listener added by
+ // BrowserTestUtils.waitForEvent is called before the normal event listener
+ // below.
+ let eventPromise = BrowserTestUtils.waitForEvent(
+ gBrowser,
+ "dummyevent",
+ true
+ );
+ eventPromise.then(() => {
+ waitForEventResolved = true;
+ });
+ // Add normal event listener that is called after the event listener added by
+ // BrowserTestUtils.waitForEvent.
+ gBrowser.addEventListener(
+ "dummyevent",
+ () => {
+ eventListenerCalled = true;
+ is(
+ waitForEventResolved,
+ false,
+ "BrowserTestUtils.waitForEvent promise resolution handler shouldn't be called at this point."
+ );
+ },
+ { once: true }
+ );
+
+ var event = new CustomEvent("dummyevent");
+ gBrowser.dispatchEvent(event);
+
+ await eventPromise;
+
+ is(eventListenerCalled, true, "dummyevent listener should be called");
+});
diff --git a/testing/mochitest/tests/browser/browser_add_task.js b/testing/mochitest/tests/browser/browser_add_task.js
new file mode 100644
index 0000000000..2466112834
--- /dev/null
+++ b/testing/mochitest/tests/browser/browser_add_task.js
@@ -0,0 +1,31 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+var test1Complete = false;
+var test2Complete = false;
+
+function executeWithTimeout() {
+ return new Promise(resolve =>
+ executeSoon(function () {
+ ok(true, "we get here after a timeout");
+ resolve();
+ })
+ );
+}
+
+add_task(async function asyncTest_no1() {
+ await executeWithTimeout();
+ test1Complete = true;
+});
+
+add_task(async function asyncTest_no2() {
+ await executeWithTimeout();
+ test2Complete = true;
+});
+
+add_task(function () {
+ ok(test1Complete, "We have been through test 1");
+ ok(test2Complete, "We have been through test 2");
+});
diff --git a/testing/mochitest/tests/browser/browser_async.js b/testing/mochitest/tests/browser/browser_async.js
new file mode 100644
index 0000000000..d07cb21740
--- /dev/null
+++ b/testing/mochitest/tests/browser/browser_async.js
@@ -0,0 +1,9 @@
+function test() {
+ waitForExplicitFinish();
+ function done() {
+ ok(true, "timeout ran");
+ finish();
+ }
+ // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
+ setTimeout(done, 500);
+}
diff --git a/testing/mochitest/tests/browser/browser_browserLoaded_content_loaded.js b/testing/mochitest/tests/browser/browser_browserLoaded_content_loaded.js
new file mode 100644
index 0000000000..fa29e03d23
--- /dev/null
+++ b/testing/mochitest/tests/browser/browser_browserLoaded_content_loaded.js
@@ -0,0 +1,53 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
+
+function isDOMLoaded(browser) {
+ return SpecialPowers.spawn(browser, [], async function () {
+ Assert.equal(
+ content.document.readyState,
+ "complete",
+ "Browser should be loaded."
+ );
+ });
+}
+
+// It checks if calling BrowserTestUtils.browserLoaded() yields
+// browser object.
+add_task(async function () {
+ let tab = BrowserTestUtils.addTab(gBrowser, "http://example.com");
+ let browser = tab.linkedBrowser;
+ await BrowserTestUtils.browserLoaded(browser);
+ await isDOMLoaded(browser);
+ gBrowser.removeTab(tab);
+});
+
+// It checks that BrowserTestUtils.browserLoaded() works well with
+// promise.all().
+add_task(async function () {
+ let tabURLs = [
+ `http://example.org`,
+ `http://mochi.test:8888`,
+ `http://test:80`,
+ ];
+ // Add tabs, get the respective browsers
+ let browsers = tabURLs.map(
+ u => BrowserTestUtils.addTab(gBrowser, u).linkedBrowser
+ );
+
+ // wait for promises to settle
+ await Promise.all(
+ (function* () {
+ for (let b of browsers) {
+ yield BrowserTestUtils.browserLoaded(b);
+ }
+ })()
+ );
+ for (const browser of browsers) {
+ await isDOMLoaded(browser);
+ }
+ // cleanup
+ browsers
+ .map(browser => gBrowser.getTabForBrowser(browser))
+ .forEach(tab => gBrowser.removeTab(tab));
+});
diff --git a/testing/mochitest/tests/browser/browser_document_builder_sjs.js b/testing/mochitest/tests/browser/browser_document_builder_sjs.js
new file mode 100644
index 0000000000..4b653a792d
--- /dev/null
+++ b/testing/mochitest/tests/browser/browser_document_builder_sjs.js
@@ -0,0 +1,74 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
+
+// Checks that document-builder.sjs works as expected
+add_task(async function assertHtmlParam() {
+ const html = "<main><h1>I'm built different</h1></main>";
+ const delay = 5000;
+
+ const params = new URLSearchParams({
+ delay,
+ html,
+ });
+ params.append("headers", "x-header-1:a");
+ params.append("headers", "x-header-2:b");
+
+ const startTime = performance.now();
+ const request = new Request(
+ `https://example.com/document-builder.sjs?${params}`
+ );
+ info("Do a fetch request to document-builder.sjs");
+ const response = await fetch(request);
+ const duration = performance.now() - startTime;
+
+ is(response.status, 200, "Response is a 200");
+ ok(
+ duration > delay,
+ `The delay parameter works as expected (took ${duration}ms)`
+ );
+
+ const responseText = await response.text();
+ is(responseText, html, "The response has the expected content");
+
+ is(
+ response.headers.get("content-type"),
+ "text/html",
+ "response has the expected content-type"
+ );
+ is(
+ response.headers.get("x-header-1"),
+ "a",
+ "first header was set as expected"
+ );
+ is(
+ response.headers.get("x-header-2"),
+ "b",
+ "second header was set as expected"
+ );
+});
+
+add_task(async function assertFileParam() {
+ const file = `browser/testing/mochitest/tests/browser/dummy.html`;
+ const request = new Request(
+ `https://example.com/document-builder.sjs?file=${file}`
+ );
+
+ info("Do a fetch request to document-builder.sjs with a `file` parameter");
+ const response = await fetch(request);
+ is(response.status, 200, "Response is a 200");
+ is(
+ response.headers.get("content-type"),
+ "text/html",
+ "response has the expected content-type"
+ );
+
+ const responseText = await response.text();
+ const parser = new DOMParser();
+ const doc = parser.parseFromString(responseText, "text/html");
+ is(
+ doc.body.innerHTML.trim(),
+ "This is a dummy page",
+ "The response has the file content"
+ );
+});
diff --git a/testing/mochitest/tests/browser/browser_fail.js b/testing/mochitest/tests/browser/browser_fail.js
new file mode 100644
index 0000000000..f6b439fb0d
--- /dev/null
+++ b/testing/mochitest/tests/browser/browser_fail.js
@@ -0,0 +1,10 @@
+setExpectedFailuresForSelfTest(6);
+
+function test() {
+ ok(false, "fail ok");
+ is(true, false, "fail is");
+ isnot(true, true, "fail isnot");
+ todo(true, "fail todo");
+ todo_is(true, true, "fail todo_is");
+ todo_isnot(true, false, "fail todo_isnot");
+}
diff --git a/testing/mochitest/tests/browser/browser_fail_add_task.js b/testing/mochitest/tests/browser/browser_fail_add_task.js
new file mode 100644
index 0000000000..aeb1129943
--- /dev/null
+++ b/testing/mochitest/tests/browser/browser_fail_add_task.js
@@ -0,0 +1,27 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+setExpectedFailuresForSelfTest(4);
+
+function rejectOnNextTick(error) {
+ return new Promise((resolve, reject) => executeSoon(() => reject(error)));
+}
+
+add_task(async function failWithoutError() {
+ await rejectOnNextTick(undefined);
+});
+
+add_task(async function failWithString() {
+ await rejectOnNextTick("This is a string");
+});
+
+add_task(async function failWithInt() {
+ await rejectOnNextTick(42);
+});
+
+// This one should display a stack trace
+add_task(async function failWithError() {
+ await rejectOnNextTick(new Error("This is an error"));
+});
diff --git a/testing/mochitest/tests/browser/browser_fail_add_task_uncaught_rejection.js b/testing/mochitest/tests/browser/browser_fail_add_task_uncaught_rejection.js
new file mode 100644
index 0000000000..8a42740acb
--- /dev/null
+++ b/testing/mochitest/tests/browser/browser_fail_add_task_uncaught_rejection.js
@@ -0,0 +1,29 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+setExpectedFailuresForSelfTest(4);
+
+async function rejectOnNextTick(error) {
+ await Promise.resolve();
+
+ Promise.reject(error);
+}
+
+add_task(async function failWithoutError() {
+ await rejectOnNextTick(undefined);
+});
+
+add_task(async function failWithString() {
+ await rejectOnNextTick("This is a string");
+});
+
+add_task(async function failWithInt() {
+ await rejectOnNextTick(42);
+});
+
+// This one should display a stack trace
+add_task(async function failWithError() {
+ await rejectOnNextTick(new Error("This is an error"));
+});
diff --git a/testing/mochitest/tests/browser/browser_fail_async.js b/testing/mochitest/tests/browser/browser_fail_async.js
new file mode 100644
index 0000000000..6f284bf2aa
--- /dev/null
+++ b/testing/mochitest/tests/browser/browser_fail_async.js
@@ -0,0 +1,9 @@
+setExpectedFailuresForSelfTest(1);
+
+function test() {
+ waitForExplicitFinish();
+ executeSoon(() => {
+ ok(false, "fail");
+ finish();
+ });
+}
diff --git a/testing/mochitest/tests/browser/browser_fail_if.js b/testing/mochitest/tests/browser/browser_fail_if.js
new file mode 100644
index 0000000000..dad56e7dac
--- /dev/null
+++ b/testing/mochitest/tests/browser/browser_fail_if.js
@@ -0,0 +1,4 @@
+// We expect this test to fail because it is marked as fail-if in the manifest.
+function test() {
+ ok(false, "fail ok");
+}
diff --git a/testing/mochitest/tests/browser/browser_fail_throw.js b/testing/mochitest/tests/browser/browser_fail_throw.js
new file mode 100644
index 0000000000..585b47561d
--- /dev/null
+++ b/testing/mochitest/tests/browser/browser_fail_throw.js
@@ -0,0 +1,5 @@
+setExpectedFailuresForSelfTest(1);
+
+function test() {
+ throw new Error("thrown exception");
+}
diff --git a/testing/mochitest/tests/browser/browser_fail_timeout.js b/testing/mochitest/tests/browser/browser_fail_timeout.js
new file mode 100644
index 0000000000..44030a00f0
--- /dev/null
+++ b/testing/mochitest/tests/browser/browser_fail_timeout.js
@@ -0,0 +1,9 @@
+function test() {
+ function end() {
+ ok(false, "should have timed out");
+ finish();
+ }
+ waitForExplicitFinish();
+ // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
+ setTimeout(end, 40000);
+}
diff --git a/testing/mochitest/tests/browser/browser_fail_uncaught_rejection.js b/testing/mochitest/tests/browser/browser_fail_uncaught_rejection.js
new file mode 100644
index 0000000000..86d3e77b7f
--- /dev/null
+++ b/testing/mochitest/tests/browser/browser_fail_uncaught_rejection.js
@@ -0,0 +1,14 @@
+setExpectedFailuresForSelfTest(2);
+
+function test() {
+ Promise.reject(new Error("Promise rejection."));
+ (async () => {
+ throw new Error("Synchronous rejection from async function.");
+ })();
+
+ // The following rejections are caught, so they won't result in failures.
+ Promise.reject(new Error("Promise rejection.")).catch(() => {});
+ (async () => {
+ throw new Error("Synchronous rejection from async function.");
+ })().catch(() => {});
+}
diff --git a/testing/mochitest/tests/browser/browser_fail_uncaught_rejection_expected.js b/testing/mochitest/tests/browser/browser_fail_uncaught_rejection_expected.js
new file mode 100644
index 0000000000..6c30d4eb3d
--- /dev/null
+++ b/testing/mochitest/tests/browser/browser_fail_uncaught_rejection_expected.js
@@ -0,0 +1,12 @@
+setExpectedFailuresForSelfTest(1);
+
+// The test will fail because there is only one of two expected rejections.
+const { PromiseTestUtils } = ChromeUtils.importESModule(
+ "resource://testing-common/PromiseTestUtils.sys.mjs"
+);
+PromiseTestUtils.expectUncaughtRejection(/Promise rejection./);
+PromiseTestUtils.expectUncaughtRejection(/Promise rejection./);
+
+function test() {
+ Promise.reject(new Error("Promise rejection."));
+}
diff --git a/testing/mochitest/tests/browser/browser_fail_uncaught_rejection_expected_multi.js b/testing/mochitest/tests/browser/browser_fail_uncaught_rejection_expected_multi.js
new file mode 100644
index 0000000000..cea5a870aa
--- /dev/null
+++ b/testing/mochitest/tests/browser/browser_fail_uncaught_rejection_expected_multi.js
@@ -0,0 +1,11 @@
+setExpectedFailuresForSelfTest(1);
+
+// The test will fail because an expected uncaught rejection is actually caught.
+const { PromiseTestUtils } = ChromeUtils.importESModule(
+ "resource://testing-common/PromiseTestUtils.sys.mjs"
+);
+PromiseTestUtils.expectUncaughtRejection(/Promise rejection./);
+
+function test() {
+ Promise.reject(new Error("Promise rejection.")).catch(() => {});
+}
diff --git a/testing/mochitest/tests/browser/browser_fail_unexpectedTimeout.js b/testing/mochitest/tests/browser/browser_fail_unexpectedTimeout.js
new file mode 100644
index 0000000000..d0aef231bd
--- /dev/null
+++ b/testing/mochitest/tests/browser/browser_fail_unexpectedTimeout.js
@@ -0,0 +1,14 @@
+function test() {
+ function message() {
+ info("This should delay timeout");
+ }
+ function end() {
+ ok(true, "Should have not timed out, but notified long running test");
+ finish();
+ }
+ waitForExplicitFinish();
+ // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
+ setTimeout(message, 20000);
+ // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
+ setTimeout(end, 40000);
+}
diff --git a/testing/mochitest/tests/browser/browser_getTestFile.js b/testing/mochitest/tests/browser/browser_getTestFile.js
new file mode 100644
index 0000000000..154bf716da
--- /dev/null
+++ b/testing/mochitest/tests/browser/browser_getTestFile.js
@@ -0,0 +1,37 @@
+add_task(async function test() {
+ SimpleTest.doesThrow(function () {
+ getTestFilePath("/browser_getTestFile.js");
+ }, "getTestFilePath rejects absolute paths");
+
+ await Promise.all([
+ IOUtils.exists(getTestFilePath("browser_getTestFile.js")).then(function (
+ exists
+ ) {
+ ok(exists, "getTestFilePath consider the path as being relative");
+ }),
+
+ IOUtils.exists(getTestFilePath("./browser_getTestFile.js")).then(function (
+ exists
+ ) {
+ ok(exists, "getTestFilePath also accepts explicit relative path");
+ }),
+
+ IOUtils.exists(getTestFilePath("./browser_getTestFileTypo.xul")).then(
+ function (exists) {
+ ok(!exists, "getTestFilePath do not throw if the file doesn't exists");
+ }
+ ),
+
+ IOUtils.readUTF8(getTestFilePath("test-dir/test-file")).then(function (
+ content
+ ) {
+ is(content, "foo\n", "getTestFilePath can reach sub-folder files 1/2");
+ }),
+
+ IOUtils.readUTF8(getTestFilePath("./test-dir/test-file")).then(function (
+ content
+ ) {
+ is(content, "foo\n", "getTestFilePath can reach sub-folder files 2/2");
+ }),
+ ]);
+});
diff --git a/testing/mochitest/tests/browser/browser_head.js b/testing/mochitest/tests/browser/browser_head.js
new file mode 100644
index 0000000000..3e3893f2d4
--- /dev/null
+++ b/testing/mochitest/tests/browser/browser_head.js
@@ -0,0 +1,16 @@
+var testVar;
+
+registerCleanupFunction(function () {
+ ok(true, "I'm a cleanup function in test file");
+ is(
+ this.testVar,
+ "I'm a var in test file",
+ "Test cleanup function scope is correct"
+ );
+});
+
+function test() {
+ is(headVar, "I'm a var in head file", "Head variables are set");
+ ok(headMethod(), "Head methods are imported");
+ testVar = "I'm a var in test file";
+}
diff --git a/testing/mochitest/tests/browser/browser_parameters.js b/testing/mochitest/tests/browser/browser_parameters.js
new file mode 100644
index 0000000000..813cd662ba
--- /dev/null
+++ b/testing/mochitest/tests/browser/browser_parameters.js
@@ -0,0 +1,3 @@
+function test() {
+ ok(SimpleTest.harnessParameters, "Should have parameters");
+}
diff --git a/testing/mochitest/tests/browser/browser_pass.js b/testing/mochitest/tests/browser/browser_pass.js
new file mode 100644
index 0000000000..e512ff374a
--- /dev/null
+++ b/testing/mochitest/tests/browser/browser_pass.js
@@ -0,0 +1,13 @@
+function test() {
+ SimpleTest.requestCompleteLog();
+ ok(true, "pass ok");
+ is(true, true, "pass is");
+ isnot(false, true, "pass isnot");
+ todo(false, "pass todo");
+ todo_is(false, true, "pass todo_is");
+ todo_isnot(true, true, "pass todo_isnot");
+ info("info message");
+
+ var func = is;
+ func(true, true, "pass indirect is");
+}
diff --git a/testing/mochitest/tests/browser/browser_privileges.js b/testing/mochitest/tests/browser/browser_privileges.js
new file mode 100644
index 0000000000..042a928b9c
--- /dev/null
+++ b/testing/mochitest/tests/browser/browser_privileges.js
@@ -0,0 +1,17 @@
+function test() {
+ // simple test to confirm we have chrome privileges
+ let hasPrivileges = true;
+
+ // this will throw an exception if we are not running with privileges
+ try {
+ // eslint-disable-next-line no-unused-vars, mozilla/use-services
+ var prefs = Cc["@mozilla.org/preferences-service;1"].getService(
+ Ci.nsIPrefBranch
+ );
+ } catch (e) {
+ hasPrivileges = false;
+ }
+
+ // if we get here, we must have chrome privileges
+ ok(hasPrivileges, "running with chrome privileges");
+}
diff --git a/testing/mochitest/tests/browser/browser_requestLongerTimeout.js b/testing/mochitest/tests/browser/browser_requestLongerTimeout.js
new file mode 100644
index 0000000000..4107e11fd0
--- /dev/null
+++ b/testing/mochitest/tests/browser/browser_requestLongerTimeout.js
@@ -0,0 +1,10 @@
+function test() {
+ requestLongerTimeout(2);
+ function end() {
+ ok(true, "should not time out");
+ finish();
+ }
+ waitForExplicitFinish();
+ // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
+ setTimeout(end, 40000);
+}
diff --git a/testing/mochitest/tests/browser/browser_sanityException.js b/testing/mochitest/tests/browser/browser_sanityException.js
new file mode 100644
index 0000000000..2678dd80ad
--- /dev/null
+++ b/testing/mochitest/tests/browser/browser_sanityException.js
@@ -0,0 +1,5 @@
+function test() {
+ ok(true, "ok called");
+ expectUncaughtException();
+ throw new Error("this is a deliberately thrown exception");
+}
diff --git a/testing/mochitest/tests/browser/browser_sanityException2.js b/testing/mochitest/tests/browser/browser_sanityException2.js
new file mode 100644
index 0000000000..4512ed982b
--- /dev/null
+++ b/testing/mochitest/tests/browser/browser_sanityException2.js
@@ -0,0 +1,11 @@
+function test() {
+ waitForExplicitFinish();
+ ok(true, "ok called");
+ executeSoon(function () {
+ expectUncaughtException();
+ throw new Error("this is a deliberately thrown exception");
+ });
+ executeSoon(function () {
+ finish();
+ });
+}
diff --git a/testing/mochitest/tests/browser/browser_setup_runs_first.js b/testing/mochitest/tests/browser/browser_setup_runs_first.js
new file mode 100644
index 0000000000..6b9ce145da
--- /dev/null
+++ b/testing/mochitest/tests/browser/browser_setup_runs_first.js
@@ -0,0 +1,14 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+let someVar = 1;
+
+add_task(() => {
+ is(someVar, 2, "Should get updated by setup which runs first.");
+});
+
+add_setup(() => {
+ someVar = 2;
+});
diff --git a/testing/mochitest/tests/browser/browser_setup_runs_for_only_tests.js b/testing/mochitest/tests/browser/browser_setup_runs_for_only_tests.js
new file mode 100644
index 0000000000..d1b811b2d1
--- /dev/null
+++ b/testing/mochitest/tests/browser/browser_setup_runs_for_only_tests.js
@@ -0,0 +1,15 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+let someVar = 1;
+
+add_setup(() => {
+ someVar = 2;
+});
+
+/* eslint-disable mozilla/reject-addtask-only */
+add_task(() => {
+ is(someVar, 2, "Setup should have run, even though this is the only test.");
+}).only();
diff --git a/testing/mochitest/tests/browser/browser_tasks_skip.js b/testing/mochitest/tests/browser/browser_tasks_skip.js
new file mode 100644
index 0000000000..99f3e8d2c2
--- /dev/null
+++ b/testing/mochitest/tests/browser/browser_tasks_skip.js
@@ -0,0 +1,21 @@
+"use strict";
+
+add_task(async function skipMeNot1() {
+ Assert.ok(true, "Well well well.");
+});
+
+add_task(async function skipMe1() {
+ Assert.ok(false, "Not skipped after all.");
+}).skip();
+
+add_task(async function skipMeNot2() {
+ Assert.ok(true, "Well well well.");
+});
+
+add_task(async function skipMeNot3() {
+ Assert.ok(true, "Well well well.");
+});
+
+add_task(async function skipMe2() {
+ Assert.ok(false, "Not skipped after all.");
+}).skip();
diff --git a/testing/mochitest/tests/browser/browser_tasks_skipall.js b/testing/mochitest/tests/browser/browser_tasks_skipall.js
new file mode 100644
index 0000000000..13290e58ba
--- /dev/null
+++ b/testing/mochitest/tests/browser/browser_tasks_skipall.js
@@ -0,0 +1,23 @@
+"use strict";
+
+/* eslint-disable mozilla/reject-addtask-only */
+
+add_task(async function skipMe1() {
+ Assert.ok(false, "Not skipped after all.");
+});
+
+add_task(async function skipMe2() {
+ Assert.ok(false, "Not skipped after all.");
+}).skip();
+
+add_task(async function skipMe3() {
+ Assert.ok(false, "Not skipped after all.");
+}).only();
+
+add_task(async function skipMeNot() {
+ Assert.ok(true, "Well well well.");
+}).only();
+
+add_task(async function skipMe4() {
+ Assert.ok(false, "Not skipped after all.");
+});
diff --git a/testing/mochitest/tests/browser/browser_uncaught_rejection_expected.js b/testing/mochitest/tests/browser/browser_uncaught_rejection_expected.js
new file mode 100644
index 0000000000..2ee9f23d79
--- /dev/null
+++ b/testing/mochitest/tests/browser/browser_uncaught_rejection_expected.js
@@ -0,0 +1,12 @@
+const { PromiseTestUtils } = ChromeUtils.importESModule(
+ "resource://testing-common/PromiseTestUtils.sys.mjs"
+);
+PromiseTestUtils.allowMatchingRejectionsGlobally(/Allowed rejection./);
+PromiseTestUtils.expectUncaughtRejection(/Promise rejection./);
+PromiseTestUtils.expectUncaughtRejection(/Promise rejection./);
+
+function test() {
+ Promise.reject(new Error("Promise rejection."));
+ Promise.reject(new Error("Promise rejection."));
+ Promise.reject(new Error("Allowed rejection."));
+}
diff --git a/testing/mochitest/tests/browser/browser_waitForFocus.js b/testing/mochitest/tests/browser/browser_waitForFocus.js
new file mode 100644
index 0000000000..b41b07f423
--- /dev/null
+++ b/testing/mochitest/tests/browser/browser_waitForFocus.js
@@ -0,0 +1,160 @@
+const gBaseURL = "https://example.com/browser/testing/mochitest/tests/browser/";
+
+function promiseTabLoadEvent(tab, url) {
+ let promise = BrowserTestUtils.browserLoaded(tab.linkedBrowser, false, url);
+ if (url) {
+ tab.linkedBrowser.loadURI(Services.io.newURI(url));
+ }
+ return promise;
+}
+
+// Load a new blank tab
+add_task(async function () {
+ await BrowserTestUtils.openNewForegroundTab(gBrowser);
+
+ gURLBar.focus();
+
+ let browser = gBrowser.selectedBrowser;
+ await SimpleTest.promiseFocus(browser, true);
+
+ is(
+ document.activeElement,
+ browser,
+ "Browser is focused when about:blank is loaded"
+ );
+
+ gBrowser.removeCurrentTab();
+ gURLBar.focus();
+});
+
+add_task(async function () {
+ await BrowserTestUtils.openNewForegroundTab(gBrowser);
+
+ gURLBar.focus();
+
+ let browser = gBrowser.selectedBrowser;
+ // If we're running in e10s, we don't have access to the content
+ // window, so only test window arguments in non-e10s mode.
+ if (browser.contentWindow) {
+ await SimpleTest.promiseFocus(browser.contentWindow, true);
+
+ is(
+ document.activeElement,
+ browser,
+ "Browser is focused when about:blank is loaded"
+ );
+ }
+
+ gBrowser.removeCurrentTab();
+ gURLBar.focus();
+});
+
+// Load a tab with a subframe inside it and wait until the subframe is focused
+add_task(async function () {
+ let tab = BrowserTestUtils.addTab(gBrowser);
+ gBrowser.selectedTab = tab;
+
+ let browser = gBrowser.getBrowserForTab(tab);
+ // If we're running in e10s, we don't have access to the content
+ // window, so only test <iframe> arguments in non-e10s mode.
+ if (browser.contentWindow) {
+ await promiseTabLoadEvent(tab, gBaseURL + "waitForFocusPage.html");
+
+ await SimpleTest.promiseFocus(browser.contentWindow);
+
+ is(
+ document.activeElement,
+ browser,
+ "Browser is focused when page is loaded"
+ );
+
+ await SimpleTest.promiseFocus(browser.contentWindow.frames[0]);
+
+ is(
+ browser.contentWindow.document.activeElement.localName,
+ "iframe",
+ "Child iframe is focused"
+ );
+ }
+
+ gBrowser.removeCurrentTab();
+});
+
+// Pass a browser to promiseFocus
+add_task(async function () {
+ await BrowserTestUtils.openNewForegroundTab(
+ gBrowser,
+ gBaseURL + "waitForFocusPage.html"
+ );
+
+ gURLBar.focus();
+
+ await SimpleTest.promiseFocus(gBrowser.selectedBrowser);
+
+ is(
+ document.activeElement,
+ gBrowser.selectedBrowser,
+ "Browser is focused when promiseFocus is passed a browser"
+ );
+
+ gBrowser.removeCurrentTab();
+});
+
+// Tests focusing the sidebar, which is in a parent process subframe
+// and then switching the focus to another window.
+add_task(async function () {
+ await SidebarUI.show("viewBookmarksSidebar");
+
+ gURLBar.focus();
+
+ // Focus the sidebar.
+ await SimpleTest.promiseFocus(SidebarUI.browser);
+ is(
+ document.activeElement,
+ document.getElementById("sidebar"),
+ "sidebar focused"
+ );
+ ok(
+ document.activeElement.contentDocument.hasFocus(),
+ "sidebar document hasFocus"
+ );
+
+ // Focus the sidebar again, which should cause no change.
+ await SimpleTest.promiseFocus(SidebarUI.browser);
+ is(
+ document.activeElement,
+ document.getElementById("sidebar"),
+ "sidebar focused"
+ );
+ ok(
+ document.activeElement.contentDocument.hasFocus(),
+ "sidebar document hasFocus"
+ );
+
+ // Focus another window. The sidebar should no longer be focused.
+ let window2 = await BrowserTestUtils.openNewBrowserWindow();
+ is(
+ document.activeElement,
+ document.getElementById("sidebar"),
+ "sidebar focused after window 2 opened"
+ );
+ ok(
+ !document.activeElement.contentDocument.hasFocus(),
+ "sidebar document hasFocus after window 2 opened"
+ );
+
+ // Focus the first window again and the sidebar should be focused again.
+ await SimpleTest.promiseFocus(window);
+ is(
+ document.activeElement,
+ document.getElementById("sidebar"),
+ "sidebar focused after window1 refocused"
+ );
+ ok(
+ document.activeElement.contentDocument.hasFocus(),
+ "sidebar document hasFocus after window1 refocused"
+ );
+
+ await BrowserTestUtils.closeWindow(window2);
+ await SidebarUI.hide();
+});
diff --git a/testing/mochitest/tests/browser/browser_zz_fail_openwindow.js b/testing/mochitest/tests/browser/browser_zz_fail_openwindow.js
new file mode 100644
index 0000000000..2f7fb04d78
--- /dev/null
+++ b/testing/mochitest/tests/browser/browser_zz_fail_openwindow.js
@@ -0,0 +1,13 @@
+function test() {
+ waitForExplicitFinish();
+ function done() {
+ ok(true, "timeout ran");
+ finish();
+ }
+
+ ok(OpenBrowserWindow(), "opened browser window");
+ // and didn't close it!
+
+ // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
+ setTimeout(done, 10000);
+}
diff --git a/testing/mochitest/tests/browser/dummy.html b/testing/mochitest/tests/browser/dummy.html
new file mode 100644
index 0000000000..7954185285
--- /dev/null
+++ b/testing/mochitest/tests/browser/dummy.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<html>
+ <meta http-equiv="Content-Security-Policy" content="default-src 'none'; object-src 'none'"></meta>
+ <title>This is a dummy page</title>
+ <meta charset="utf-8">
+ <body>This is a dummy page</body>
+</html>
diff --git a/testing/mochitest/tests/browser/head.js b/testing/mochitest/tests/browser/head.js
new file mode 100644
index 0000000000..fdfd097176
--- /dev/null
+++ b/testing/mochitest/tests/browser/head.js
@@ -0,0 +1,16 @@
+var headVar = "I'm a var in head file";
+
+function headMethod() {
+ return true;
+}
+
+ok(true, "I'm a test in head file");
+
+registerCleanupFunction(function () {
+ ok(true, "I'm a cleanup function in head file");
+ is(
+ this.headVar,
+ "I'm a var in head file",
+ "Head cleanup function scope is correct"
+ );
+});
diff --git a/testing/mochitest/tests/browser/test-dir/test-file b/testing/mochitest/tests/browser/test-dir/test-file
new file mode 100644
index 0000000000..257cc5642c
--- /dev/null
+++ b/testing/mochitest/tests/browser/test-dir/test-file
@@ -0,0 +1 @@
+foo
diff --git a/testing/mochitest/tests/browser/waitForFocusPage.html b/testing/mochitest/tests/browser/waitForFocusPage.html
new file mode 100644
index 0000000000..286ad7849c
--- /dev/null
+++ b/testing/mochitest/tests/browser/waitForFocusPage.html
@@ -0,0 +1,4 @@
+<body>
+ <input>
+ <iframe id="f" src="data:text/plain,Test" width=80 height=80></iframe>
+</body>