michael@0: const Cu = Components.utils; michael@0: michael@0: const { Services } = Cu.import("resource://gre/modules/Services.jsm"); michael@0: michael@0: // Load a duplicated copy of the jsm to prevent messing with the currently running one michael@0: let scope = {}; michael@0: Services.scriptloader.loadSubScript("resource://gre/modules/SystemAppProxy.jsm", scope); michael@0: const { SystemAppProxy } = scope; michael@0: michael@0: let frame; michael@0: michael@0: let index = -1; michael@0: function next() { michael@0: index++; michael@0: if (index >= steps.length) { michael@0: assert.ok(false, "Shouldn't get here!"); michael@0: return; michael@0: } michael@0: try { michael@0: steps[index](); michael@0: } catch(ex) { michael@0: assert.ok(false, "Caught exception: " + ex); michael@0: } michael@0: } michael@0: michael@0: // Listen for events received by the system app document michael@0: // to ensure that we receive all of them, in an expected order and time michael@0: let isLoaded = false; michael@0: let n = 0; michael@0: function listener(event) { michael@0: if (!isLoaded) { michael@0: assert.ok(false, "Received event before the iframe is ready"); michael@0: return; michael@0: } michael@0: n++; michael@0: if (n == 1) { michael@0: assert.equal(event.type, "mozChromeEvent"); michael@0: assert.equal(event.detail.name, "first"); michael@0: } else if (n == 2) { michael@0: assert.equal(event.type, "custom"); michael@0: assert.equal(event.detail.name, "second"); michael@0: michael@0: next(); // call checkEventDispatching michael@0: } else if (n == 3) { michael@0: assert.equal(event.type, "custom"); michael@0: assert.equal(event.detail.name, "third"); michael@0: } else if (n == 4) { michael@0: assert.equal(event.type, "mozChromeEvent"); michael@0: assert.equal(event.detail.name, "fourth"); michael@0: michael@0: next(); // call checkEventListening(); michael@0: } else { michael@0: assert.ok(false, "Unexpected event of type " + event.type); michael@0: } michael@0: } michael@0: michael@0: michael@0: let steps = [ michael@0: function waitForWebapps() { michael@0: // We are using webapps API later in this test and we need to ensure michael@0: // it is fully initialized before trying to use it michael@0: let { DOMApplicationRegistry } = Cu.import('resource://gre/modules/Webapps.jsm', {}); michael@0: DOMApplicationRegistry.registryReady.then(function () { michael@0: next(); michael@0: }); michael@0: }, michael@0: michael@0: function earlyEvents() { michael@0: // Immediately try to send events michael@0: SystemAppProxy.dispatchEvent({ name: "first" }); michael@0: SystemAppProxy._sendCustomEvent("custom", { name: "second" }); michael@0: next(); michael@0: }, michael@0: michael@0: function createFrame() { michael@0: // Create a fake system app frame michael@0: let win = Services.wm.getMostRecentWindow("navigator:browser"); michael@0: let doc = win.document; michael@0: frame = doc.createElement("iframe"); michael@0: doc.documentElement.appendChild(frame); michael@0: michael@0: // Ensure that events are correctly sent to the frame. michael@0: // `listener` is going to call next() michael@0: frame.contentWindow.addEventListener("mozChromeEvent", listener); michael@0: frame.contentWindow.addEventListener("custom", listener); michael@0: michael@0: // Ensure that listener being registered before the system app is ready michael@0: // are correctly removed from the pending list michael@0: function removedListener() { michael@0: assert(false, "Listener isn't correctly removed from the pending list"); michael@0: } michael@0: SystemAppProxy.addEventListener("mozChromeEvent", removedListener); michael@0: SystemAppProxy.removeEventListener("mozChromeEvent", removedListener); michael@0: michael@0: // Register it to the JSM michael@0: SystemAppProxy.registerFrame(frame); michael@0: assert.ok(true, "Frame created and registered"); michael@0: michael@0: frame.contentWindow.addEventListener("load", function onload() { michael@0: frame.contentWindow.removeEventListener("load", onload); michael@0: assert.ok(true, "Frame document loaded"); michael@0: michael@0: // Declare that the iframe is now loaded. michael@0: // That should dispatch early events michael@0: isLoaded = true; michael@0: SystemAppProxy.setIsReady(); michael@0: assert.ok(true, "Frame declared as loaded"); michael@0: michael@0: // Once pending events are received, michael@0: // we will run checkEventDispatching from `listener` function michael@0: }); michael@0: michael@0: frame.setAttribute("src", "data:text/html,system app"); michael@0: }, michael@0: michael@0: function checkEventDispatching() { michael@0: // Send events after the iframe is ready, michael@0: // they should be dispatched right away michael@0: SystemAppProxy._sendCustomEvent("custom", { name: "third" }); michael@0: SystemAppProxy.dispatchEvent({ name: "fourth" }); michael@0: // Once this 4th event is received, we will run checkEventListening michael@0: }, michael@0: michael@0: function checkEventListening() { michael@0: SystemAppProxy.addEventListener("mozContentEvent", function onContentEvent(event) { michael@0: assert.equal(event.detail.name, "first-content", "received a system app event"); michael@0: SystemAppProxy.removeEventListener("mozContentEvent", onContentEvent); michael@0: michael@0: next(); michael@0: }); michael@0: let win = frame.contentWindow; michael@0: win.dispatchEvent(new win.CustomEvent("mozContentEvent", { detail: {name: "first-content"} })); michael@0: }, michael@0: michael@0: function endOfTest() { michael@0: frame.remove(); michael@0: sendAsyncMessage("finish"); michael@0: } michael@0: ]; michael@0: michael@0: next();