Bug 1239437 - xpcshell tests for responsive.html. r=pbrosset
authorJ. Ryan Stinnett <jryans@gmail.com>
Tue, 19 Jan 2016 22:04:36 -0600
changeset 325616 6b3fdf3adbc3ea8b9956da2fca088b069e96b2f9
parent 325615 bbdb71a5c1c002ae6c3c679f76e19705bdc6cd67
child 325617 11a95f8c361aa3f52dd509c539010928304fddb5
push id10011
push usercmanchester@mozilla.com
push dateTue, 26 Jan 2016 02:20:25 +0000
reviewerspbrosset
bugs1239437
milestone47.0a1
Bug 1239437 - xpcshell tests for responsive.html. r=pbrosset
devtools/client/framework/moz.build
devtools/client/framework/test/browser.ini
devtools/client/framework/test/shared-redux-head.js
devtools/client/framework/test/xpcshell.ini
devtools/client/memory/test/browser/head.js
devtools/client/memory/test/unit/head.js
devtools/client/memory/test/unit/xpcshell.ini
devtools/client/responsive.html/moz.build
devtools/client/responsive.html/test/unit/.eslintrc
devtools/client/responsive.html/test/unit/head.js
devtools/client/responsive.html/test/unit/test_add_viewport.js
devtools/client/responsive.html/test/unit/test_change_location.js
devtools/client/responsive.html/test/unit/xpcshell.ini
--- a/devtools/client/framework/moz.build
+++ b/devtools/client/framework/moz.build
@@ -1,15 +1,16 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
 BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
+XPCSHELL_TESTS_MANIFESTS += ['test/xpcshell.ini']
 
 DevToolsModules(
     'attach-thread.js',
     'gDevTools.jsm',
     'selection.js',
     'sidebar.js',
     'target.js',
     'toolbox-highlighter-utils.js',
--- a/devtools/client/framework/test/browser.ini
+++ b/devtools/client/framework/test/browser.ini
@@ -4,16 +4,17 @@ subsuite = devtools
 support-files =
   browser_toolbox_options_disable_js.html
   browser_toolbox_options_disable_js_iframe.html
   browser_toolbox_options_disable_cache.sjs
   browser_toolbox_sidebar_tool.xul
   code_math.js
   head.js
   shared-head.js
+  shared-redux-head.js
   helper_disable_cache.js
   doc_theme.css
   doc_viewsource.html
   browser_toolbox_options_enable_serviceworkers_testing_frame_script.js
   browser_toolbox_options_enable_serviceworkers_testing.html
   serviceworker.js
 
 [browser_devtools_api.js]
new file mode 100644
--- /dev/null
+++ b/devtools/client/framework/test/shared-redux-head.js
@@ -0,0 +1,83 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+/* eslint no-unused-vars: [2, {"vars": "local"}] */
+// Currently this file expects "promise" to be imported into scope.
+/* globals promise */
+
+// Common utility functions for working with Redux stores.  The file is meant
+// to be safe to load in both mochitest and xpcshell environments.
+
+/**
+ * A logging function that can be used from xpcshell and browser mochitest
+ * environments.
+ */
+function commonLog(message) {
+  let log;
+  if (Services && Services.appinfo && Services.appinfo.name &&
+      Services.appinfo.name == "Firefox") {
+    log = info;
+  } else {
+    log = do_print;
+  }
+  log(message);
+}
+
+/**
+ * Wait until the store has reached a state that matches the predicate.
+ * @param Store store
+ *        The Redux store being used.
+ * @param function predicate
+ *        A function that returns true when the store has reached the expected
+ *        state.
+ * @return Promise
+ *         Resolved once the store reaches the expected state.
+ */
+function waitUntilState(store, predicate) {
+  let deferred = promise.defer();
+  let unsubscribe = store.subscribe(check);
+
+  commonLog(`Waiting for state predicate "${predicate}"`);
+  function check() {
+    if (predicate(store.getState())) {
+      commonLog(`Found state predicate "${predicate}"`);
+      unsubscribe();
+      deferred.resolve();
+    }
+  }
+
+  // Fire the check immediately in case the action has already occurred
+  check();
+
+  return deferred.promise;
+}
+
+/**
+ * Wait until a particular action has been emitted by the store.
+ * @param Store store
+ *        The Redux store being used.
+ * @param string actionType
+ *        The expected action to wait for.
+ * @return Promise
+ *         Resolved once the expected action is emitted by the store.
+ */
+function waitUntilAction(store, actionType) {
+  let deferred = promise.defer();
+  let unsubscribe = store.subscribe(check);
+  let history = store.history;
+  let index = history.length;
+
+  commonLog(`Waiting for action "${actionType}"`);
+  function check() {
+    let action = history[index++];
+    if (action && action.type === actionType) {
+      commonLog(`Found action "${actionType}"`);
+      unsubscribe();
+      deferred.resolve(store.getState());
+    }
+  }
+
+  return deferred.promise;
+}
new file mode 100644
--- /dev/null
+++ b/devtools/client/framework/test/xpcshell.ini
@@ -0,0 +1,7 @@
+[DEFAULT]
+tags = devtools
+head =
+tail =
+firefox-appdir = browser
+support-files =
+  shared-redux-head.js
--- a/devtools/client/memory/test/browser/head.js
+++ b/devtools/client/memory/test/browser/head.js
@@ -3,16 +3,21 @@
 
 "use strict";
 
 // Load the shared test helpers into this compartment.
 Services.scriptloader.loadSubScript(
   "chrome://mochitests/content/browser/devtools/client/framework/test/shared-head.js",
   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);
+
 var { snapshotState: states } = require("devtools/client/memory/constants");
 var { breakdownEquals, breakdownNameToSpec } = require("devtools/client/memory/utils");
 
 Services.prefs.setBoolPref("devtools.memory.enabled", true);
 
 /**
  * Open the memory panel for the given tab.
  */
@@ -62,34 +67,16 @@ function makeMemoryTest(url, generator) 
 
     yield closeMemoryPanel(tab);
     yield removeTab(tab);
 
     finish();
   });
 }
 
