Bug 625257 - Undo Close Tab does not work for not-yet-loaded tab. r=zpao a=blocking2.0
authorMehdi Mulani <mmmulani@uwaterloo.ca>
Tue, 18 Jan 2011 19:46:16 -0800
changeset 61090 a01589063ec0571339b76e9f7eb137d14997fd0c
parent 61089 599e9b6cd5e5cf56d3b1858b2cb2cbbcc85c090e
child 61091 64c7b8b4e0465f7cc9e89c0785528fa58bc8d504
push idunknown
push userunknown
push dateunknown
reviewerszpao, blocking2
bugs625257
milestone2.0b10pre
Bug 625257 - Undo Close Tab does not work for not-yet-loaded tab. r=zpao a=blocking2.0
browser/components/sessionstore/src/nsSessionStore.js
browser/components/sessionstore/test/browser/Makefile.in
browser/components/sessionstore/test/browser/browser_625257.js
--- a/browser/components/sessionstore/src/nsSessionStore.js
+++ b/browser/components/sessionstore/src/nsSessionStore.js
@@ -1503,16 +1503,17 @@ SessionStoreService.prototype = {
       history = browser.sessionHistory;
     }
     catch (ex) { } // this could happen if we catch a tab during (de)initialization
     
     // XXXzeniko anchor navigation doesn't reset __SS_data, so we could reuse
     //           data even when we shouldn't (e.g. Back, different anchor)
     if (history && browser.__SS_data &&
         browser.__SS_data.entries[history.index] &&
+        browser.__SS_data.entries[history.index].url == browser.currentURI.spec &&
         history.index < this._sessionhistory_max_entries - 1 && !aFullData) {
       tabData = browser.__SS_data;
       tabData.index = history.index + 1;
     }
     else if (history && history.count > 0) {
       for (var j = 0; j < history.count; j++) {
         let entry = this._serializeHistoryEntry(history.getEntryAtIndex(j, false),
                                                 aFullData, aTab.pinned);
--- a/browser/components/sessionstore/test/browser/Makefile.in
+++ b/browser/components/sessionstore/test/browser/Makefile.in
@@ -132,16 +132,17 @@ include $(topsrcdir)/config/rules.mk
 	browser_597315_c1.html \
 	browser_597315_c2.html \
 	browser_600545.js \
 	browser_601955.js \
 	browser_607016.js \
 	browser_615394-SSWindowState_events.js \
 	browser_618151.js \
 	browser_623779.js \
+	browser_625257.js \
 	$(NULL)
 
 ifneq ($(OS_ARCH),Darwin)
 _BROWSER_TEST_FILES += \
 	browser_597071.js \
 	$(NULL)
 endif
 
new file mode 100644
--- /dev/null
+++ b/browser/components/sessionstore/test/browser/browser_625257.js
@@ -0,0 +1,128 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is sessionstore test code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Mehdi Mulani <mmmulani@uwaterloo.ca>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK *****/
+
+// This tests that a tab which is closed while loading is not lost.
+// Specifically, that session store does not rely on an invalid cache when
+// constructing data for a tab which is loading.
+
+let ss = Cc["@mozilla.org/browser/sessionstore;1"].
+         getService(Ci.nsISessionStore);
+
+// The newly created tab which we load a URL into and try closing/undoing.
+let tab;
+
+// |state| tracks the progress of the test in 4 parts:
+// -1: Initial value.
+//  0: Tab has been created is loading URI_TO_LOAD.
+//  1: browser.currentURI has changed and tab is scheduled to be removed.
+//  2: undoCloseTab() has been called, tab should fully load.
+let state = -1;
+const URI_TO_LOAD = "about:home";
+
+function test() {
+  waitForExplicitFinish();
+
+  // We'll be waiting for session stores, so we speed up their rate to ensure
+  // we don't timeout.
+  Services.prefs.setIntPref("browser.sessionstore.interval", 2000);
+
+  gBrowser.addTabsProgressListener(tabsListener);
+
+  waitForSaveState(test_bug625257_1);
+  tab = gBrowser.addTab();
+
+  tab.linkedBrowser.addEventListener("load", onLoad, true);
+
+  gBrowser.tabContainer.addEventListener("TabClose", onTabClose, true);
+}
+
+// First, the newly created blank tab should trigger a save state.
+function test_bug625257_1() {
+  is(gBrowser.tabs[1], tab, "newly created tab should exist by now");
+  ok(tab.linkedBrowser.__SS_data, "newly created tab should be in save state");
+
+  tab.linkedBrowser.loadURI(URI_TO_LOAD);
+  state = 0;
+}
+
+let tabsListener = {
+  onLocationChange: function onLocationChange(aBrowser) {
+    gBrowser.removeTabsProgressListener(tabsListener);
+    is(state, 0, "should be the first listener event");
+    state++;
+
+    // Since we are running in the context of tabs listeners, we do not
+    // want to disrupt other tabs listeners.
+    executeSoon(function() {
+      tab.linkedBrowser.removeEventListener("load", onLoad, true);
+      gBrowser.removeTab(tab);
+    });
+  }
+};
+
+function onTabClose(aEvent) {
+  let uri = aEvent.target.location;
+
+  is(state, 1, "should only remove tab at this point");
+  state++;
+  gBrowser.tabContainer.removeEventListener("TabClose", onTabClose, true);
+
+  executeSoon(function() {
+    tab = ss.undoCloseTab(window, 0);
+    tab.linkedBrowser.addEventListener("load", onLoad, true);
+  });
+}
+
+function onLoad(aEvent) {
+  let uri = aEvent.target.location;
+
+  if (state == 2) {
+    is(uri, URI_TO_LOAD, "should load page from undoCloseTab");
+    done();
+  }
+  else {
+    isnot(uri, URI_TO_LOAD, "should not fully load page");
+  }
+}
+
+function done() {
+  tab.linkedBrowser.removeEventListener("load", onLoad, true);
+  gBrowser.removeTab(gBrowser.tabs[1]);
+  Services.prefs.clearUserPref("browser.sessionstore.interval");
+
+  executeSoon(finish);
+}