michael@0: // Utilities for running tests in an e10s environment. michael@0: michael@0: // There are some tricks/shortcuts that test code takes that we don't see michael@0: // in the real browser code. These include setting content.location.href michael@0: // (which doesn't work in test code with e10s enabled as the document object michael@0: // is yet to be created), waiting for certain events the main browser doesn't michael@0: // care about and so doesn't normally get special support, eg, the "pageshow" michael@0: // or "load" events). michael@0: // So we make some hacks to pretend these work in the test suite. michael@0: michael@0: // Ideally all these hacks could be removed, but this can only happen when michael@0: // the tests are refactored to not use these tricks. But this would be a huge michael@0: // amount of work and is unlikely to happen anytime soon... michael@0: michael@0: const CONTENT_URL = "chrome://mochikit/content/mochitest-e10s-utils-content.js"; michael@0: michael@0: // This is an object that is used as the "location" on a remote document or michael@0: // window. It will be overwritten as the real document and window are made michael@0: // available. michael@0: let locationStub = function(browser) { michael@0: this.browser = browser; michael@0: }; michael@0: locationStub.prototype = { michael@0: get href() { michael@0: return this.browser.webNavigation.currentURI.spec; michael@0: }, michael@0: set href(val) { michael@0: this.browser.loadURI(val); michael@0: }, michael@0: assign: function(url) { michael@0: this.href = url; michael@0: } michael@0: }; michael@0: michael@0: // This object is used in place of contentWindow while we wait for it to be michael@0: // overwritten as the real window becomes available. michael@0: let TemporaryWindowStub = function(browser) { michael@0: this._locationStub = new locationStub(browser); michael@0: }; michael@0: michael@0: TemporaryWindowStub.prototype = { michael@0: // save poor developers from getting confused about why the window isn't michael@0: // working like a window should.. michael@0: toString: function() { michael@0: return "[Window Stub for e10s tests]"; michael@0: }, michael@0: get location() { michael@0: return this._locationStub; michael@0: }, michael@0: set location(val) { michael@0: this._locationStub.href = val; michael@0: }, michael@0: get document() { michael@0: // so tests can say: document.location.... michael@0: return this; michael@0: } michael@0: }; michael@0: michael@0: // An observer called when a new remote browser element is created. We replace michael@0: // the _contentWindow in new browsers with our TemporaryWindowStub object. michael@0: function observeNewFrameloader(subject, topic, data) { michael@0: let browser = subject.QueryInterface(Ci.nsIFrameLoader).ownerElement; michael@0: browser._contentWindow = new TemporaryWindowStub(browser); michael@0: } michael@0: michael@0: function e10s_init() { michael@0: // Use the global message manager to inject a content script into all browsers. michael@0: let globalMM = Cc["@mozilla.org/globalmessagemanager;1"] michael@0: .getService(Ci.nsIMessageListenerManager); michael@0: globalMM.loadFrameScript(CONTENT_URL, true); michael@0: globalMM.addMessageListener("Test:Event", function(message) { michael@0: let event = document.createEvent('HTMLEvents'); michael@0: event.initEvent(message.data.name, true, true, {}); michael@0: message.target.dispatchEvent(event); michael@0: }); michael@0: michael@0: // We add an observer so we can notice new elements created michael@0: Services.obs.addObserver(observeNewFrameloader, "remote-browser-shown", false); michael@0: michael@0: // Listen for an 'oop-browser-crashed' event and log it so people analysing michael@0: // test logs have a clue about what is going on. michael@0: window.addEventListener("oop-browser-crashed", (event) => { michael@0: let uri = event.target.currentURI; michael@0: Cu.reportError("remote browser crashed while on " + michael@0: (uri ? uri.spec : "") + "\n"); michael@0: }, true); michael@0: }