-
-function waitUntilState (store, predicate) {
-  let deferred = promise.defer();
-  let unsubscribe = store.subscribe(check);
-
-  function check () {
-    if (predicate(store.getState())) {
-      unsubscribe();
-      deferred.resolve()
-    }
-  }
-
-  // Fire the check immediately incase the action has already occurred
-  check();
-
-  return deferred.promise;
-}
-
 function waitUntilSnapshotState (store, expected) {
   let predicate = () => {
     let snapshots = store.getState().snapshots;
     info(snapshots.map(x => x.state));
     return snapshots.length === expected.length &&
            expected.every((state, i) => state === "*" || snapshots[i].state === state);
   };
   info(`Waiting for snapshots to be of state: ${expected}`);
--- a/devtools/client/memory/test/unit/head.js
+++ b/devtools/client/memory/test/unit/head.js
@@ -57,52 +57,16 @@ StubbedMemoryFront.prototype.saveHeapSna
 StubbedMemoryFront.prototype.startRecordingAllocations = expectState("attached", Task.async(function* () {
   this.recordingAllocations = true;
 }));
 
 StubbedMemoryFront.prototype.stopRecordingAllocations = expectState("attached", Task.async(function* () {
   this.recordingAllocations = false;
 }));
 
-function waitUntilState (store, predicate) {
-  let deferred = promise.defer();
-  let unsubscribe = store.subscribe(check);
-
-  function check () {
-    if (predicate(store.getState())) {
-      unsubscribe();
-      deferred.resolve()
-    }
-  }
-
-  // Fire the check immediately incase the action has already occurred
-  check();
-
-  return deferred.promise;
-}
-
-function waitUntilAction (store, actionType) {
-  let deferred = promise.defer();
-  let unsubscribe = store.subscribe(check);
-  let history = store.history;
-  let index = history.length;
-
-  do_print(`Waiting for action "${actionType}"`);
-  function check () {
-    let action = history[index++];
-    if (action && action.type === actionType) {
-      do_print(`Found action "${actionType}"`);
-      unsubscribe();
-      deferred.resolve(store.getState());
-    }
-  }
-
-  return deferred.promise;
-}
-
 function waitUntilSnapshotState (store, expected) {
   let predicate = () => {
     let snapshots = store.getState().snapshots;
     do_print(snapshots.map(x => x.state));
     return snapshots.length === expected.length &&
            expected.every((state, i) => state === "*" || snapshots[i].state === state);
   };
   do_print(`Waiting for snapshots to be of state: ${expected}`);
--- a/devtools/client/memory/test/unit/xpcshell.ini
+++ b/devtools/client/memory/test/unit/xpcshell.ini
@@ -1,11 +1,11 @@
 [DEFAULT]
 tags = devtools devtools-memory
-head = head.js
+head = head.js ../../../framework/test/shared-redux-head.js
 tail =
 firefox-appdir = browser
 skip-if = toolkit == 'android' || toolkit == 'gonk'
 
 [test_action_diffing_01.js]
 [test_action_diffing_02.js]
 [test_action_diffing_03.js]
 [test_action_diffing_04.js]
--- a/devtools/client/responsive.html/moz.build
+++ b/devtools/client/responsive.html/moz.build
@@ -13,8 +13,10 @@ DIRS += [
 DevToolsModules(
     'app.js',
     'index.css',
     'manager.js',
     'reducers.js',
     'store.js',
     'types.js',
 )
+
+XPCSHELL_TESTS_MANIFESTS += ['test/unit/xpcshell.ini']
new file mode 100644
--- /dev/null
+++ b/devtools/client/responsive.html/test/unit/.eslintrc
@@ -0,0 +1,4 @@
+{
+  // Extend from the shared list of defined globals for xpcshell.
+  "extends": "../../../../.eslintrc.xpcshell"
+}
new file mode 100644
--- /dev/null
+++ b/devtools/client/responsive.html/test/unit/head.js
@@ -0,0 +1,19 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+/* eslint no-unused-vars: [2, {"vars": "local"}] */
+
+const { utils: Cu } = Components;
+const { require } = Cu.import("resource://devtools/shared/Loader.jsm", {});
+
+const promise = require("promise");
+const { Task } = require("resource://gre/modules/Task.jsm");
+const Store = require("devtools/client/responsive.html/store");
+
+const DevToolsUtils = require("devtools/shared/DevToolsUtils");
+DevToolsUtils.testing = true;
+do_register_cleanup(() => {
+  DevToolsUtils.testing = false;
+});
new file mode 100644
--- /dev/null
+++ b/devtools/client/responsive.html/test/unit/test_add_viewport.js
@@ -0,0 +1,23 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test adding viewports to the page.
+
+const { addViewport } =
+  require("devtools/client/responsive.html/actions/viewports");
+
+add_task(function*() {
+  let store = Store();
+  const { getState, dispatch } = store;
+
+  equal(getState().viewports.length, 0, "Defaults to no viewpots at startup");
+
+  dispatch(addViewport());
+  equal(getState().viewports.length, 1, "One viewport total");
+
+  // For the moment, there can be at most one viewport.
+  dispatch(addViewport());
+  equal(getState().viewports.length, 1, "One viewport total, again");
+});
new file mode 100644
--- /dev/null
+++ b/devtools/client/responsive.html/test/unit/test_change_location.js
@@ -0,0 +1,22 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test changing the location of the displayed page.
+
+const { changeLocation } =
+  require("devtools/client/responsive.html/actions/location");
+
+const TEST_URL = "http://example.com";
+
+add_task(function*() {
+  let store = Store();
+  const { getState, dispatch } = store;
+
+  equal(getState().location, "about:blank",
+        "Defaults to about:blank at startup");
+
+  dispatch(changeLocation(TEST_URL));
+  equal(getState().location, TEST_URL, "Location changed to TEST_URL");
+});
new file mode 100644
--- /dev/null
+++ b/devtools/client/responsive.html/test/unit/xpcshell.ini
@@ -0,0 +1,8 @@
+[DEFAULT]
+tags = devtools
+head = head.js ../../../framework/test/shared-redux-head.js
+tail =
+firefox-appdir = browser
+
+[test_add_viewport.js]
+[test_change_location.js]