/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ /* vim: set sts=2 sw=2 et tw=80: */ "use strict"; const { HttpServer } = ChromeUtils.import("resource://testing-common/httpd.js"); do_get_profile(); const server = new HttpServer(); server.registerDirectory("/", do_get_cwd()); server.start(-1); const ROOT = `http://localhost:${server.identity.primaryPort}`; const BASE = `${ROOT}/`; const HEADLESS_URL = Services.io.newURI(`${BASE}/headless.html`); const HEADLESS_BUTTON_URL = Services.io.newURI(`${BASE}/headless_button.html`); registerCleanupFunction(() => { server.stop(() => {}); }); // Refrences to the progress listeners to keep them from being gc'ed // before they are called. const progressListeners = new Map(); function loadContentWindow(windowlessBrowser, uri) { return new Promise((resolve, reject) => { let loadURIOptions = { triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(), }; windowlessBrowser.loadURI(uri, loadURIOptions); let docShell = windowlessBrowser.docShell; let webProgress = docShell .QueryInterface(Ci.nsIInterfaceRequestor) .getInterface(Ci.nsIWebProgress); let progressListener = { onLocationChange(progress, request, location, flags) { // Ignore inner-frame events if (progress != webProgress) { return; } // Ignore events that don't change the document if (flags & Ci.nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT) { return; } let contentWindow = docShell.domWindow; webProgress.removeProgressListener(progressListener); progressListeners.delete(progressListener); contentWindow.addEventListener( "load", event => { resolve(contentWindow); }, { once: true } ); }, QueryInterface: ChromeUtils.generateQI([ "nsIWebProgressListener", "nsISupportsWeakReference", ]), }; progressListeners.set(progressListener, progressListener); webProgress.addProgressListener( progressListener, Ci.nsIWebProgress.NOTIFY_LOCATION ); }); } add_task(async function test_snapshot() { let windowlessBrowser = Services.appShell.createWindowlessBrowser(false); let contentWindow = await loadContentWindow(windowlessBrowser, HEADLESS_URL); const contentWidth = 400; const contentHeight = 300; // Verify dimensions. contentWindow.resizeTo(contentWidth, contentHeight); equal(contentWindow.innerWidth, contentWidth); equal(contentWindow.innerHeight, contentHeight); // Snapshot the test page. let canvas = contentWindow.document.createElementNS( "http://www.w3.org/1999/xhtml", "html:canvas" ); let context = canvas.getContext("2d"); let width = contentWindow.innerWidth; let height = contentWindow.innerHeight; canvas.width = width; canvas.height = height; context.drawWindow(contentWindow, 0, 0, width, height, "rgb(255, 255, 255)"); let imageData = context.getImageData(0, 0, width, height).data; ok( imageData[0] === 0 && imageData[1] === 255 && imageData[2] === 0 && imageData[3] === 255, "Page is green." ); // Search for a blue pixel (a quick and dirty check to see if the blue text is // on the page) let found = false; for (let i = 0; i < imageData.length; i += 4) { if (imageData[i + 2] === 255) { found = true; break; } } ok(found, "Found blue text on page."); windowlessBrowser.close(); }); add_task(async function test_snapshot_widget_layers() { let windowlessBrowser = Services.appShell.createWindowlessBrowser(false); // nsIWindowlessBrowser inherits from nsIWebNavigation. let contentWindow = await loadContentWindow(windowlessBrowser, HEADLESS_URL); const contentWidth = 1; const contentHeight = 2; // Verify dimensions. contentWindow.resizeTo(contentWidth, contentHeight); equal(contentWindow.innerWidth, contentWidth); equal(contentWindow.innerHeight, contentHeight); // Snapshot the test page. let canvas = contentWindow.document.createElementNS( "http://www.w3.org/1999/xhtml", "html:canvas" ); let context = canvas.getContext("2d"); let width = contentWindow.innerWidth; let height = contentWindow.innerHeight; canvas.width = width; canvas.height = height; context.drawWindow( contentWindow, 0, 0, width, height, "rgb(255, 255, 255)", context.DRAWWINDOW_DRAW_CARET | context.DRAWWINDOW_DRAW_VIEW | context.DRAWWINDOW_USE_WIDGET_LAYERS ); ok(true, "Snapshot with widget layers didn't crash."); windowlessBrowser.close(); }); // Ensure keydown events are triggered on the windowless browser. add_task(async function test_keydown() { let windowlessBrowser = Services.appShell.createWindowlessBrowser(false); // nsIWindowlessBrowser inherits from nsIWebNavigation. let contentWindow = await loadContentWindow(windowlessBrowser, HEADLESS_URL); let keydown = new Promise(resolve => { contentWindow.addEventListener( "keydown", () => { resolve(); }, { once: true } ); }); let tip = Cc["@mozilla.org/text-input-processor;1"].createInstance( Ci.nsITextInputProcessor ); let begun = tip.beginInputTransactionForTests(contentWindow); ok( begun, "nsITextInputProcessor.beginInputTransactionForTests() should succeed" ); tip.keydown( new contentWindow.KeyboardEvent("", { key: "a", code: "KeyA", keyCode: contentWindow.KeyboardEvent.DOM_VK_A, }) ); await keydown; ok(true, "Send keydown didn't crash"); windowlessBrowser.close(); }); // Test dragging the mouse on a button to ensure the creation of the drag // service doesn't crash in headless. add_task(async function test_mouse_drag() { let windowlessBrowser = Services.appShell.createWindowlessBrowser(false); // nsIWindowlessBrowser inherits from nsIWebNavigation. let contentWindow = await loadContentWindow( windowlessBrowser, HEADLESS_BUTTON_URL ); contentWindow.resizeTo(400, 400); let target = contentWindow.document.getElementById("btn"); let rect = target.getBoundingClientRect(); let left = rect.left; let top = rect.top; let utils = contentWindow.windowUtils; utils.sendMouseEvent("mousedown", left, top, 0, 1, 0, false, 0, 0); utils.sendMouseEvent("mousemove", left, top, 0, 1, 0, false, 0, 0); // Wait for a turn of the event loop since the synthetic mouse event // that creates the drag service is processed during the refresh driver. await new Promise(r => { executeSoon(r); }); utils.sendMouseEvent("mouseup", left, top, 0, 1, 0, false, 0, 0); ok(true, "Send mouse event didn't crash"); windowlessBrowser.close(); });