Bug 1373134 - Unit tests. r?pbro draft
authorMicah Tigley <tigleym@gmail.com>
Mon, 28 Aug 2017 21:17:20 -0600
changeset 658749 9d7b8f9841a7d78268a44b6d08e976e0b9cce332
parent 654655 031b2e08e871ef9f2d0cbee60ded5d97d754547b
child 729747 3da5d51ce54c9c5d45a5ab95537ec0fda0938b9b
push id77868
push userbmo:tigleym@gmail.com
push dateMon, 04 Sep 2017 21:10:30 +0000
reviewerspbro
bugs1373134
milestone57.0a1
Bug 1373134 - Unit tests. r?pbro MozReview-Commit-ID: KF7hfGf8XmC
devtools/client/inspector/grids/test/browser.ini
devtools/client/inspector/grids/test/browser_grids_grid-outline-scroll-into-view-of-grid.js
devtools/client/inspector/grids/test/head.js
devtools/client/shared/test/test-actor.js
--- a/devtools/client/inspector/grids/test/browser.ini
+++ b/devtools/client/inspector/grids/test/browser.ini
@@ -24,13 +24,14 @@ support-files =
 [browser_grids_grid-list-on-iframe-reloaded.js]
 [browser_grids_grid-list-on-mutation-element-added.js]
 [browser_grids_grid-list-on-mutation-element-removed.js]
 [browser_grids_grid-list-toggle-multiple-grids.js]
 [browser_grids_grid-list-toggle-single-grid.js]
 [browser_grids_grid-outline-cannot-show-outline.js]
 [browser_grids_grid-outline-highlight-area.js]
 [browser_grids_grid-outline-highlight-cell.js]
+[browser_grids_grid-outline-scroll-into-view-of-grid.js]
 [browser_grids_grid-outline-selected-grid.js]
 [browser_grids_grid-outline-updates-on-grid-change.js]
 [browser_grids_highlighter-setting-rules-grid-toggle.js]
 [browser_grids_number-of-css-grids-telemetry.js]
 [browser_grids_restored-after-reload.js]
