Bug 1266415 - display a warning on about:debugging if service workers are disabled; r?jdescottes draft
authorgasolin <gasolin@gmail.com>
Fri, 20 May 2016 11:30:56 +0800
changeset 372021 186f3e629a3dfd096d6f4c385b6a916fbb6dbf51
parent 371997 1cf7e08007f9b63d228f9e42a9b501c22a48da92
child 522071 a89b6e2e0fd22d3cf82047c8babe493224ac938a
push id19413
push userbmo:gasolin@mozilla.com
push dateFri, 27 May 2016 07:13:24 +0000
reviewersjdescottes
bugs1266415
milestone49.0a1
Bug 1266415 - display a warning on about:debugging if service workers are disabled; r?jdescottes MozReview-Commit-ID: 5OipoBx7LH2
devtools/client/aboutdebugging/aboutdebugging.css
devtools/client/aboutdebugging/components/addons/controls.js
devtools/client/aboutdebugging/components/target-list.js
devtools/client/aboutdebugging/components/workers/panel.js
devtools/client/aboutdebugging/test/browser.ini
devtools/client/aboutdebugging/test/browser_service_workers_not_compatible.js
devtools/client/aboutdebugging/test/head.js
devtools/client/locales/en-US/aboutdebugging.properties
--- a/devtools/client/aboutdebugging/aboutdebugging.css
+++ b/devtools/client/aboutdebugging/aboutdebugging.css
@@ -107,26 +107,28 @@ button {
 }
 
 .addons-install-error {
   background-color: #f3b0b0;
   padding: 5px 10px;
   margin: 5px 4px 5px 0px;
 }
 
+.service-worker-disabled .warning,
 .addons-install-error .warning {
   background-image: url(chrome://devtools/skin/images/alerticon-warning.png);
   background-size: 13px 12px;
   margin-right: 10px;
   display: inline-block;
   width: 13px;
   height: 12px;
 }
 
 @media (min-resolution: 1.1dppx) {
+  .service-worker-disabled .warning,
   .addons-install-error .warning {
     background-image: url(chrome://devtools/skin/images/alerticon-warning@2x.png);
   }
 }
 
 .addons-options {
   flex: 1;
 }
--- a/devtools/client/aboutdebugging/components/addons/controls.js
+++ b/devtools/client/aboutdebugging/components/addons/controls.js
@@ -75,17 +75,17 @@ module.exports = createClass({
           }),
           dom.label({
             className: "addons-debugging-label",
             htmlFor: "enable-addon-debugging",
             title: Strings.GetStringFromName("addonDebugging.tooltip")
           }, Strings.GetStringFromName("addonDebugging.label")),
           "(",
           dom.a({ href: MORE_INFO_URL, target: "_blank" },
-            Strings.GetStringFromName("addonDebugging.moreInfo")),
+            Strings.GetStringFromName("moreInfo")),
           ")"
         ),
         dom.button({
           id: "load-addon-from-file",
           onClick: this.loadAddonFromFile,
         }, Strings.GetStringFromName("loadTemporaryAddon"))
       ),
       AddonsInstallError({ error: this.state.installError }));
--- a/devtools/client/aboutdebugging/components/target-list.js
+++ b/devtools/client/aboutdebugging/components/target-list.js
@@ -14,24 +14,29 @@ const Strings = Services.strings.createB
 const LocaleCompare = (a, b) => {
   return a.name.toLowerCase().localeCompare(b.name.toLowerCase());
 };
 
 module.exports = createClass({
   displayName: "TargetList",
 
   render() {
-    let { client, debugDisabled, targetClass, targets, sort } = this.props;
+    let { client, debugDisabled, error, targetClass, targets, sort } = this.props;
     if (sort) {
       targets = targets.sort(LocaleCompare);
     }
     targets = targets.map(target => {
       return targetClass({ client, target, debugDisabled });
     });
 
+    let content = "";
+    if (error) {
+      content = error;
+    } else if (targets.length > 0) {
+      content = dom.ul({ className: "target-list" }, targets);
+    } else {
+      content = dom.p(null, Strings.GetStringFromName("nothing"));
+    }
+
     return dom.div({ id: this.props.id, className: "targets" },
-      dom.h2(null, this.props.name),
-      targets.length > 0 ?
-        dom.ul({ className: "target-list" }, targets) :
-        dom.p(null, Strings.GetStringFromName("nothing"))
-    );
+      dom.h2(null, this.props.name), content);
   },
 });
--- a/devtools/client/aboutdebugging/components/workers/panel.js
+++ b/devtools/client/aboutdebugging/components/workers/panel.js
@@ -1,29 +1,33 @@
 /* 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/. */
+/* globals window */
+"use strict";
 
