Commit e61c3156 authored by Mike Conley's avatar Mike Conley
Browse files

Bug 1724748 - Add regression tests for JSWindowActor...

Bug 1724748 - Add regression tests for JSWindowActor nsITopLevelNavigationDelegate behaviour. r=smaug

Differential Revision: https://phabricator.services.mozilla.com/D122151
parent 6b8e200b
Loading
Loading
Loading
Loading
+56 −0
Original line number Diff line number Diff line
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */

"use strict";

/**
 * To avoid a proliferation of JSMs just for this test, we implement
 * both the TopLevelNavigationDelegateChild and
 * TopLevelNavigationDelegateParent JSWindowActors here.
 *
 * Note that the implementation must be called TopLevelNavigationDelegate
 * in order for the nsDocShell to detect it.
 */
var EXPORTED_SYMBOLS = [
  "TopLevelNavigationDelegateChild",
  "TopLevelNavigationDelegateParent",
];

class TopLevelNavigationDelegateParent extends JSWindowActorParent {
  actorCreated() {
    this.seenURIStrings = [];
  }

  receiveMessage(message) {
    if (message.name == "ShouldNavigate") {
      this.seenURIStrings.push(message.data.URIString);
    }
  }
}

class TopLevelNavigationDelegateChild extends JSWindowActorChild {
  shouldNavigate(
    docShell,
    URI,
    referrer,
    hasPostData,
    triggeringPrincipal,
    csp
  ) {
    if (URI.spec.includes("example.org")) {
      this.sendAsyncMessage("ShouldNavigate", { URIString: URI.spec });
      this.contentWindow.dispatchEvent(
        new this.contentWindow.Event("TopLevelNavigationDelegateEvent", {
          bubbles: true,
        })
      );
      return false;
    }

    return true;
  }
}

TopLevelNavigationDelegateChild.prototype.QueryInterface = ChromeUtils.generateQI(
  ["nsITopLevelNavigationDelegate"]
);
+4 −0
Original line number Diff line number Diff line
@@ -68,6 +68,10 @@ support-files =
  file_bug1688368-1.sjs
  file_bug1691153.html

[browser_TopLevelNavigationDelegate.js]
support-files =
  dummy_iframe_page.html
  TestTopLevelNavigationDelegate.jsm
[browser_alternate_fixup_middle_click_link.js]
https_first_disabled = true
[browser_backforward_userinteraction.js]
+146 −0
Original line number Diff line number Diff line
/* Any copyright is dedicated to the Public Domain.
   http://creativecommons.org/publicdomain/zero/1.0/ */

"use strict";

const ACTOR_NAME = "TopLevelNavigationDelegate";
const ACTOR_MODULE_URI =
  getRootDirectory(gTestPath) + "TestTopLevelNavigationDelegate.jsm";
const IFRAME_PAGE =
  getRootDirectory(gTestPath).replace(
    "chrome://mochitests/content",
    "http://example.com"
  ) + "dummy_iframe_page.html";

/**
 * Tests that when browser navigates to uriString, that the
 * TopLevelNavigationDelegateChild detects it, prevents the navigation,
 * and that the TopLevelNavigationDelegateParent is notified
 * about the navigation attempt.
 *
 * @param {Element} browser The <xul:browser> to attempt the navigation with.
 * @param {String} uriString The URI to navigate browser to.
 * @return {Promise}
 * @resolves {undefined} Once the delegation has been detected.
 */
async function doesDelegateFor(browser, uriString) {
  let delegatePromise = BrowserTestUtils.waitForContentEvent(
    browser,
    "TopLevelNavigationDelegateEvent",
    false,
    null,
    true
  );
  BrowserTestUtils.loadURI(browser, uriString);
  await delegatePromise;
  Assert.ok(true, `Delegated navigation for ${uriString}`);
  let parentActor = browser.browsingContext.currentWindowGlobal.getActor(
    ACTOR_NAME
  );
  Assert.equal(
    parentActor.seenURIStrings.shift(),
    uriString,
    "TopLevelNavigationDelegateParent saw the load attempt."
  );
}

