Bug 1464461 - add back mochitests for screenshot command; r=nchevobbe,ochameau
authoryulia <ystartsev@mozilla.com>
Fri, 08 Jun 2018 20:14:36 +0200
changeset 424813 ea3556925d99
parent 424812 e090de5269dc
child 424814 dc54472ca3bf
push id34224
push usershindli@mozilla.com
push dateTue, 03 Jul 2018 21:55:38 +0000
treeherdermozilla-central@b636a45b545e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnchevobbe, ochameau
bugs1464461
milestone63.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1464461 - add back mochitests for screenshot command; r=nchevobbe,ochameau MozReview-Commit-ID: 4yGM74AXwoP
devtools/client/webconsole/test/mochitest/browser.ini
devtools/client/webconsole/test/mochitest/browser_jsterm_screenshot_command_clipboard.js
devtools/client/webconsole/test/mochitest/browser_jsterm_screenshot_command_file.js
devtools/client/webconsole/test/mochitest/test_jsterm_screenshot_command.html
devtools/server/actors/webconsole/screenshot.js
--- a/devtools/client/webconsole/test/mochitest/browser.ini
+++ b/devtools/client/webconsole/test/mochitest/browser.ini
@@ -98,16 +98,17 @@ support-files =
   test-ineffective-iframe-sandbox-warning4.html
   test-ineffective-iframe-sandbox-warning5.html
   test-insecure-frame.html
   test-insecure-passwords-about-blank-web-console-warning.html
   test-insecure-passwords-web-console-warning.html
   test-inspect-cross-domain-objects-frame.html
   test-inspect-cross-domain-objects-top.html
   test-jsterm-dollar.html
+  test_jsterm_screenshot_command.html
   test-local-session-storage.html
   test-location-debugger-link-console-log.js
   test-location-debugger-link-errors.js
   test-location-debugger-link.html
   test-location-styleeditor-link-1.css
   test-location-styleeditor-link-2.css
   test-location-styleeditor-link.html
   test-message-categories-canvas-css.html
@@ -222,16 +223,20 @@ skip-if = os != 'mac' # The tested ctrl+
 [browser_jsterm_instance_of.js]
 [browser_jsterm_multiline.js]
 [browser_jsterm_no_autocompletion_on_defined_variables.js]
 [browser_jsterm_no_input_and_tab_key_pressed.js]
 [browser_jsterm_no_input_change_and_tab_key_pressed.js]
 [browser_jsterm_null_undefined.js]
 [browser_jsterm_popup_close_on_tab_switch.js]
 [browser_jsterm_popup.js]
+[browser_jsterm_screenshot_command_clipboard.js]
+subsuite = clipboard
+[browser_jsterm_screenshot_command_file.js]
+skip-if = (os == 'win') # Bug 1464461, disabled on Win due to timeouts
 [browser_jsterm_selfxss.js]
 subsuite = clipboard
 [browser_webconsole_allow_mixedcontent_securityerrors.js]
 tags = mcb
 [browser_webconsole_batching.js]
 [browser_webconsole_block_mixedcontent_securityerrors.js]
 tags = mcb
 [browser_webconsole_cached_messages.js]
