diff --git a/devtools/client/aboutdebugging/components/target-list.js b/devtools/client/aboutdebugging/components/target-list.js index 81886046b84f..6fcf9c34cd2e 100644 --- a/devtools/client/aboutdebugging/components/target-list.js +++ b/devtools/client/aboutdebugging/components/target-list.js @@ -27,7 +27,7 @@ exports.TargetListComponent = React.createClass({ return React.createElement(TargetComponent, { client, target }); }); return ( - React.createElement("div", { className: "targets" }, + React.createElement("div", { id: this.props.id, className: "targets" }, React.createElement("h4", null, this.props.name), targets.length > 0 ? targets : React.createElement("p", null, Strings.GetStringFromName("nothing")) diff --git a/devtools/client/aboutdebugging/components/workers.js b/devtools/client/aboutdebugging/components/workers.js index 628a8f93e7ab..87c4578e2991 100644 --- a/devtools/client/aboutdebugging/components/workers.js +++ b/devtools/client/aboutdebugging/components/workers.js @@ -14,6 +14,8 @@ loader.lazyRequireGetter(this, "TargetListComponent", "devtools/client/aboutdebugging/components/target-list", true); loader.lazyRequireGetter(this, "Services"); +loader.lazyImporter(this, "Task", "resource://gre/modules/Task.jsm"); + const Strings = Services.strings.createBundle( "chrome://devtools/locale/aboutdebugging.properties"); const WorkerIcon = "chrome://devtools/skin/images/debugging-workers.svg"; @@ -32,12 +34,16 @@ exports.WorkersComponent = React.createClass({ }, componentDidMount() { - this.props.client.addListener("workerListChanged", this.update); + let client = this.props.client; + client.addListener("workerListChanged", this.update); + client.addListener("processListChanged", this.update); this.update(); }, componentWillUnmount() { - this.props.client.removeListener("workerListChanged", this.update); + let client = this.props.client; + client.removeListener("processListChanged", this.update); + client.removeListener("workerListChanged", this.update); }, render() { @@ -45,22 +51,23 @@ exports.WorkersComponent = React.createClass({ let workers = this.state.workers; return React.createElement("div", { className: "inverted-icons" }, React.createElement(TargetListComponent, { + id: "service-workers", name: Strings.GetStringFromName("serviceWorkers"), targets: workers.service, client }), React.createElement(TargetListComponent, { + id: "shared-workers", name: Strings.GetStringFromName("sharedWorkers"), targets: workers.shared, client }), React.createElement(TargetListComponent, { + id: "other-workers", name: Strings.GetStringFromName("otherWorkers"), targets: workers.other, client }) ); }, update() { - let client = this.props.client; let workers = this.getInitialState().workers; - client.mainRoot.listWorkers(response => { - let forms = response.workers; + this.getWorkerForms().then(forms => { forms.forEach(form => { let worker = { name: form.url, @@ -83,5 +90,29 @@ exports.WorkersComponent = React.createClass({ }); this.setState({ workers }); }); - } + }, + + getWorkerForms: Task.async(function*() { + let client = this.props.client; + + // List workers from the Parent process + let result = yield client.mainRoot.listWorkers(); + let forms = result.workers; + + // And then from the Child processes + let { processes } = yield client.mainRoot.listProcesses(); + for (let process of processes) { + // Ignore parent process + if (process.parent) { + continue; + } + let { form } = yield client.getProcess(process.id); + let processActor = form.actor; + let { workers } = yield client.request({to: processActor, + type: "listWorkers"}); + forms = forms.concat(workers); + } + + return forms; + }), }); diff --git a/devtools/client/aboutdebugging/test/browser.ini b/devtools/client/aboutdebugging/test/browser.ini index 64d323388833..7308c9517629 100644 --- a/devtools/client/aboutdebugging/test/browser.ini +++ b/devtools/client/aboutdebugging/test/browser.ini @@ -5,5 +5,8 @@ support-files = head.js addons/unpacked/bootstrap.js addons/unpacked/install.rdf + service-workers/empty-sw.html + service-workers/empty-sw.js [browser_addons_install.js] +[browser_service_workers.js] diff --git a/devtools/client/aboutdebugging/test/browser_service_workers.js b/devtools/client/aboutdebugging/test/browser_service_workers.js new file mode 100644 index 000000000000..fccfeefb9040 --- /dev/null +++ b/devtools/client/aboutdebugging/test/browser_service_workers.js @@ -0,0 +1,66 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ +"use strict"; + +// Service workers can't be loaded from chrome://, +// but http:// is ok with dom.serviceWorkers.testing.enabled turned on. +const HTTP_ROOT = CHROME_ROOT.replace("chrome://mochitests/content/", + "http://mochi.test:8888/"); +const SERVICE_WORKER = HTTP_ROOT + "service-workers/empty-sw.js"; +const TAB_URL = HTTP_ROOT + "service-workers/empty-sw.html"; + +function waitForWorkersUpdate(document) { + return new Promise(done => { + var observer = new MutationObserver(function(mutations) { + observer.disconnect(); + done(); + }); + var target = document.getElementById("service-workers"); + observer.observe(target, { childList: true }); + }); +} + +add_task(function *() { + yield new Promise(done => { + let options = {"set": [ + ["dom.serviceWorkers.testing.enabled", true], + ]}; + SpecialPowers.pushPrefEnv(options, done); + }); + + let { tab, document } = yield openAboutDebugging("workers"); + + let swTab = yield addTab(TAB_URL); + + yield waitForWorkersUpdate(document); + + // Check that the service worker appears in the UI + let names = [...document.querySelectorAll("#service-workers .target-name")]; + names = names.map(element => element.textContent); + ok(names.includes(SERVICE_WORKER), "The service worker url appears in the list: " + names); + + // Use message manager to work with e10s + let frameScript = function () { + // Retrieve the `sw` promise created in the html page + let { sw } = content.wrappedJSObject; + sw.then(function (registration) { + registration.unregister().then(function (success) { + dump("SW unregistered: " + success + "\n"); + }, + function (e) { + dump("SW not unregistered; " + e + "\n"); + }); + }); + }; + swTab.linkedBrowser.messageManager.loadFrameScript("data:,(" + encodeURIComponent(frameScript) + ")()", true); + + yield waitForWorkersUpdate(document); + + // Check that the service worker disappeared from the UI + names = [...document.querySelectorAll("#service-workers .target-name")]; + names = names.map(element => element.textContent); + ok(!names.includes(SERVICE_WORKER), "The service worker url is no longer in the list: " + names); + + yield removeTab(swTab); + yield closeAboutDebugging(tab); +}); diff --git a/devtools/client/aboutdebugging/test/head.js b/devtools/client/aboutdebugging/test/head.js index b61bb4dd1b5c..c2722640737e 100644 --- a/devtools/client/aboutdebugging/test/head.js +++ b/devtools/client/aboutdebugging/test/head.js @@ -16,9 +16,13 @@ registerCleanupFunction(() => { DevToolsUtils.testing = false; }); -function openAboutDebugging() { +function openAboutDebugging(page) { info("opening about:debugging"); - return addTab("about:debugging").then(tab => { + let url = "about:debugging"; + if (page) { + url += "#" + page; + } + return addTab(url).then(tab => { let browser = tab.linkedBrowser; return { tab, diff --git a/devtools/client/aboutdebugging/test/service-workers/empty-sw.html b/devtools/client/aboutdebugging/test/service-workers/empty-sw.html new file mode 100644 index 000000000000..d475883f8cea --- /dev/null +++ b/devtools/client/aboutdebugging/test/service-workers/empty-sw.html @@ -0,0 +1,20 @@ + + +
+ +