-"use strict";
+loader.lazyImporter(this, "PrivateBrowsingUtils",
+  "resource://gre/modules/PrivateBrowsingUtils.jsm");
 
 const { Ci } = require("chrome");
 const { createClass, createFactory, DOM: dom } =
   require("devtools/client/shared/vendor/react");
 const { getWorkerForms } = require("../../modules/worker");
 const Services = require("Services");
 
 const PanelHeader = createFactory(require("../panel-header"));
 const TargetList = createFactory(require("../target-list"));
 const WorkerTarget = createFactory(require("./target"));
 const ServiceWorkerTarget = createFactory(require("./service-worker-target"));
 
 const Strings = Services.strings.createBundle(
   "chrome://devtools/locale/aboutdebugging.properties");
 
 const WorkerIcon = "chrome://devtools/skin/images/debugging-workers.svg";
+const MORE_INFO_URL = "https://developer.mozilla.org/en-US/docs/Tools/about%3Adebugging";
 
 module.exports = createClass({
   displayName: "WorkersPanel",
 
   getInitialState() {
     return {
       workers: {
         service: [],
@@ -98,29 +102,45 @@ module.exports = createClass({
       this.setState({ workers });
     });
   },
 
   render() {
     let { client, id } = this.props;
     let { workers } = this.state;
 
+    let isWindowPrivate = PrivateBrowsingUtils.isContentWindowPrivate(window);
+    let isPrivateBrowsingMode = PrivateBrowsingUtils.permanentPrivateBrowsing;
+    let isServiceWorkerDisabled = !Services.prefs
+                                    .getBoolPref("dom.serviceWorkers.enabled");
+    let errorMsg = isWindowPrivate || isPrivateBrowsingMode ||
+           isServiceWorkerDisabled ?
+      dom.p({ className: "service-worker-disabled" },
+        dom.div({ className: "warning" }),
+        Strings.GetStringFromName("configurationIsNotCompatible"),
+        " (",
+        dom.a({ href: MORE_INFO_URL, target: "_blank" },
+          Strings.GetStringFromName("moreInfo")),
+        ")"
+      ) : "";
+
     return dom.div({
       id: id + "-panel",
       className: "panel",
       role: "tabpanel",
       "aria-labelledby": id + "-header"
     },
     PanelHeader({
       id: id + "-header",
       name: Strings.GetStringFromName("workers")
     }),
     dom.div({ id: "workers", className: "inverted-icons" },
       TargetList({
         client,
+        error: errorMsg,
         id: "service-workers",
         name: Strings.GetStringFromName("serviceWorkers"),
         sort: true,
         targetClass: ServiceWorkerTarget,
         targets: workers.service
       }),
       TargetList({
         client,
--- a/devtools/client/aboutdebugging/test/browser.ini
+++ b/devtools/client/aboutdebugging/test/browser.ini
@@ -14,14 +14,15 @@ support-files =
 
 [browser_addons_debug_bootstrapped.js]
 [browser_addons_debugging_initial_state.js]
 [browser_addons_install.js]
 [browser_addons_reload.js]
 [browser_addons_toggle_debug.js]
 [browser_page_not_found.js]
 [browser_service_workers.js]
+[browser_service_workers_not_compatible.js]
 [browser_service_workers_push.js]
 [browser_service_workers_start.js]
 [browser_service_workers_timeout.js]
 skip-if = true # Bug 1232931
 [browser_service_workers_unregister.js]
 [browser_tabs.js]
new file mode 100644
--- /dev/null
+++ b/devtools/client/aboutdebugging/test/browser_service_workers_not_compatible.js
@@ -0,0 +1,60 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test that Service Worker section should show warning message in
+// about:debugging if any of following conditions is met:
+// 1. service worker is disabled
+// 2. the about:debugging pannel is openned in private browsing mode
+// 3. the about:debugging pannel is openned in private content window
+
+var imgClass = ".service-worker-disabled .warning";
+
+add_task(function* () {
+  yield new Promise(done => {
+    info("disable service workers");
+    let options = {"set": [
+      ["dom.serviceWorkers.enabled", false],
+    ]};
+    SpecialPowers.pushPrefEnv(options, done);
+  });
+
+  let { tab, document } = yield openAboutDebugging("workers");
+  // Check that the warning img appears in the UI
+  let img = document.querySelector(imgClass);
+  ok(img, "warning message is rendered");
+
+  yield closeAboutDebugging(tab);
+});
+
+add_task(function* () {
+  yield new Promise(done => {
+    info("set private browsing mode as default");
+    let options = {"set": [
+      ["browser.privatebrowsing.autostart", true],
+    ]};
+    SpecialPowers.pushPrefEnv(options, done);
+  });
+
+  let { tab, document } = yield openAboutDebugging("workers");
+  // Check that the warning img appears in the UI
+  let img = document.querySelector(imgClass);
+  ok(img, "warning message is rendered");
+
+  yield closeAboutDebugging(tab);
+});
+
+add_task(function* () {
+  info("Opening a new private window");
+  let win = OpenBrowserWindow({private: true});
+  yield waitForDelayedStartupFinished(win);
+
+  let { tab, document } = yield openAboutDebugging("workers", win);
+  // Check that the warning img appears in the UI
+  let img = document.querySelector(imgClass);
+  ok(img, "warning message is rendered");
+
+  yield closeAboutDebugging(tab, win);
+  win.close();
+});
--- a/devtools/client/aboutdebugging/test/head.js
+++ b/devtools/client/aboutdebugging/test/head.js
@@ -1,17 +1,18 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 /* eslint-env browser */
 /* eslint-disable mozilla/no-cpows-in-tests */
 /* exported openAboutDebugging, changeAboutDebuggingHash, closeAboutDebugging,
    installAddon, uninstallAddon, waitForMutation, assertHasTarget,
    getServiceWorkerList, getTabList, openPanel, waitForInitialAddonList,
-   waitForServiceWorkerRegistered, unregisterServiceWorker */
+   waitForServiceWorkerRegistered, unregisterServiceWorker,
+   waitForDelayedStartupFinished */
 
 "use strict";
 
 var { utils: Cu, classes: Cc, interfaces: Ci } = Components;
 
 const { require } = Cu.import("resource://devtools/shared/Loader.jsm", {});
 const { AddonManager } = Cu.import("resource://gre/modules/AddonManager.jsm", {});
 const Services = require("Services");
@@ -19,24 +20,24 @@ const DevToolsUtils = require("devtools/
 DevToolsUtils.testing = true;
 
 const CHROME_ROOT = gTestPath.substr(0, gTestPath.lastIndexOf("/") + 1);
 
 registerCleanupFunction(() => {
   DevToolsUtils.testing = false;
 });
 
-function* openAboutDebugging(page) {
+function* openAboutDebugging(page, win) {
   info("opening about:debugging");
   let url = "about:debugging";
   if (page) {
     url += "#" + page;
   }
 
-  let tab = yield addTab(url);
+  let tab = yield addTab(url, win);
   let browser = tab.linkedBrowser;
   let document = browser.contentDocument;
 
   if (!document.querySelector(".app")) {
     yield waitForMutation(document.body, { childList: true });
   }
 
   return { tab, document };
@@ -58,19 +59,19 @@ function changeAboutDebuggingHash(docume
 
 function openPanel(document, panelId) {
   info(`Opening ${panelId} panel`);
   document.querySelector(`[aria-controls="${panelId}"]`).click();
   return waitForMutation(
     document.querySelector(".main-content"), {childList: true});
 }
 
-function closeAboutDebugging(tab) {
+function closeAboutDebugging(tab, win) {
   info("Closing about:debugging");
-  return removeTab(tab);
+  return removeTab(tab, win);
 }
 
 function addTab(url, win, backgroundTab = false) {
   info("Adding tab: " + url);
 
   return new Promise(done => {
     let targetWindow = win || window;
     let targetBrowser = targetWindow.gBrowser;
@@ -291,8 +292,25 @@ function waitForServiceWorkerRegistered(
 function unregisterServiceWorker(tab) {
   return ContentTask.spawn(tab.linkedBrowser, {}, function* () {
     // Retrieve the `sw` promise created in the html page
     let { sw } = content.wrappedJSObject;
     let registration = yield sw;
     yield registration.unregister();
   });
 }
+
+/**
+ * Waits for the creation of a new window, usually used with create private
+ * browsing window.
+ * Returns a promise that will resolve when the window is successfully created.
+ * @param {window} win
+ */
+function waitForDelayedStartupFinished(win) {
+  return new Promise(function (resolve) {
+    Services.obs.addObserver(function observer(subject, topic) {
+      if (win == subject) {
+        Services.obs.removeObserver(observer, topic);
+        resolve();
+      }
+    }, "browser-delayed-startup-finished", false);
+  });
+}
--- a/devtools/client/locales/en-US/aboutdebugging.properties
+++ b/devtools/client/locales/en-US/aboutdebugging.properties
@@ -7,17 +7,17 @@ push = Push
 start = Start
 
 scope = Scope
 unregister = unregister
 
 addons = Add-ons
 addonDebugging.label = Enable add-on debugging
 addonDebugging.tooltip = Turning this on will allow you to debug add-ons and various other parts of the browser chrome
-addonDebugging.moreInfo = more info
+moreInfo = more info
 loadTemporaryAddon = Load Temporary Add-on
 extensions = Extensions
 selectAddonFromFile2 = Select Manifest File or Package (.xpi)
 reload = Reload
 reloadDisabledTooltip = Only temporarily installed add-ons can be reloaded
 
 workers = Workers
 serviceWorkers = Service Workers
@@ -25,8 +25,9 @@ sharedWorkers = Shared Workers
 otherWorkers = Other Workers
 
 tabs = Tabs
 
 pageNotFound = Page not found
 doesNotExist = #%S does not exist!
 
 nothing = Nothing yet.
+configurationIsNotCompatible = Your browser configuration is not compatible with Service Workers