/* Test for Bug 420605
 * https://bugzilla.mozilla.org/show_bug.cgi?id=420605
 */

const { PlacesTestUtils } = ChromeUtils.import(
  "resource://testing-common/PlacesTestUtils.jsm"
);

add_task(async function test() {
  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";

  /* Queries nsINavHistoryService and returns a single history entry
   * for a given URI */
  function getNavHistoryEntry(aURI) {
    var options = PlacesUtils.history.getNewQueryOptions();
    options.queryType = Ci.nsINavHistoryQueryOptions.QUERY_TYPE_HISTORY;
    options.maxResults = 1;

    var query = PlacesUtils.history.getNewQuery();
    query.uri = aURI;
    var result = PlacesUtils.history.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
  // favicon-changed 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 favicon-changed event,
  // this time for the fragment's URL.

  var _clickLinkTimes = 0;
  function clickLinkIfReady() {
    _clickLinkTimes++;
    if (_clickLinkTimes == 2) {
      BrowserTestUtils.synthesizeMouseAtCenter(
        "#firefox-link",
        {},
        gBrowser.selectedBrowser
      );
    }
  }

  function onPageLoad() {
    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.");

  let promiseIcon1 = PlacesTestUtils.waitForNotification(
    "favicon-changed",
    events =>
      events.some(e => {
        if (e.url == pageurl) {
          ok(
            e.faviconUrl,
            "Favicon value is not null for page without fragment."
          );
          originalFavicon = e.faviconUrl;

          // Now that the favicon has loaded, click on fragment link.
          // This should trigger the |case fragmenturl| below.
          clickLinkIfReady();
          return true;
        }
        return false;
      }),
    "places"
  );
  let promiseIcon2 = PlacesTestUtils.waitForNotification(
    "favicon-changed",
    events =>
      events.some(e => {
        if (e.url == fragmenturl) {
          // If the fragment URL's favicon isn't set, this branch won't
          // be called and the test will time out.
          is(
            e.faviconUrl,
            originalFavicon,
            "New favicon should be same as original favicon."
          );
          ok(
            e.faviconUrl,
            "Favicon value is not null for page without fragment."
          );
          originalFavicon = e.faviconUrl;

          // Now that the favicon has loaded, click on fragment link.
          // This should trigger the |case fragmenturl| below.
          clickLinkIfReady();
          return true;
        }
        return false;
      }),
    "places"
  );

  // Now open the test page in a new tab.
  gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser);
  BrowserTestUtils.waitForContentEvent(
    gBrowser.selectedBrowser,
    "DOMContentLoaded",
    true
  ).then(onPageLoad);
  BrowserTestUtils.loadURI(gBrowser.selectedBrowser, pageurl);

  await promiseIcon1;
  await promiseIcon2;

  // Let's explicitly check that we can get the favicon
  // from nsINavHistoryService now.
  info = getNavHistoryEntry(makeURI(fragmenturl));
  ok(info, "There must be a history entry for the fragment.");
  ok(info.icon, "The history entry must have an associated favicon.");
  gBrowser.removeCurrentTab();
});
