michael@0: michael@0: let Cu = Components.utils; michael@0: let Cc = Components.classes; michael@0: let Ci = Components.interfaces; michael@0: michael@0: const URL1 = MAIN_DOMAIN + "navigate-first.html"; michael@0: const URL2 = MAIN_DOMAIN + "navigate-second.html"; michael@0: michael@0: let { DebuggerClient } = Cu.import("resource://gre/modules/devtools/dbg-client.jsm", {}); michael@0: let { DebuggerServer } = Cu.import("resource://gre/modules/devtools/dbg-server.jsm", {}); michael@0: michael@0: let devtools = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools; michael@0: let events = devtools.require("sdk/event/core"); michael@0: michael@0: let client; michael@0: michael@0: // State machine to check events order michael@0: let i = 0; michael@0: function assertEvent(event, data) { michael@0: let x = 0; michael@0: switch(i++) { michael@0: case x++: michael@0: is(event, "request", "Get first page load"); michael@0: is(data, URL1); michael@0: break; michael@0: case x++: michael@0: is(event, "load-new-document", "Ask to load the second page"); michael@0: break; michael@0: case x++: michael@0: is(event, "unload-dialog", "We get the dialog on first page unload"); michael@0: break; michael@0: case x++: michael@0: is(event, "will-navigate", "The very first event is will-navigate on server side"); michael@0: is(data.newURI, URL2, "newURI property is correct"); michael@0: break; michael@0: case x++: michael@0: is(event, "tabNavigated", "Right after will-navigate, the client receive tabNavigated"); michael@0: is(data.state, "start", "state is start"); michael@0: is(data.url, URL2, "url property is correct"); michael@0: break; michael@0: case x++: michael@0: is(event, "request", "Given that locally, the Debugger protocol is sync, the request happens after tabNavigated"); michael@0: is(data, URL2); michael@0: break; michael@0: case x++: michael@0: is(event, "DOMContentLoaded"); michael@0: is(content.document.readyState, "interactive"); michael@0: break; michael@0: case x++: michael@0: is(event, "load"); michael@0: is(content.document.readyState, "complete"); michael@0: break; michael@0: case x++: michael@0: is(event, "navigate", "Then once the second doc is loaded, we get the navigate event"); michael@0: is(content.document.readyState, "complete", "navigate is emitted only once the document is fully loaded"); michael@0: break; michael@0: case x++: michael@0: is(event, "tabNavigated", "Finally, the receive the client event"); michael@0: is(data.state, "stop", "state is stop"); michael@0: is(data.url, URL2, "url property is correct"); michael@0: michael@0: // End of test! michael@0: cleanup(); michael@0: break; michael@0: } michael@0: } michael@0: michael@0: function waitForOnBeforeUnloadDialog(browser, callback) { michael@0: browser.addEventListener("DOMWillOpenModalDialog", function onModalDialog() { michael@0: browser.removeEventListener("DOMWillOpenModalDialog", onModalDialog, true); michael@0: michael@0: executeSoon(() => { michael@0: let stack = browser.parentNode; michael@0: let dialogs = stack.getElementsByTagName("tabmodalprompt"); michael@0: let {button0, button1} = dialogs[0].ui; michael@0: callback(button0, button1); michael@0: }); michael@0: }, true); michael@0: } michael@0: michael@0: let httpObserver = function (subject, topic, state) { michael@0: let channel = subject.QueryInterface(Ci.nsIHttpChannel); michael@0: let url = channel.URI.spec; michael@0: // Only listen for our document request, as many other requests can happen michael@0: if (url == URL1 || url == URL2) { michael@0: assertEvent("request", url); michael@0: } michael@0: }; michael@0: Services.obs.addObserver(httpObserver, "http-on-modify-request", false); michael@0: michael@0: function onDOMContentLoaded() { michael@0: assertEvent("DOMContentLoaded"); michael@0: } michael@0: function onLoad() { michael@0: assertEvent("load"); michael@0: } michael@0: michael@0: function getServerTabActor(callback) { michael@0: // Ensure having a minimal server michael@0: if (!DebuggerServer.initialized) { michael@0: DebuggerServer.init(function () { return true; }); michael@0: DebuggerServer.addBrowserActors(); michael@0: } michael@0: michael@0: // Connect to this tab michael@0: let transport = DebuggerServer.connectPipe(); michael@0: client = new DebuggerClient(transport); michael@0: client.connect(function onConnect() { michael@0: client.listTabs(function onListTabs(aResponse) { michael@0: // Fetch the BrowserTabActor for this tab michael@0: let actorID = aResponse.tabs[aResponse.selected].actor; michael@0: client.attachTab(actorID, function(aResponse, aTabClient) { michael@0: // !Hack! Retrieve a server side object, the BrowserTabActor instance michael@0: let conn = transport._serverConnection; michael@0: let tabActor = conn.getActor(actorID); michael@0: callback(tabActor); michael@0: }); michael@0: }); michael@0: }); michael@0: michael@0: client.addListener("tabNavigated", function (aEvent, aPacket) { michael@0: assertEvent("tabNavigated", aPacket); michael@0: }); michael@0: } michael@0: michael@0: function test() { michael@0: waitForExplicitFinish(); michael@0: michael@0: // Open a test tab michael@0: addTab(URL1, function(doc) { michael@0: getServerTabActor(function (tabActor) { michael@0: // In order to listen to internal will-navigate/navigate events michael@0: events.on(tabActor, "will-navigate", function (data) { michael@0: assertEvent("will-navigate", data); michael@0: }); michael@0: events.on(tabActor, "navigate", function (data) { michael@0: assertEvent("navigate", data); michael@0: }); michael@0: michael@0: // Start listening for page load events michael@0: let browser = gBrowser.selectedTab.linkedBrowser; michael@0: browser.addEventListener("DOMContentLoaded", onDOMContentLoaded, true); michael@0: browser.addEventListener("load", onLoad, true); michael@0: michael@0: // Listen for alert() call being made in navigate-first during unload michael@0: waitForOnBeforeUnloadDialog(browser, function (btnLeave, btnStay) { michael@0: assertEvent("unload-dialog"); michael@0: // accept to quit this page to another michael@0: btnLeave.click(); michael@0: }); michael@0: michael@0: // Load another document in this doc to dispatch these events michael@0: assertEvent("load-new-document"); michael@0: content.location = URL2; michael@0: }); michael@0: michael@0: }); michael@0: } michael@0: michael@0: function cleanup() { michael@0: let browser = gBrowser.selectedTab.linkedBrowser; michael@0: browser.removeEventListener("DOMContentLoaded", onDOMContentLoaded); michael@0: browser.removeEventListener("load", onLoad); michael@0: client.close(function () { michael@0: Services.obs.addObserver(httpObserver, "http-on-modify-request", false); michael@0: DebuggerServer.destroy(); michael@0: finish(); michael@0: }); michael@0: }