diff options
Diffstat (limited to 'toolkit/content/tests/browser/head.js')
-rw-r--r-- | toolkit/content/tests/browser/head.js | 338 |
1 files changed, 338 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..8973f1a6b4 --- /dev/null +++ b/toolkit/content/tests/browser/head.js @@ -0,0 +1,338 @@ +"use strict"; + +ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm", this); + +/** + * 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 getTestPlugin(pluginName) { + var ph = SpecialPowers.Cc["@mozilla.org/plugin/host;1"].getService( + SpecialPowers.Ci.nsIPluginHost + ); + var tags = ph.getPluginTags(); + var name = pluginName || "Test Plug-in"; + for (var tag of tags) { + if (tag.name == name) { + return tag; + } + } + + ok(false, "Could not find plugin tag with plugin name '" + name + "'"); + return null; +} + +async function setTestPluginEnabledState(newEnabledState, pluginName) { + var oldEnabledState = await SpecialPowers.setTestPluginEnabledState( + newEnabledState, + pluginName + ); + if (!oldEnabledState) { + return; + } + var plugin = getTestPlugin(pluginName); + // Run a nested event loop to wait for the preference change to + // propagate to the child. Yuck! + SpecialPowers.Services.tm.spinEventLoopUntil(() => { + return plugin.enabledState == newEnabledState; + }); + SimpleTest.registerCleanupFunction(function() { + return SpecialPowers.setTestPluginEnabledState(oldEnabledState, pluginName); + }); +} + +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 + */ + async openPicker(pageUrl, inFrame) { + 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 BrowserTestUtils.synthesizeMouseAtCenter("input", {}, bc); + this.frame = this.panel.querySelector("#dateTimePopupFrame"); + await this.waitForPickerReady(); + } + + promisePickerClosed() { + return new Promise(resolve => { + this.panel.addEventListener("popuphidden", resolve, { once: true }); + }); + } + + async waitForPickerReady() { + let readyPromise; + let loadPromise = new Promise(resolve => { + this.frame.addEventListener( + "load", + () => { + // Add the PickerReady event listener directly inside the load event + // listener to avoid missing the event. + readyPromise = BrowserTestUtils.waitForEvent( + this.frame.contentDocument, + "PickerReady" + ); + resolve(); + }, + { capture: true, once: 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.hidden) { + 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); + }); +} |