new file mode 100644
--- /dev/null
+++ b/devtools/client/webconsole/test/mochitest/browser_jsterm_screenshot_command_clipboard.js
@@ -0,0 +1,209 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that screenshot command works properly
+
+"use strict";
+
+const TEST_URI = "http://example.com/browser/devtools/client/webconsole/" +
+                 "test/mochitest/test_jsterm_screenshot_command.html";
+
+// on some machines, such as macOS, dpr is set to 2. This is expected behavior, however
+// to keep tests consistant across OSs we are setting the dpr to 1
+const dpr = "--dpr 1";
+
+add_task(async function() {
+  const hud = await openNewTabAndConsole(TEST_URI);
+  ok(hud, "web console opened");
+
+  await testClipboard(hud);
+  await testFullpageClipboard(hud);
+  await testSelectorClipboard(hud);
+
+  // overflow
+  await createScrollbarOverflow();
+  await testFullpageClipboardScrollbar(hud);
+});
+
+async function testClipboard(hud) {
+  const command = `:screenshot --clipboard ${dpr}`;
+  const onMessage = waitForMessage(hud, "Screenshot copied to clipboard.");
+  hud.jsterm.execute(command);
+  await onMessage;
+  const contentSize = await getContentSize();
+  const imgSize = await getImageSizeFromClipboard();
+
+  is(imgSize.width, contentSize.innerWidth,
+     "Clipboard: Image width matches window size");
+  is(imgSize.height, contentSize.innerHeight,
+     "Clipboard: Image height matches window size");
+}
+
+async function testFullpageClipboard(hud) {
+  const command = `:screenshot --fullpage --clipboard ${dpr}`;
+  const onMessage = waitForMessage(hud, "Screenshot copied to clipboard.");
+  hud.jsterm.execute(command);
+  await onMessage;
+  const contentSize = await getContentSize();
+  const imgSize = await getImageSizeFromClipboard();
+
+  is(imgSize.width,
+    (contentSize.innerWidth + contentSize.scrollMaxX -
+     contentSize.scrollMinX),
+    "Fullpage Clipboard: Image width matches page size");
+  is(imgSize.height,
+    (contentSize.innerHeight + contentSize.scrollMaxY -
+     contentSize.scrollMinY),
+    "Fullpage Clipboard: Image height matches page size");
+}
+
+async function testSelectorClipboard(hud) {
+  const command = `:screenshot --selector "img#testImage" --clipboard ${dpr}`;
+  const messageReceived = waitForMessage(hud, "Screenshot copied to clipboard.");
+  hud.jsterm.execute(command);
+  await messageReceived;
+  const imgSize1 = await getImageSizeFromClipboard();
+  await ContentTask.spawn(
+    gBrowser.selectedBrowser,
+    imgSize1,
+    function(imgSize) {
+      const img = content.document.querySelector("#testImage");
+      is(imgSize.width, img.clientWidth,
+         "Selector Clipboard: Image width matches element size");
+      is(imgSize.height, img.clientHeight,
+         "Selector Clipboard: Image height matches element size");
+    }
+  );
+}
+
+async function testFullpageClipboardScrollbar(hud) {
+  const command = `:screenshot --fullpage --clipboard ${dpr}`;
+  const onMessage = waitForMessage(hud, "Screenshot copied to clipboard.");
+  hud.jsterm.execute(command);
+  await onMessage;
+  const contentSize = await getContentSize();
+  const scrollbarSize = await getScrollbarSize();
+  const imgSize = await getImageSizeFromClipboard();
+
+  is(imgSize.width,
+    (contentSize.innerWidth + contentSize.scrollMaxX -
+     contentSize.scrollMinX) - scrollbarSize.width,
+    "Scroll Fullpage Clipboard: Image width matches page size minus scrollbar size");
+  is(imgSize.height,
+    (contentSize.innerHeight + contentSize.scrollMaxY -
+     contentSize.scrollMinY) - scrollbarSize.height,
+    "Scroll Fullpage Clipboard: Image height matches page size minus scrollbar size");
+}
+
+async function createScrollbarOverflow() {
+  // Trigger scrollbars by forcing document to overflow
+  // This only affects results on OSes with scrollbars that reduce document size
+  // (non-floating scrollbars).  With default OS settings, this means Windows
+  // and Linux are affected, but Mac is not.  For Mac to exhibit this behavior,
+  // change System Preferences -> General -> Show scroll bars to Always.
+  await ContentTask.spawn(gBrowser.selectedBrowser, {}, function() {
+    content.document.body.classList.add("overflow");
+  });
+}
+
+async function getScrollbarSize() {
+  const scrollbarSize = await ContentTask.spawn(
+    gBrowser.selectedBrowser,
+    {},
+    function() {
+      const winUtils = content.QueryInterface(Ci.nsIInterfaceRequestor)
+                              .getInterface(Ci.nsIDOMWindowUtils);
+      const scrollbarHeight = {};
+      const scrollbarWidth = {};
+      winUtils.getScrollbarSize(true, scrollbarWidth, scrollbarHeight);
+      return {
+        width: scrollbarWidth.value,
+        height: scrollbarHeight.value,
+      };
+    }
+  );
+  info(`Scrollbar size: ${scrollbarSize.width}x${scrollbarSize.height}`);
+  return scrollbarSize;
+}
+
+async function getContentSize() {
+  const contentSize = await ContentTask.spawn(
+    gBrowser.selectedBrowser,
+    {},
+    function() {
+      return {
+        scrollMaxY: content.scrollMaxY,
+        scrollMaxX: content.scrollMaxX,
+        scrollMinY: content.scrollMinY,
+        scrollMinX: content.scrollMinX,
+        innerWidth: content.innerWidth,
+        innerHeight: content.innerHeight
+      };
+    }
+  );
+
+  info(`content size: ${contentSize.innerWidth}x${contentSize.innerHeight}`);
+  return contentSize;
+}
+
+async function getImageSizeFromClipboard() {
+  const clipid = Ci.nsIClipboard;
+  const clip = Cc["@mozilla.org/widget/clipboard;1"].getService(clipid);
+  const trans = Cc["@mozilla.org/widget/transferable;1"]
+                .createInstance(Ci.nsITransferable);
+  const flavor = "image/png";
+  trans.init(null);
+  trans.addDataFlavor(flavor);
+
+  clip.getData(trans, clipid.kGlobalClipboard);
+  const data = {};
+  const dataLength = {};
+  trans.getTransferData(flavor, data, dataLength);
+
+  ok(data.value, "screenshot exists");
+  ok(dataLength.value > 0, "screenshot has length");
+
+  let image = data.value;
+  let dataURI = `data:${flavor};base64,`;
+
+  // 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, but also as pointer, or as image container. If it's not
+  // possible obtain a byte stream, the function returns `null`.
+  if (image instanceof Ci.nsISupportsInterfacePointer) {
+    image = image.data;
+  }
+
+  if (image instanceof Ci.imgIContainer) {
+    image = Cc["@mozilla.org/image/tools;1"]
+              .getService(Ci.imgITools)
+              .encodeImage(image, flavor);
+  }
+
+  if (image instanceof Ci.nsIInputStream) {
+    const binaryStream = Cc["@mozilla.org/binaryinputstream;1"]
+                         .createInstance(Ci.nsIBinaryInputStream);
+    binaryStream.setInputStream(image);
+    const rawData = binaryStream.readBytes(binaryStream.available());
+    const charCodes = Array.from(rawData, c => c.charCodeAt(0) & 0xff);
+    let encodedData = String.fromCharCode(...charCodes);
+    encodedData = btoa(encodedData);
+    dataURI = dataURI + encodedData;
+  } else {
+    throw new Error("Unable to read image data");
+  }
+
+  const img = document.createElementNS("http://www.w3.org/1999/xhtml", "img");
+
+  const loaded =  once(img, "load");
+
+  img.src = dataURI;
+  document.documentElement.appendChild(img);
+  await loaded;
+  img.remove();
+
+  return {
+    width: img.width,
+    height: img.height,
+  };
+}
new file mode 100644
--- /dev/null
+++ b/devtools/client/webconsole/test/mochitest/browser_jsterm_screenshot_command_file.js
@@ -0,0 +1,39 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Test that screenshot command works properly
+
+"use strict";
+
+const TEST_URI = "http://example.com/browser/devtools/client/webconsole/" +
+                 "test/mochitest/test_jsterm_screenshot_command.html";
+
+const FileUtils = (ChromeUtils.import("resource://gre/modules/FileUtils.jsm", {})).FileUtils;
+// on some machines, such as macOS, dpr is set to 2. This is expected behavior, however
+// to keep tests consistant across OSs we are setting the dpr to 1
+const dpr = "--dpr 1";
+
+add_task(async function() {
+  await addTab(TEST_URI);
+
+  const hud = await openConsole();
+  ok(hud, "web console opened");
+
+  await testFile(hud);
+});
+
+async function testFile(hud) {
+  // Test capture to file
+  const file = FileUtils.getFile("TmpD", [ "TestScreenshotFile.png" ]);
+  const command = `:screenshot ${file.path} ${dpr}`;
+  const onMessage = waitForMessage(hud, `Saved to ${file.path}`);
+  hud.jsterm.execute(command);
+  await onMessage;
+
+  ok(file.exists(), "Screenshot file exists");
+
+  if (file.exists()) {
+    file.remove(false);
+  }
+}
+
new file mode 100644
--- /dev/null
+++ b/devtools/client/webconsole/test/mochitest/test_jsterm_screenshot_command.html
@@ -0,0 +1,18 @@
+<html>
+  <head>
+    <style>
+      img {
+        height: 100px;
+        width: 100px;
+      }
+      .overflow {
+        overflow: scroll;
+        height: 200%;
+        width: 200%;
+      }
+    </style>
+  </head>
+  <body>
+    <img id="testImage" ></img>
+  </body>
+</html>
--- a/devtools/server/actors/webconsole/screenshot.js
+++ b/devtools/server/actors/webconsole/screenshot.js
@@ -1,17 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const { Ci, Cu } = require("chrome");
 const { getRect } = require("devtools/shared/layout/utils");
-const { LocalizationHelper } = require("devtools/shared/L10N");
+const { LocalizationHelper } = require("devtools/shared/l10n");
 
 const CONTAINER_FLASHING_DURATION = 500;
 const STRINGS_URI = "devtools/shared/locales/screenshot.properties";
 const L10N = new LocalizationHelper(STRINGS_URI);
 
 exports.screenshot = function takeAsyncScreenshot(owner, args = {}) {
   if (args.help) {
     // Early return as help will be handled on the client side.