Bug 840156 - Inspector doesn't gracefully handle onDOMReady event that fires after the inspector has been destroyed; r=jwalker,paul
authorDavid Creswick <dcrewi@gyrae.net>
Tue, 19 Feb 2013 10:48:05 +0000
changeset 122284 508f98d86cf0092b0ed7bac4827d8d1c4bd296d0
parent 122283 3f0f2fc4bd0f4c9df2061a1ce9fd462a1a86fa4c
child 122285 c1abd2ac8de991286bda842b36c63b0a55ea77c7
push id1364
push userjwalker@mozilla.com
push dateTue, 19 Feb 2013 11:12:22 +0000
treeherderfx-team@53d22797d694 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjwalker, paul
bugs840156
milestone21.0a1
Bug 840156 - Inspector doesn't gracefully handle onDOMReady event that fires after the inspector has been destroyed; r=jwalker,paul
browser/devtools/inspector/InspectorPanel.jsm
browser/devtools/inspector/test/Makefile.in
browser/devtools/inspector/test/browser_inspector_bug_840156_destroy_after_navigation.js
--- a/browser/devtools/inspector/InspectorPanel.jsm
+++ b/browser/devtools/inspector/InspectorPanel.jsm
@@ -237,16 +237,20 @@ InspectorPanel.prototype = {
     this.selection.setNode(null);
     this._destroyMarkup();
     this.isDirty = false;
     let self = this;
 
     function onDOMReady() {
       newWindow.removeEventListener("DOMContentLoaded", onDOMReady, true);
 
+      if (self._destroyed) {
+        return;
+      }
+
       if (!self.selection.node) {
         self.selection.setNode(newWindow.document.documentElement);
       }
       self._initMarkup();
     }
 
     if (newWindow.document.readyState == "loading") {
       newWindow.addEventListener("DOMContentLoaded", onDOMReady, true);
--- a/browser/devtools/inspector/test/Makefile.in
+++ b/browser/devtools/inspector/test/Makefile.in
@@ -33,14 +33,15 @@ include $(topsrcdir)/config/rules.mk
 		browser_inspector_cmd_inspect.js \
 		browser_inspector_cmd_inspect.html \
 		browser_inspector_highlighter_autohide.js \
 		browser_inspector_changes.js \
 		browser_inspector_bug_674871.js \
 		browser_inspector_bug_817558_delete_node.js \
 		browser_inspector_bug_650804_search.js \
 		browser_inspector_bug_650804_search.html \
+		browser_inspector_bug_840156_destroy_after_navigation.js \
 		head.js \
 		helpers.js \
 		$(NULL)
 
 libs::	$(_BROWSER_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/browser/devtools/inspector/test/browser_inspector_bug_840156_destroy_after_navigation.js
@@ -0,0 +1,61 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+let temp = {};
+Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js", temp);
+let Promise = temp.Promise;
+temp = {};
+Cu.import("resource:///modules/devtools/Toolbox.jsm", temp);
+let Toolbox = temp.Toolbox;
+temp = {};
+Cu.import("resource:///modules/devtools/Target.jsm", temp);
+let TargetFactory = temp.TargetFactory;
+temp = null;
+
+function test() {
+  waitForExplicitFinish();
+
+  const URL_1 = "data:text/plain;charset=UTF-8,abcde";
+  const URL_2 = "data:text/plain;charset=UTF-8,12345";
+
+  let target, toolbox;
+
+  // open tab, load URL_1, and wait for load to finish
+  let tab = gBrowser.selectedTab = gBrowser.addTab();
+  let target = TargetFactory.forTab(gBrowser.selectedTab);
+  let deferred = Promise.defer();
+  let browser = gBrowser.getBrowserForTab(tab);
+  function onTabLoad() {
+    browser.removeEventListener("load", onTabLoad, true);
+    deferred.resolve(null);
+  }
+  browser.addEventListener("load", onTabLoad, true);
+  browser.loadURI(URL_1);
+
+  // open devtools panel
+  deferred.promise
+    .then(function () gDevTools.showToolbox(target, null, Toolbox.HostType.BOTTOM))
+    .then(function (aToolbox) { toolbox = aToolbox; })
+
+  // select the inspector
+    .then(function () toolbox.selectTool("inspector"))
+
+  // navigate to URL_2
+    .then(function () {
+      let deferred = Promise.defer();
+      target.once("navigate", function () deferred.resolve());
+      browser.loadURI(URL_2);
+      return deferred.promise;
+    })
+
+  // destroy the toolbox (and hence the inspector) before the load completes
+    .then(function () toolbox.destroy())
+
+  // this (or any other) exception should not occur:
+  // [JavaScript Error: "TypeError: self.selection is null" {file: "resource:///modules/devtools/InspectorPanel.jsm" line: 250}]
+
+    .then(function cleanUp() {
+      gBrowser.removeCurrentTab();
+      finish();
+    });
+}