new file mode 100644
--- /dev/null
+++ b/devtools/client/inspector/grids/test/browser_grids_grid-outline-scroll-into-view-of-grid.js
@@ -0,0 +1,167 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests that a grid is scrolled into view when it is toggled or when the
+// grid outline is hovered over.
+
+const TEST_URI = `
+  <style>
+  .container {
+    display: grid;
+    grid-template-columns: repeat(2, 20vw);
+    grid-template-rows: repeat(10, 20vh);
+  }
+  .container2 {
+    display: grid;
+    grid-template-columns: repeat(2, 20vw);
+    grid-template-rows: repeat(20, 20vh);
+  }
+  </style>
+  <div id="grid1" class="container">
+    <div>Grid 1</div>
+  </div>
+  <div id="grid2" class="container2">
+    <div>Grid 2</div>
+  </div>
+  <div id="grid3" class="container">
+    <div>Grid 3</div>
+  </div>
+`;
+
+const SCROLL_INTO_VIEW_OF_GRID_PREF = "devtools.gridinspector.scrollIntoViewOfGridNode";
+const AUTOSCROLL_TO_GRID_CELLS = "devtools.gridinspector.autoScrollToGridCells";
+
+add_task(function* () {
+  yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+
+  let { inspector, gridInspector, testActor } = yield openLayoutView();
+  let { document: doc } = gridInspector;
+
+  info("Setting 'scrollIntoViewOfGridNode' pref to true.");
+  Services.prefs.setBoolPref(SCROLL_INTO_VIEW_OF_GRID_PREF, true);
+  ok(Services.prefs.getBoolPref(SCROLL_INTO_VIEW_OF_GRID_PREF),
+    "Scrolling into view of grid is true.");
+
+  let gridList = doc.getElementById("grid-list");
+  let { store, highlighters } = inspector;
+
+  info("Select the #grid3 node to scroll to it.");
+  yield selectGrid(2, gridList, highlighters, store);
+
+  info("#grid1 should be scrolled away from and #grid3 should be in view.");
+  yield checkElementIsInViewport("#grid1", false, testActor);
+  yield checkElementIsInViewport("#grid3", true, testActor);
+
+  info("Select the #grid2 node to scroll to it.");
+  yield selectGrid(1, gridList, highlighters, store);
+
+  info("#grid3 should be scrolled away from and #grid2 should be in view.");
+  yield checkElementIsInViewport("#grid3", false, testActor);
+  yield checkElementIsInViewport("#grid2", true, testActor);
+
+  let checkbox = doc.getElementById("grid-setting-scroll-to-grid-cell");
+  ok(checkbox, "'Automatically scroll to grid cell' checkbox label "
+    + "should be shown");
+
+  info("Checking the initial state of auto scrolling grid cell view pref setting.");
+  ok(!Services.prefs.getBoolPref(AUTOSCROLL_TO_GRID_CELLS),
+    "'Automatically scroll to grid cells' pref is off by default.");
+
+  info("Toggling ON the 'Automatically scroll to grid cells' setting.");
+  let onCheckboxChange = waitUntilState(store, state =>
+    state.highlighterSettings.scrollToGridCell);
+  checkbox.click();
+  yield onCheckboxChange;
+
+  ok(Services.prefs.getBoolPref(AUTOSCROLL_TO_GRID_CELLS),
+    "'Automatically scroll to grid cells' pref is on.");
+
+  info("Hovering over last grid cell in the grid outline for grid#2.");
+  let outline = yield doc.getElementById("grid-cell-group");
+  let lastCellIndex = outline.children.length - 1;
+  let gridCell = outline.children[lastCellIndex];
+
+  gridCell.scrollIntoView();
+
+  let onCellHighlight = highlighters.once("grid-highlighter-shown");
+  EventUtils.synthesizeMouse(gridCell, 5, 5, {type: "mouseover"}, doc.defaultView);
+  yield onCellHighlight;
+
+  info("#grid3 should be in view.");
+  yield checkElementIsInViewport("#grid3", true, testActor);
+
+  info("Toggling OFF the 'Automatically scroll to grid cells' setting.");
+  onCheckboxChange = waitUntilState(store, state =>
+    !state.highlighterSettings.scrollToGridCell);
+  checkbox.click();
+  yield onCheckboxChange;
+
+  ok(!Services.prefs.getBoolPref(AUTOSCROLL_TO_GRID_CELLS),
+    "'Automatically scroll to grid cells' pref is off.");
+
+  info("Hovering over last grid cell in the grid outline for grid#1.");
+  yield selectGrid(0, gridList, highlighters, store);
+  outline = yield doc.getElementById("grid-cell-group");
+  lastCellIndex = outline.children.length - 1;
+  gridCell = outline.children[lastCellIndex];
+  let onGridOutlineRendered = waitForDOM(doc, ".grid-outline-cell", 20);
+
+  yield gridCell.scrollIntoView();
+
+  info("Press down ctrlKey as mouse hovers over outline.");
+  EventUtils.synthesizeMouse(gridCell, 5, 5, { type: "mousemove", ctrlKey: true },
+   doc.defaultView);
+
+  yield onCellHighlight;
+  yield onGridOutlineRendered;
+
+  info("#grid2 should be in view.");
+  yield checkElementIsInViewport("#grid2", true, testActor);
+
+  info("Clearing 'scrollIntoViewOfGridNode' pref");
+  Services.prefs.clearUserPref(SCROLL_INTO_VIEW_OF_GRID_PREF);
+  ok(!Services.prefs.getBoolPref(SCROLL_INTO_VIEW_OF_GRID_PREF),
+    "Scrolling into view of grid is false by default.");
+});
+
+/**
+ * Verify that the element matching the provided selector is either in or out
+ * of the viewport, depending on the provided "expected" argument.
+ * Returns a promise that will resolve when the test has been performed.
+ *
+ * @param {String} selector
+ *        css selector for the element to test
+ * @param {Boolean} expected
+ *        true if the element is expected to be in the viewport, false otherwise
+ * @param {TestActor} testActor
+ *        current test actor
+ * @return {Promise} promise
+ */
+function* checkElementIsInViewport(selector, expected, testActor) {
+  let isInViewport = yield testActor.isInViewport(selector);
+  is(isInViewport, expected, selector + " in the viewport: expected to be " + expected);
+}
+
+/**
+ * Simulate selecting a grid from the grid list.
+ *
+ * @param {Number} gridIndex
+ *        Index of grid node to select.
+ * @param {Object} gridList
+ *        List of grid items.
+ * @param {Highlighters} highlighters
+ *        Grid inspector highlighters.
+ * @param {Store} store
+ *        Store for the grid inspector state.
+ */
+function* selectGrid(gridIndex, gridList, highlighters, store) {
+  let gridCheckBox = gridList.children[gridIndex].querySelector("input");
+  let onHighlighterShown = highlighters.once("grid-highlighter-shown");
+  let onGridCheckboxChange = waitUntilState(store, state =>
+    state.grids[gridIndex].highlighted);
+  gridCheckBox.click();
+  yield onHighlighterShown;
+  yield onGridCheckboxChange;
+}
--- a/devtools/client/inspector/grids/test/head.js
+++ b/devtools/client/inspector/grids/test/head.js
@@ -12,16 +12,17 @@ Services.scriptloader.loadSubScript(
   this);
 
 // Load the shared Redux helpers into this compartment.
 Services.scriptloader.loadSubScript(
   "chrome://mochitests/content/browser/devtools/client/framework/test/shared-redux-head.js",
   this);
 
 Services.prefs.setBoolPref("devtools.promote.layoutview.showPromoteBar", false);