/**
 * Tests that when browser navigates to uriString, that the
 * TopLevelNavigationDelegateChild does not prevent the navigation,
 * and that the load event properly fires after reaching the new
 * location.
 *
 * @param {Element} browser The <xul:browser> to attempt the navigation with.
 * @param {String} uriString The URI to navigate browser to.
 * @param {Boolean} hashChange The URI to navigate to is a same-document fragment
 *   navigation.
 * @return {Promise}
 * @resolves {undefined} Once the successful load has been detected.
 */
async function doesNotDelegateFor(browser, uriString, hashChange = false) {
  let loaded = hashChange
    ? BrowserTestUtils.waitForContentEvent(browser, "hashchange", true)
    : BrowserTestUtils.browserLoaded(browser, false, uriString);
  BrowserTestUtils.loadURI(browser, uriString);
  await loaded;
  Assert.ok(true, `Successfully navigated to ${uriString}`);
}

/**
 * Registers a test nsITopLevelNavigationDelegate JSWindowActorChild that
 * stops attempts to reach example.org on top-level BrowsingContexts, and
 * then ensures that example.org sites cannot be loaded, but example.com
 * sites can. Also tests that iframes can load both example.org and
 * example.com sites successfully. Finally, unregisters the
 * JSWindowActorChild and ensures that top-level example.org navigations
 * are no longer prevented.
 */
add_task(async function() {
  await BrowserTestUtils.withNewTab("http://example.com", async browser => {
    ChromeUtils.registerWindowActor(ACTOR_NAME, {
      child: {
        moduleURI: ACTOR_MODULE_URI,
      },
      parent: {
        moduleURI: ACTOR_MODULE_URI,
      },
      messageManagerGroups: ["browsers"],
    });

    // This is normally done towards the end of the test, but just in case that
    // task exits early for some reason, we unregister the JSWindowActorChild
    // to ensure we don't contaminate other tests. Doing this when the
    // JSWindowActorChild is already unregistered is a no-op.
    registerCleanupFunction(() => {
      ChromeUtils.unregisterWindowActor(ACTOR_NAME);
    });

    await doesDelegateFor(browser, "http://example.org/");
    await doesDelegateFor(browser, "http://example.org/2");
    // We still want to delegate for a fragment navigation when we're
    // transitioning from example.com to example.org, and is not a
    // same document navigation.
    await doesDelegateFor(browser, "http://example.org/2#test");

    await doesNotDelegateFor(browser, "https://example.com/");
    await doesNotDelegateFor(
      browser,
      "https://example.com/#test",
      true /* hashChange */
    );
    await doesNotDelegateFor(browser, "http://example.com/2");
    await doesNotDelegateFor(browser, "https://example.com/3");

    await doesNotDelegateFor(browser, IFRAME_PAGE);

    // Now check that iframes don't qualify for delegation
    await SpecialPowers.spawn(browser, [], async () => {
      let iframe1 = content.document.getElementById("frame1");
      iframe1.remove();
      iframe1.src = "http://example.com";
      let load1 = ContentTaskUtils.waitForEvent(iframe1, "load");
      content.document.body.appendChild(iframe1);
      await load1;

      let iframe2 = content.document.getElementById("frame2");
      iframe2.remove();
      iframe2.src = "http://example.org";
      let load2 = ContentTaskUtils.waitForEvent(iframe2, "load");
      content.document.body.appendChild(iframe2);
      await load2;
    });

    ChromeUtils.unregisterWindowActor(ACTOR_NAME);

    await doesNotDelegateFor(browser, "http://example.org/2");
    await doesNotDelegateFor(browser, "https://example.org/3");
    await doesNotDelegateFor(browser, "https://example.org/");
    // We expect a same-document fragment navigation to succeed
    // on example.org now.
    await doesNotDelegateFor(
      browser,
      "https://example.org/#test",
      true /* hashChange */
    );
  });
});