summaryrefslogtreecommitdiffstats
path: root/toolkit/content/tests/browser/head.js
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/content/tests/browser/head.js')
-rw-r--r--toolkit/content/tests/browser/head.js405
1 files changed, 405 insertions, 0 deletions
diff --git a/toolkit/content/tests/browser/head.js b/toolkit/content/tests/browser/head.js
new file mode 100644
index 0000000000..9684d495e8
--- /dev/null
+++ b/toolkit/content/tests/browser/head.js
@@ -0,0 +1,405 @@
+"use strict";
+
+const { XPCOMUtils } = ChromeUtils.importESModule(
+ "resource://gre/modules/XPCOMUtils.sys.mjs"
+);
+
+/**
+ * Set the findbar value to the given text, start a search for that text, and
+ * return a promise that resolves when the find has completed.
+ *
+ * @param gBrowser tabbrowser to search in the current tab.
+ * @param searchText text to search for.
+ * @param highlightOn true if highlight mode should be enabled before searching.
+ * @returns Promise resolves when find is complete.
+ */
+async function promiseFindFinished(gBrowser, searchText, highlightOn = false) {
+ let findbar = await gBrowser.getFindBar();
+ findbar.startFind(findbar.FIND_NORMAL);
+ let highlightElement = findbar.getElement("highlight");
+ if (highlightElement.checked != highlightOn) {
+ highlightElement.click();
+ }
+ return new Promise(resolve => {
+ executeSoon(() => {
+ findbar._findField.value = searchText;
+
+ let resultListener;
+ // When highlighting is on the finder sends a second "FOUND" message after
+ // the search wraps. This causes timing problems with e10s. waitMore
+ // forces foundOrTimeout wait for the second "FOUND" message before
+ // resolving the promise.
+ let waitMore = highlightOn;
+ let findTimeout = setTimeout(() => foundOrTimedout(null), 5000);
+ let foundOrTimedout = function(aData) {
+ if (aData !== null && waitMore) {
+ waitMore = false;
+ return;
+ }
+ if (aData === null) {
+ info("Result listener not called, timeout reached.");
+ }
+ clearTimeout(findTimeout);
+ findbar.browser?.finder.removeResultListener(resultListener);
+ resolve();
+ };
+
+ resultListener = {
+ onFindResult: foundOrTimedout,
+ onCurrentSelection() {},
+ onMatchesCountResult() {},
+ onHighlightFinished() {},
+ };
+ findbar.browser.finder.addResultListener(resultListener);
+ findbar._find();
+ });
+ });
+}
+
+/**
+ * A wrapper for the findbar's method "close", which is not synchronous
+ * because of animation.
+ */
+function closeFindbarAndWait(findbar) {
+ return new Promise(resolve => {
+ if (findbar.hidden) {
+ resolve();
+ return;
+ }
+ findbar.addEventListener("transitionend", function cont(aEvent) {
+ if (aEvent.propertyName != "visibility") {
+ return;
+ }
+ findbar.removeEventListener("transitionend", cont);
+ resolve();
+ });
+ let close = findbar.getElement("find-closebutton");
+ close.doCommand();
+ });
+}
+
+function pushPrefs(...aPrefs) {
+ return new Promise(resolve => {
+ SpecialPowers.pushPrefEnv({ set: aPrefs }, resolve);
+ });
+}
+
+/**
+ * Used to check whether the audio unblocking icon is in the tab.
+ */
+async function waitForTabBlockEvent(tab, expectBlocked) {
+ if (tab.activeMediaBlocked == expectBlocked) {
+ ok(true, "The tab should " + (expectBlocked ? "" : "not ") + "be blocked");
+ } else {
+ info("Block state doens't match, wait for attributes changes.");
+ await BrowserTestUtils.waitForEvent(
+ tab,
+ "TabAttrModified",
+ false,
+ event => {
+ if (event.detail.changed.includes("activemedia-blocked")) {
+ is(
+ tab.activeMediaBlocked,
+ expectBlocked,
+ "The tab should " + (expectBlocked ? "" : "not ") + "be blocked"
+ );
+ return true;
+ }
+ return false;
+ }
+ );
+ }
+}
+
+/**
+ * Used to check whether the tab has soundplaying attribute.
+ */
+async function waitForTabPlayingEvent(tab, expectPlaying) {
+ if (tab.soundPlaying == expectPlaying) {
+ ok(true, "The tab should " + (expectPlaying ? "" : "not ") + "be playing");
+ } else {
+ info("Playing state doesn't match, wait for attributes changes.");
+ await BrowserTestUtils.waitForEvent(
+ tab,
+ "TabAttrModified",
+ false,
+ event => {
+ if (event.detail.changed.includes("soundplaying")) {
+ is(
+ tab.soundPlaying,
+ expectPlaying,
+ "The tab should " + (expectPlaying ? "" : "not ") + "be playing"
+ );
+ return true;
+ }
+ return false;
+ }
+ );
+ }
+}
+
+function disable_non_test_mouse(disable) {
+ let utils = window.windowUtils;
+ utils.disableNonTestMouseEvents(disable);
+}
+
+function hover_icon(icon, tooltip) {
+ disable_non_test_mouse(true);
+
+ let popupShownPromise = BrowserTestUtils.waitForEvent(tooltip, "popupshown");
+ EventUtils.synthesizeMouse(icon, 1, 1, { type: "mouseover" });
+ EventUtils.synthesizeMouse(icon, 2, 2, { type: "mousemove" });
+ EventUtils.synthesizeMouse(icon, 3, 3, { type: "mousemove" });
+ EventUtils.synthesizeMouse(icon, 4, 4, { type: "mousemove" });
+ return popupShownPromise;
+}
+
+function leave_icon(icon) {
+ EventUtils.synthesizeMouse(icon, 0, 0, { type: "mouseout" });
+ EventUtils.synthesizeMouseAtCenter(document.documentElement, {
+ type: "mousemove",
+ });
+ EventUtils.synthesizeMouseAtCenter(document.documentElement, {
+ type: "mousemove",
+ });
+ EventUtils.synthesizeMouseAtCenter(document.documentElement, {
+ type: "mousemove",
+ });
+
+ disable_non_test_mouse(false);
+}
+
+/**
+ * Helper class for testing datetime input picker widget
+ */
+class DateTimeTestHelper {
+ constructor() {
+ this.panel = gBrowser._getAndMaybeCreateDateTimePickerPanel();
+ this.panel.setAttribute("animate", false);
+ this.tab = null;
+ this.frame = null;
+ }
+
+ /**
+ * Opens a new tab with the URL of the test page, and make sure the picker is
+ * ready for testing.
+ *
+ * @param {String} pageUrl
+ * @param {bool} inFrame true if input is in the first child frame
+ * @param {String} openMethod "click" or "showPicker"
+ */
+ async openPicker(pageUrl, inFrame, openMethod = "click") {
+ this.tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, pageUrl);
+ let bc = gBrowser.selectedBrowser;
+ if (inFrame) {
+ await SpecialPowers.spawn(bc, [], async function() {
+ const iframe = content.document.querySelector("iframe");
+ // Ensure the iframe's position is correct before doing any
+ // other operations
+ iframe.getBoundingClientRect();
+ });
+ bc = bc.browsingContext.children[0];
+ }
+ await SpecialPowers.spawn(bc, [], async function() {
+ // Ensure that screen coordinates are ok.
+ await SpecialPowers.contentTransformsReceived(content);
+ });
+
+ if (openMethod === "click") {
+ await SpecialPowers.spawn(bc, [], () => {
+ const input = content.document.querySelector("input");
+ const shadowRoot = SpecialPowers.wrap(input).openOrClosedShadowRoot;
+ shadowRoot.getElementById("calendar-button").click();
+ });
+ } else if (openMethod === "showPicker") {
+ await SpecialPowers.spawn(bc, [], function() {
+ content.document.notifyUserGestureActivation();
+ content.document.querySelector("input").showPicker();
+ });
+ }
+ this.frame = this.panel.querySelector("#dateTimePopupFrame");
+ await this.waitForPickerReady();
+ }
+
+ promisePickerClosed() {
+ return new Promise(resolve => {
+ this.panel.addEventListener("popuphidden", resolve, { once: true });
+ });
+ }
+
+ promiseChange(selector = "input") {
+ return SpecialPowers.spawn(
+ this.tab.linkedBrowser,
+ [selector],
+ async selector => {
+ let input = content.document.querySelector(selector);
+ await ContentTaskUtils.waitForEvent(input, "change", false, e => {
+ ok(
+ content.window.windowUtils.isHandlingUserInput,
+ "isHandlingUserInput should be true"
+ );
+ return true;
+ });
+ }
+ );
+ }
+
+ async waitForPickerReady() {
+ let readyPromise;
+ let loadPromise = new Promise(resolve => {
+ let listener = () => {
+ if (
+ this.frame.browsingContext.currentURI.spec !=
+ "chrome://global/content/datepicker.xhtml"
+ ) {
+ return;
+ }
+
+ this.frame.removeEventListener("load", listener, { capture: true });
+ // Add the PickerReady event listener directly inside the load event
+ // listener to avoid missing the event.
+ readyPromise = BrowserTestUtils.waitForEvent(
+ this.frame.contentDocument,
+ "PickerReady"
+ );
+ resolve();
+ };
+
+ this.frame.addEventListener("load", listener, { capture: true });
+ });
+
+ await loadPromise;
+ // Wait for picker elements to be ready
+ await readyPromise;
+ }
+
+ /**
+ * Find an element on the picker.
+ *
+ * @param {String} selector
+ * @return {DOMElement}
+ */
+ getElement(selector) {
+ return this.frame.contentDocument.querySelector(selector);
+ }
+
+ /**
+ * Find the children of an element on the picker.
+ *
+ * @param {String} selector
+ * @return {Array<DOMElement>}
+ */
+ getChildren(selector) {
+ return Array.from(this.getElement(selector).children);
+ }
+
+ /**
+ * Click on an element
+ *
+ * @param {DOMElement} element
+ */
+ click(element) {
+ EventUtils.synthesizeMouseAtCenter(element, {}, this.frame.contentWindow);
+ }
+
+ /**
+ * Close the panel and the tab
+ */
+ async tearDown() {
+ if (this.panel.state != "closed") {
+ let pickerClosePromise = this.promisePickerClosed();
+ this.panel.hidePopup();
+ await pickerClosePromise;
+ }
+ BrowserTestUtils.removeTab(this.tab);
+ this.tab = null;
+ }
+
+ /**
+ * Clean up after tests. Remove the frame to prevent leak.
+ */
+ cleanup() {
+ this.frame.remove();
+ this.frame = null;
+ this.panel.removeAttribute("animate");
+ this.panel = null;
+ }
+}
+
+/**
+ * Used to listen events if you just need it once
+ */
+function once(target, name) {
+ var p = new Promise(function(resolve, reject) {
+ target.addEventListener(
+ name,
+ function() {
+ resolve();
+ },
+ { once: true }
+ );
+ });
+ return p;
+}
+
+/**
+ * check if current wakelock is equal to expected state, if not, then wait until
+ * the wakelock changes its state to expected state.
+ * @param needLock
+ * the wakolock should be locked or not
+ * @param isForegroundLock
+ * when the lock is on, the wakelock should be in the foreground or not
+ */
+async function waitForExpectedWakeLockState(
+ topic,
+ { needLock, isForegroundLock }
+) {
+ const powerManagerService = Cc["@mozilla.org/power/powermanagerservice;1"];
+ const powerManager = powerManagerService.getService(
+ Ci.nsIPowerManagerService
+ );
+ const wakelockState = powerManager.getWakeLockState(topic);
+ let expectedLockState = "unlocked";
+ if (needLock) {
+ expectedLockState = isForegroundLock
+ ? "locked-foreground"
+ : "locked-background";
+ }
+ if (wakelockState != expectedLockState) {
+ info(`wait until wakelock becomes ${expectedLockState}`);
+ await wakeLockObserved(
+ powerManager,
+ topic,
+ state => state == expectedLockState
+ );
+ }
+ is(
+ powerManager.getWakeLockState(topic),
+ expectedLockState,
+ `the wakelock state for '${topic}' is equal to '${expectedLockState}'`
+ );
+}
+
+function wakeLockObserved(powerManager, observeTopic, checkFn) {
+ return new Promise(resolve => {
+ function wakeLockListener() {}
+ wakeLockListener.prototype = {
+ QueryInterface: ChromeUtils.generateQI(["nsIDOMMozWakeLockListener"]),
+ callback(topic, state) {
+ if (topic == observeTopic && checkFn(state)) {
+ powerManager.removeWakeLockListener(wakeLockListener.prototype);
+ resolve();
+ }
+ },
+ };
+ powerManager.addWakeLockListener(wakeLockListener.prototype);
+ });
+}
+
+function getTestWebBasedURL(fileName, { crossOrigin = false } = {}) {
+ const origin = crossOrigin ? "http://example.org" : "http://example.com";
+ return (
+ getRootDirectory(gTestPath).replace("chrome://mochitests/content", origin) +
+ fileName
+ );
+}