+Services.prefs.setBoolPref("devtools.gridinspector.scrollIntoViewOfGridNode", true);
 Services.prefs.setIntPref("devtools.toolbox.footer.height", 350);
 registerCleanupFunction(() => {
   Services.prefs.clearUserPref("devtools.promote.layoutview.showPromoteBar");
   Services.prefs.clearUserPref("devtools.toolbox.footer.height");
 });
 
 const HIGHLIGHTER_TYPE = "CssGridHighlighter";
 
--- a/devtools/client/shared/test/test-actor.js
+++ b/devtools/client/shared/test/test-actor.js
@@ -292,16 +292,24 @@ var testSpec = protocol.generateActorSpe
         value: RetVal("json")
       }
     },
     getWindowDimensions: {
       request: {},
       response: {
         value: RetVal("json")
       }
+    },
+    isInViewport: {
+      request: {
+        selector: Arg(0, "string")
+      },
+      response: {
+        value: RetVal("boolean")
+      }
     }
   }
 });
 
 var TestActor = exports.TestActor = protocol.ActorClassWithSpec(testSpec, {
   initialize: function (conn, tabActor, options) {
     this.conn = conn;
     this.tabActor = tabActor;
@@ -795,17 +803,34 @@ var TestActor = exports.TestActor = prot
   /**
    * Returns the window's dimensions for the `window` given.
    *
    * @return {Object} An object with `width` and `height` properties, representing the
    * number of pixels for the document's size.
    */
   getWindowDimensions: function () {
     return getWindowDimensions(this.content);
-  }
+  },
+
+  /**
+   * Verifies whether or not an element matching the specified selector is visible in the
+   * viewport.
+   *
+   * @param   {String} selector
+   *          CSS selector for the element to test
+   *
+   * @return  {Boolean}
+   *          Whether or not the element is visible in the viewport.
+   */
+  isInViewport: function (selector) {
+    const rect = this.getBoundingClientRect(selector);
+
+    return rect.bottom >= 0 && rect.right >= 0 &&
+          rect.top <= this.content.innerHeight && rect.left <= this.content.innerWidth;
+  },
 });
 
 var TestActorFront = exports.TestActorFront = protocol.FrontClassWithSpec(testSpec, {
   initialize: function (client, { testActor }, toolbox) {
     protocol.Front.prototype.initialize.call(this, client, { actor: testActor });
     this.manage(this);
     this.toolbox = toolbox;
   },