"use strict"; const TEST_ROOT = getRootDirectory(gTestPath).replace( "chrome://mochitests/content", "http://example.com" ); const TEST_GREEN_PAGE = TEST_ROOT + "green2vh.html"; const gScreenshotUISelectors = { preselectIframe: "#firefox-screenshots-preselection-iframe", fullPageButton: "button.full-page", visiblePageButton: "button.visible", previewIframe: "#firefox-screenshots-preview-iframe", copyButton: "button.highlight-button-copy", downloadButton: "button.highlight-button-download", }; class ScreenshotsHelper { constructor(browser) { this.browser = browser; this.selector = gScreenshotUISelectors; } get toolbarButton() { return document.getElementById("screenshot-button"); } async triggerUIFromToolbar() { let button = this.toolbarButton; ok( BrowserTestUtils.is_visible(button), "The screenshot toolbar button is visible" ); EventUtils.synthesizeMouseAtCenter(button, {}); // Make sure the Screenshots UI is loaded before yielding await this.waitForUIContent( this.selector.preselectIframe, this.selector.fullPageButton ); } async waitForUIContent(iframeSel, elemSel) { await SpecialPowers.spawn( this.browser, [iframeSel, elemSel], async function (iframeSelector, elemSelector) { info( `in waitForUIContent content function, iframeSelector: ${iframeSelector}, elemSelector: ${elemSelector}` ); let iframe; await ContentTaskUtils.waitForCondition(() => { iframe = content.document.querySelector(iframeSelector); if (!iframe || !ContentTaskUtils.is_visible(iframe)) { info("in waitForUIContent, no visible iframe yet"); return false; } let elem = iframe.contentDocument.querySelector(elemSelector); info( "in waitForUIContent, got visible elem: " + (elem && ContentTaskUtils.is_visible(elem)) ); return elem && ContentTaskUtils.is_visible(elem); }); // wait a frame for the screenshots UI to finish any init await new content.Promise(res => content.requestAnimationFrame(res)); } ); } async clickUIElement(iframeSel, elemSel) { await SpecialPowers.spawn( this.browser, [iframeSel, elemSel], async function (iframeSelector, elemSelector) { info( `in clickScreenshotsUIElement content function, iframeSelector: ${iframeSelector}, elemSelector: ${elemSelector}` ); const EventUtils = ContentTaskUtils.getEventUtils(content); let iframe = content.document.querySelector(iframeSelector); let elem = iframe.contentDocument.querySelector(elemSelector); info(`Found the thing to click: ${elemSelector}: ${!!elem}`); EventUtils.synthesizeMouseAtCenter(elem, {}, iframe.contentWindow); await new content.Promise(res => content.requestAnimationFrame(res)); } ); } waitForToolbarButtonDeactivation() { return BrowserTestUtils.waitForCondition(() => { return !this.toolbarButton.style.cssText.includes("icon-highlight"); }); } getContentDimensions() { return SpecialPowers.spawn(this.browser, [], async function () { let doc = content.document; let rect = doc.documentElement.getBoundingClientRect(); return { clientHeight: doc.documentElement.clientHeight, clientWidth: doc.documentElement.clientWidth, currentURI: doc.documentURI, documentHeight: Math.round(rect.height), documentWidth: Math.round(rect.width), }; }); } } function waitForRawClipboardChange() { const initialClipboardData = Date.now().toString(); SpecialPowers.clipboardCopyString(initialClipboardData); let promiseChanged = BrowserTestUtils.waitForCondition(() => { let data; try { data = getRawClipboardData("image/png"); } catch (e) { console.log("Failed to get image/png clipboard data:", e); return false; } return data && initialClipboardData !== data; }); return promiseChanged; } function getRawClipboardData(flavor) { const whichClipboard = Services.clipboard.kGlobalClipboard; const xferable = Cc["@mozilla.org/widget/transferable;1"].createInstance( Ci.nsITransferable ); xferable.init(null); xferable.addDataFlavor(flavor); Services.clipboard.getData(xferable, whichClipboard); let data = {}; try { xferable.getTransferData(flavor, data); } catch (e) {} data = data.value || null; return data; } /** * A helper that returns the size of the image that was just put into the clipboard by the * :screenshot command. * @return The {width, height} dimension object. */ async function getImageSizeFromClipboard(browser) { let flavor = "image/png"; let image = getRawClipboardData(flavor); ok(image, "screenshot data exists on the clipboard"); // Due to the differences in how images could be stored in the clipboard the // checks below are needed. The clipboard could already provide the image as // byte streams or as image container. If it's not possible obtain a // byte stream, the function throws. if (image instanceof Ci.imgIContainer) { image = Cc["@mozilla.org/image/tools;1"] .getService(Ci.imgITools) .encodeImage(image, flavor); } if (!(image instanceof Ci.nsIInputStream)) { throw new Error("Unable to read image data"); } const binaryStream = Cc["@mozilla.org/binaryinputstream;1"].createInstance( Ci.nsIBinaryInputStream ); binaryStream.setInputStream(image); const available = binaryStream.available(); const buffer = new ArrayBuffer(available); is( binaryStream.readArrayBuffer(available, buffer), available, "Read expected amount of data" ); // We are going to load the image in the content page to measure its size. // We don't want to insert the image directly in the browser's document // which could mess all sorts of things up return SpecialPowers.spawn(browser, [buffer], async function (_buffer) { const img = content.document.createElement("img"); const loaded = new Promise(r => { img.addEventListener("load", r, { once: true }); }); const url = content.URL.createObjectURL( new Blob([_buffer], { type: "image/png" }) ); img.src = url; content.document.documentElement.appendChild(img); info("Waiting for the clipboard image to load in the content page"); await loaded; img.remove(); content.URL.revokeObjectURL(url); // TODO: could get pixel data as well so we can check colors at specific locations return { width: img.width, height: img.height, }; }); } add_setup(async function common_initialize() { // Ensure Screenshots is initially enabled for all tests const addon = await AddonManager.getAddonByID("screenshots@mozilla.org"); const isEnabled = addon.enabled; if (!isEnabled) { await addon.enable({ allowSystemAddons: true }); registerCleanupFunction(async () => { await addon.disable({ allowSystemAddons: true }); }); } // Add the Screenshots button to the toolbar for all tests CustomizableUI.addWidgetToArea( "screenshot-button", CustomizableUI.AREA_NAVBAR ); registerCleanupFunction(() => CustomizableUI.removeWidgetFromArea("screenshot-button") ); let screenshotBtn = document.getElementById("screenshot-button"); Assert.ok(screenshotBtn, "The screenshots button was added to the nav bar"); });