michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: const stateBackup = JSON.parse(ss.getBrowserState()); michael@0: const testState = { michael@0: windows: [{ michael@0: tabs: [ michael@0: { entries: [{ url: "about:blank" }] }, michael@0: { entries: [{ url: "about:rights" }] } michael@0: ] michael@0: }] michael@0: }; michael@0: const lameMultiWindowState = { windows: [ michael@0: { michael@0: tabs: [ michael@0: { entries: [{ url: "http://example.org#1" }], extData: { "uniq": r() } }, michael@0: { entries: [{ url: "http://example.org#2" }], extData: { "uniq": r() } }, michael@0: { entries: [{ url: "http://example.org#3" }], extData: { "uniq": r() } }, michael@0: { entries: [{ url: "http://example.org#4" }], extData: { "uniq": r() } } michael@0: ], michael@0: selected: 1 michael@0: }, michael@0: { michael@0: tabs: [ michael@0: { entries: [{ url: "http://example.com#1" }], extData: { "uniq": r() } }, michael@0: { entries: [{ url: "http://example.com#2" }], extData: { "uniq": r() } }, michael@0: { entries: [{ url: "http://example.com#3" }], extData: { "uniq": r() } }, michael@0: { entries: [{ url: "http://example.com#4" }], extData: { "uniq": r() } }, michael@0: ], michael@0: selected: 3 michael@0: } michael@0: ] }; michael@0: michael@0: michael@0: function getOuterWindowID(aWindow) { michael@0: return aWindow.QueryInterface(Ci.nsIInterfaceRequestor). michael@0: getInterface(Ci.nsIDOMWindowUtils).outerWindowID; michael@0: } michael@0: michael@0: function test() { michael@0: /** Test for Bug 615394 - Session Restore should notify when it is beginning and ending a restore **/ michael@0: waitForExplicitFinish(); michael@0: // Preemptively extend the timeout to prevent [orange] michael@0: requestLongerTimeout(2); michael@0: runNextTest(); michael@0: } michael@0: michael@0: michael@0: let tests = [ michael@0: test_setTabState, michael@0: test_duplicateTab, michael@0: test_undoCloseTab, michael@0: test_setWindowState, michael@0: test_setBrowserState, michael@0: test_undoCloseWindow michael@0: ]; michael@0: function runNextTest() { michael@0: // set an empty state & run the next test, or finish michael@0: if (tests.length) { michael@0: // Enumerate windows and close everything but our primary window. We can't michael@0: // use waitForFocus() because apparently it's buggy. See bug 599253. michael@0: var windowsEnum = Services.wm.getEnumerator("navigator:browser"); michael@0: while (windowsEnum.hasMoreElements()) { michael@0: var currentWindow = windowsEnum.getNext(); michael@0: if (currentWindow != window) { michael@0: currentWindow.close(); michael@0: } michael@0: } michael@0: michael@0: // If we closed a window, give it time to close michael@0: executeSoon(function() { michael@0: let currentTest = tests.shift(); michael@0: info("prepping for " + currentTest.name); michael@0: waitForBrowserState(testState, currentTest); michael@0: }); michael@0: } michael@0: else { michael@0: waitForBrowserState(stateBackup, finish); michael@0: } michael@0: } michael@0: michael@0: /** ACTUAL TESTS **/ michael@0: michael@0: function test_setTabState() { michael@0: let tab = gBrowser.tabs[1]; michael@0: let newTabState = JSON.stringify({ entries: [{ url: "http://example.org" }], extData: { foo: "bar" } }); michael@0: let busyEventCount = 0; michael@0: let readyEventCount = 0; michael@0: michael@0: function onSSWindowStateBusy(aEvent) { michael@0: busyEventCount++; michael@0: } michael@0: michael@0: function onSSWindowStateReady(aEvent) { michael@0: readyEventCount++; michael@0: is(ss.getTabValue(tab, "foo"), "bar"); michael@0: ss.setTabValue(tab, "baz", "qux"); michael@0: } michael@0: michael@0: function onSSTabRestored(aEvent) { michael@0: is(busyEventCount, 1); michael@0: is(readyEventCount, 1); michael@0: is(ss.getTabValue(tab, "baz"), "qux"); michael@0: is(tab.linkedBrowser.currentURI.spec, "http://example.org/"); michael@0: michael@0: window.removeEventListener("SSWindowStateBusy", onSSWindowStateBusy, false); michael@0: window.removeEventListener("SSWindowStateReady", onSSWindowStateReady, false); michael@0: gBrowser.tabContainer.removeEventListener("SSTabRestored", onSSTabRestored, false); michael@0: michael@0: runNextTest(); michael@0: } michael@0: michael@0: window.addEventListener("SSWindowStateBusy", onSSWindowStateBusy, false); michael@0: window.addEventListener("SSWindowStateReady", onSSWindowStateReady, false); michael@0: gBrowser.tabContainer.addEventListener("SSTabRestored", onSSTabRestored, false); michael@0: ss.setTabState(tab, newTabState); michael@0: } michael@0: michael@0: michael@0: function test_duplicateTab() { michael@0: let tab = gBrowser.tabs[1]; michael@0: let busyEventCount = 0; michael@0: let readyEventCount = 0; michael@0: let newTab; michael@0: michael@0: // We'll look to make sure this value is on the duplicated tab michael@0: ss.setTabValue(tab, "foo", "bar"); michael@0: michael@0: function onSSWindowStateBusy(aEvent) { michael@0: busyEventCount++; michael@0: } michael@0: michael@0: function onSSWindowStateReady(aEvent) { michael@0: newTab = gBrowser.tabs[2]; michael@0: readyEventCount++; michael@0: is(ss.getTabValue(newTab, "foo"), "bar"); michael@0: ss.setTabValue(newTab, "baz", "qux"); michael@0: } michael@0: michael@0: function onSSTabRestored(aEvent) { michael@0: is(busyEventCount, 1); michael@0: is(readyEventCount, 1); michael@0: is(ss.getTabValue(newTab, "baz"), "qux"); michael@0: is(newTab.linkedBrowser.currentURI.spec, "about:rights"); michael@0: michael@0: window.removeEventListener("SSWindowStateBusy", onSSWindowStateBusy, false); michael@0: window.removeEventListener("SSWindowStateReady", onSSWindowStateReady, false); michael@0: gBrowser.tabContainer.removeEventListener("SSTabRestored", onSSTabRestored, false); michael@0: michael@0: runNextTest(); michael@0: } michael@0: michael@0: window.addEventListener("SSWindowStateBusy", onSSWindowStateBusy, false); michael@0: window.addEventListener("SSWindowStateReady", onSSWindowStateReady, false); michael@0: gBrowser.tabContainer.addEventListener("SSTabRestored", onSSTabRestored, false); michael@0: michael@0: newTab = ss.duplicateTab(window, tab); michael@0: } michael@0: michael@0: michael@0: function test_undoCloseTab() { michael@0: let tab = gBrowser.tabs[1], michael@0: busyEventCount = 0, michael@0: readyEventCount = 0, michael@0: reopenedTab; michael@0: michael@0: ss.setTabValue(tab, "foo", "bar"); michael@0: michael@0: function onSSWindowStateBusy(aEvent) { michael@0: busyEventCount++; michael@0: } michael@0: michael@0: function onSSWindowStateReady(aEvent) { michael@0: reopenedTab = gBrowser.tabs[1]; michael@0: readyEventCount++; michael@0: is(ss.getTabValue(reopenedTab, "foo"), "bar"); michael@0: ss.setTabValue(reopenedTab, "baz", "qux"); michael@0: } michael@0: michael@0: function onSSTabRestored(aEvent) { michael@0: is(busyEventCount, 1); michael@0: is(readyEventCount, 1); michael@0: is(ss.getTabValue(reopenedTab, "baz"), "qux"); michael@0: is(reopenedTab.linkedBrowser.currentURI.spec, "about:rights"); michael@0: michael@0: window.removeEventListener("SSWindowStateBusy", onSSWindowStateBusy, false); michael@0: window.removeEventListener("SSWindowStateReady", onSSWindowStateReady, false); michael@0: gBrowser.tabContainer.removeEventListener("SSTabRestored", onSSTabRestored, false); michael@0: michael@0: runNextTest(); michael@0: } michael@0: michael@0: window.addEventListener("SSWindowStateBusy", onSSWindowStateBusy, false); michael@0: window.addEventListener("SSWindowStateReady", onSSWindowStateReady, false); michael@0: gBrowser.tabContainer.addEventListener("SSTabRestored", onSSTabRestored, false); michael@0: michael@0: gBrowser.removeTab(tab); michael@0: reopenedTab = ss.undoCloseTab(window, 0); michael@0: } michael@0: michael@0: michael@0: function test_setWindowState() { michael@0: let testState = { michael@0: windows: [{ michael@0: tabs: [ michael@0: { entries: [{ url: "about:mozilla" }], extData: { "foo": "bar" } }, michael@0: { entries: [{ url: "http://example.org" }], extData: { "baz": "qux" } } michael@0: ] michael@0: }] michael@0: }; michael@0: michael@0: let busyEventCount = 0, michael@0: readyEventCount = 0, michael@0: tabRestoredCount = 0; michael@0: michael@0: function onSSWindowStateBusy(aEvent) { michael@0: busyEventCount++; michael@0: } michael@0: michael@0: function onSSWindowStateReady(aEvent) { michael@0: readyEventCount++; michael@0: is(ss.getTabValue(gBrowser.tabs[0], "foo"), "bar"); michael@0: is(ss.getTabValue(gBrowser.tabs[1], "baz"), "qux"); michael@0: } michael@0: michael@0: function onSSTabRestored(aEvent) { michael@0: if (++tabRestoredCount < 2) michael@0: return; michael@0: michael@0: is(busyEventCount, 1); michael@0: is(readyEventCount, 1); michael@0: is(gBrowser.tabs[0].linkedBrowser.currentURI.spec, "about:mozilla"); michael@0: is(gBrowser.tabs[1].linkedBrowser.currentURI.spec, "http://example.org/"); michael@0: michael@0: window.removeEventListener("SSWindowStateBusy", onSSWindowStateBusy, false); michael@0: window.removeEventListener("SSWindowStateReady", onSSWindowStateReady, false); michael@0: gBrowser.tabContainer.removeEventListener("SSTabRestored", onSSTabRestored, false); michael@0: michael@0: runNextTest(); michael@0: } michael@0: michael@0: window.addEventListener("SSWindowStateBusy", onSSWindowStateBusy, false); michael@0: window.addEventListener("SSWindowStateReady", onSSWindowStateReady, false); michael@0: gBrowser.tabContainer.addEventListener("SSTabRestored", onSSTabRestored, false); michael@0: michael@0: ss.setWindowState(window, JSON.stringify(testState), true); michael@0: } michael@0: michael@0: michael@0: function test_setBrowserState() { michael@0: // We'll track events per window so we are sure that they are each happening once michael@0: // pre window. michael@0: let windowEvents = {}; michael@0: windowEvents[getOuterWindowID(window)] = { busyEventCount: 0, readyEventCount: 0 }; michael@0: michael@0: // waitForBrowserState does it's own observing for windows, but doesn't attach michael@0: // the listeners we want here, so do it ourselves. michael@0: let newWindow; michael@0: function windowObserver(aSubject, aTopic, aData) { michael@0: if (aTopic == "domwindowopened") { michael@0: newWindow = aSubject.QueryInterface(Ci.nsIDOMWindow); michael@0: newWindow.addEventListener("load", function() { michael@0: newWindow.removeEventListener("load", arguments.callee, false); michael@0: michael@0: Services.ww.unregisterNotification(windowObserver); michael@0: michael@0: windowEvents[getOuterWindowID(newWindow)] = { busyEventCount: 0, readyEventCount: 0 }; michael@0: michael@0: newWindow.addEventListener("SSWindowStateBusy", onSSWindowStateBusy, false); michael@0: newWindow.addEventListener("SSWindowStateReady", onSSWindowStateReady, false); michael@0: }, false); michael@0: } michael@0: } michael@0: michael@0: function onSSWindowStateBusy(aEvent) { michael@0: windowEvents[getOuterWindowID(aEvent.originalTarget)].busyEventCount++; michael@0: } michael@0: michael@0: function onSSWindowStateReady(aEvent) { michael@0: windowEvents[getOuterWindowID(aEvent.originalTarget)].readyEventCount++; michael@0: } michael@0: michael@0: window.addEventListener("SSWindowStateBusy", onSSWindowStateBusy, false); michael@0: window.addEventListener("SSWindowStateReady", onSSWindowStateReady, false); michael@0: Services.ww.registerNotification(windowObserver); michael@0: michael@0: waitForBrowserState(lameMultiWindowState, function() { michael@0: let checkedWindows = 0; michael@0: for (let id of Object.keys(windowEvents)) { michael@0: let winEvents = windowEvents[id]; michael@0: is(winEvents.busyEventCount, 1, michael@0: "[test_setBrowserState] window" + id + " busy event count correct"); michael@0: is(winEvents.readyEventCount, 1, michael@0: "[test_setBrowserState] window" + id + " ready event count correct"); michael@0: checkedWindows++; michael@0: } michael@0: is(checkedWindows, 2, michael@0: "[test_setBrowserState] checked 2 windows"); michael@0: window.removeEventListener("SSWindowStateBusy", onSSWindowStateBusy, false); michael@0: window.removeEventListener("SSWindowStateReady", onSSWindowStateReady, false); michael@0: newWindow.removeEventListener("SSWindowStateBusy", onSSWindowStateBusy, false); michael@0: newWindow.removeEventListener("SSWindowStateReady", onSSWindowStateReady, false); michael@0: runNextTest(); michael@0: }); michael@0: } michael@0: michael@0: michael@0: function test_undoCloseWindow() { michael@0: let newWindow, reopenedWindow; michael@0: michael@0: function firstWindowObserver(aSubject, aTopic, aData) { michael@0: if (aTopic == "domwindowopened") { michael@0: newWindow = aSubject.QueryInterface(Ci.nsIDOMWindow); michael@0: Services.ww.unregisterNotification(firstWindowObserver); michael@0: } michael@0: } michael@0: Services.ww.registerNotification(firstWindowObserver); michael@0: michael@0: waitForBrowserState(lameMultiWindowState, function() { michael@0: // Close the window which isn't window michael@0: newWindow.close(); michael@0: // Now give it time to close michael@0: executeSoon(function() { michael@0: reopenedWindow = ss.undoCloseWindow(0); michael@0: reopenedWindow.addEventListener("SSWindowStateBusy", onSSWindowStateBusy, false); michael@0: reopenedWindow.addEventListener("SSWindowStateReady", onSSWindowStateReady, false); michael@0: michael@0: reopenedWindow.addEventListener("load", function() { michael@0: reopenedWindow.removeEventListener("load", arguments.callee, false); michael@0: michael@0: reopenedWindow.gBrowser.tabContainer.addEventListener("SSTabRestored", onSSTabRestored, false); michael@0: }, false); michael@0: }); michael@0: }); michael@0: michael@0: let busyEventCount = 0, michael@0: readyEventCount = 0, michael@0: tabRestoredCount = 0; michael@0: // These will listen to the reopened closed window... michael@0: function onSSWindowStateBusy(aEvent) { michael@0: busyEventCount++; michael@0: } michael@0: michael@0: function onSSWindowStateReady(aEvent) { michael@0: readyEventCount++; michael@0: } michael@0: michael@0: function onSSTabRestored(aEvent) { michael@0: if (++tabRestoredCount < 4) michael@0: return; michael@0: michael@0: is(busyEventCount, 1); michael@0: is(readyEventCount, 1); michael@0: michael@0: reopenedWindow.removeEventListener("SSWindowStateBusy", onSSWindowStateBusy, false); michael@0: reopenedWindow.removeEventListener("SSWindowStateReady", onSSWindowStateReady, false); michael@0: reopenedWindow.gBrowser.tabContainer.removeEventListener("SSTabRestored", onSSTabRestored, false); michael@0: michael@0: reopenedWindow.close(); michael@0: michael@0: // Give it time to close michael@0: executeSoon(runNextTest); michael@0: } michael@0: }