text: /* Test for Bug 420605
   * https://bugzilla.mozilla.org/show_bug.cgi?id=420605
   */
  
  function test() {
      waitForExplicitFinish();
  
      var pageurl = "http://mochi.test:8888/browser/docshell/test/browser/file_bug420605.html";
      var fragmenturl = "http://mochi.test:8888/browser/docshell/test/browser/file_bug420605.html#firefox";
  
      var historyService = Cc["@mozilla.org/browser/nav-history-service;1"]
                           .getService(Ci.nsINavHistoryService);
  
      /* Queries nsINavHistoryService and returns a single history entry
       * for a given URI */
      function getNavHistoryEntry(aURI) {
          var options = historyService.getNewQueryOptions();
          options.queryType = Ci.nsINavHistoryQueryOptions.QUERY_TYPE_HISTORY;
          options.maxResults = 1;
  
          var query = historyService.getNewQuery();
          query.uri = aURI;
  
          var result = historyService.executeQuery(query, options);
          result.root.containerOpen = true;
  
          if (!result.root.childCount) {
              return null;
          }
          return result.root.getChild(0);
      }
  
      // We'll save the favicon URL of the orignal page here and check that the
      // page with a hash has the same favicon.
      var originalFavicon;
  
      // Control flow in this test is a bit complicated.
      //
      // When the page loads, onPageLoad (the DOMContentLoaded handler) and
      // historyObserver::onPageChanged are both called, in some order.  Once
      // they've both run, we click a fragment link in the content page
      // (clickLinkIfReady), which should trigger another onPageChanged event,
      // this time for the fragment's URL.
  
      var _clickLinkTimes = 0;
      function clickLinkIfReady() {
        _clickLinkTimes++;
        if (_clickLinkTimes == 2) {
          EventUtils.sendMouseEvent({type:'click'}, 'firefox-link',
                                    gBrowser.selectedBrowser.contentWindow);
        }
      }
  
      /* Global history observer that triggers for the two test URLs above. */
      var historyObserver = {
          onBeginUpdateBatch: function() {},
          onEndUpdateBatch: function() {},
          onVisit: function(aURI, aVisitID, aTime, aSessionId, aReferringId,
                            aTransitionType, _added) {},
          onTitleChanged: function(aURI, aPageTitle) {},
          onBeforeDeleteURI: function(aURI) {},
          onDeleteURI: function(aURI) {},
          onClearHistory: function() {},
          onPageChanged: function(aURI, aWhat, aValue) {
              if (aWhat != Ci.nsINavHistoryObserver.ATTRIBUTE_FAVICON) {
                  return;
              }
              aURI = aURI.spec;
              switch (aURI) {
              case pageurl:
                  ok(aValue, "Favicon value is not null for page without fragment.");
                  originalFavicon = aValue;
  
                  // Now that the favicon has loaded, click on fragment link.
                  // This should trigger the |case fragmenturl| below.
                  clickLinkIfReady();
  
                  return;
              case fragmenturl:
                  // If the fragment URL's favicon isn't set, this branch won't
                  // be called and the test will time out.
  
                  is(aValue, originalFavicon, "New favicon should be same as original favicon.");
  
                  // Let's explicitly check that we can get the favicon
                  // from nsINavHistoryService now.
                  let info = getNavHistoryEntry(makeURI(aURI));
                  ok(info, "There must be a history entry for the fragment.");
                  ok(info.icon, "The history entry must have an associated favicon.");
                  historyService.removeObserver(historyObserver, false);
                  gBrowser.removeCurrentTab();
                  finish();
              }
          },
          onPageExpired: function(aURI, aVisitTime, aWholeEntry) {},
          QueryInterface: function(iid) {
              if (iid.equals(Ci.nsINavHistoryObserver) ||
                  iid.equals(Ci.nsISupports)) {
                  return this;
              }
              throw Cr.NS_ERROR_NO_INTERFACE;
          }
      };
      historyService.addObserver(historyObserver, false);
  
      function onPageLoad() {
        gBrowser.selectedBrowser
                .removeEventListener("DOMContentLoaded", arguments.callee, true);
        clickLinkIfReady();
      }
  
      // Make sure neither of the test pages haven't been loaded before.
      var info = getNavHistoryEntry(makeURI(pageurl));
      ok(!info, "The test page must not have been visited already.");
      info = getNavHistoryEntry(makeURI(fragmenturl));
      ok(!info, "The fragment test page must not have been visited already.");
  
      // Now open the test page in a new tab.
      gBrowser.selectedTab = gBrowser.addTab();
      gBrowser.selectedBrowser.addEventListener(
          "DOMContentLoaded", onPageLoad, true);
      content.location = pageurl;
  }
  