toolkit/components/extensions/test/mochitest/test_ext_webnavigation_filters.html
author Kris Maglione <maglione.k@gmail.com>
Wed, 09 Nov 2016 18:07:07 -0800
changeset 352359 05c206c4311bc4d6e727f89243aea2b5139fca61
parent 340743 d316aa33106d4b9ad5fce1e89d8818efad79e141
child 352377 6cbde9c5e058999ba95319391b59a7d67649ca53
permissions -rw-r--r--
Bug 1305217: Part 2 - Run webNavigation listeners asynchronously. r=mixedpuppy MozReview-Commit-ID: AhnyokpgDFZ

<!DOCTYPE HTML>
<html>
<head>
  <title>Test for simple WebExtension</title>
  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
  <script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
  <script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
  <script type="text/javascript" src="head.js"></script>
  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>

<script type="text/javascript">
"use strict";

add_task(function* test_webnav_unresolved_uri_on_expected_URI_scheme() {
  function background() {
    let lastTest;

    function cleanupTestListeners() {
      if (lastTest) {
        let {event, okListener, failListener} = lastTest;
        lastTest = null;
        browser.test.log(`Cleanup previous test event listeners`);
        browser.webNavigation[event].removeListener(okListener);
        browser.webNavigation[event].removeListener(failListener);
      }
    }

    function createTestListener(event, fail, urlFilter) {
      function listener(details) {
        let log = JSON.stringify({url: details.url, urlFilter});
        if (fail) {
          browser.test.fail(`Got an unexpected ${event} on the failure listener: ${log}`);
        } else {
          browser.test.succeed(`Got the expected ${event} on the success listener: ${log}`);
        }

        cleanupTestListeners();
        browser.test.sendMessage("test-filter-next");
      }

      browser.webNavigation[event].addListener(listener, urlFilter);

      return listener;
    }

    browser.test.onMessage.addListener((msg, event, okFilter, failFilter) => {
      if (msg !== "test-filter") {
        return;
      }

      lastTest = {
        event,
        // Register the failListener first, which should not be called
        // and if it is called the test scenario is marked as a failure.
        failListener: createTestListener(event, true, failFilter),
        okListener: createTestListener(event, false, okFilter),
      };

      browser.test.sendMessage("test-filter-ready");
    });

    browser.test.sendMessage("ready");
  }

  let extensionData = {
    manifest: {
      permissions: [
        "webNavigation",
      ],
    },
    background,
  };

  let extension = ExtensionTestUtils.loadExtension(extensionData);

  yield extension.startup();

  yield extension.awaitMessage("ready");

  let win = window.open();

  let testFilterScenarios = [
    {
      url: "http://example.net/browser",
      filters: [
        // schemes
        {
          okFilter: [{schemes: ["http"]}],
          failFilter: [{schemes: ["https"]}],
        },
        // ports
        {
          okFilter: [{ports: [80, 22, 443]}],
          failFilter: [{ports: [81, 82, 83]}],
        },
        {
          okFilter: [{ports: [22, 443, [10, 80]]}],
          failFilter: [{ports: [22, 23, [81, 100]]}],
        },
      ],
    },
    {
      url: "http://example.net/browser?param=1#ref",
      filters: [
        // host: Equals, Contains, Prefix, Suffix
        {
          okFilter: [{hostEquals: "example.net"}],
          failFilter: [{hostEquals: "example.com"}],
        },
        {
          okFilter: [{hostContains: ".example"}],
          failFilter: [{hostContains: ".www"}],
        },
        {
          okFilter: [{hostPrefix: "example"}],
          failFilter: [{hostPrefix: "www"}],
        },
        {
          okFilter: [{hostSuffix: "net"}],
          failFilter: [{hostSuffix: "com"}],
        },
        // path: Equals, Contains, Prefix, Suffix
        {
          okFilter: [{pathEquals: "/browser"}],
          failFilter: [{pathEquals: "/"}],
        },
        {
          okFilter: [{pathContains: "brow"}],
          failFilter: [{pathContains: "tool"}],
        },
        {
          okFilter: [{pathPrefix: "/bro"}],
          failFilter: [{pathPrefix: "/tool"}],
        },
        {
          okFilter: [{pathSuffix: "wser"}],
          failFilter: [{pathSuffix: "kit"}],
        },
        // query: Equals, Contains, Prefix, Suffix
        {
          okFilter: [{queryEquals: "param=1"}],
          failFilter: [{queryEquals: "wrongparam=2"}],
        },
        {
          okFilter: [{queryContains: "param"}],
          failFilter: [{queryContains: "wrongparam"}],
        },
        {
          okFilter: [{queryPrefix: "param="}],
          failFilter: [{queryPrefix: "wrong"}],
        },
        {
          okFilter: [{querySuffix: "=1"}],
          failFilter: [{querySuffix: "=2"}],
        },
        // urlMatches, originAndPathMatches
        {
          okFilter: [{urlMatches: "example.net/.*\?param=1"}],
          failFilter: [{urlMatches: "example.net/.*\?wrongparam=2"}],
        },
        {
          okFilter: [{originAndPathMatches: "example.net\/browser"}],
          failFilter: [{originAndPathMatches: "example.net/.*\?param=1"}],
        },
      ],
    },
    {
      url: "http://example.net/browser",
      filters: [
        // multiple criteria in a single filter:
        // if one of the critera is not verified, the event should not be received.
        {
          okFilter: [{schemes: ["http"], ports: [80, 22, 443]}],
          failFilter: [{schemes: ["http"], ports: [81, 82, 83]}],
        },
        // multiple urlFilters on the same listener
        // if at least one of the critera is verified, the event should be received.
        {
          okFilter: [{schemes: ["https"]}, {ports: [80, 22, 443]}],
          failFilter: [{schemes: ["https"]}, {ports: [81, 82, 83]}],
        },
      ],
    },
  ];

  function* runTestScenario(event, {url, filters}) {
    for (let testFilters of filters) {
      let {okFilter, failFilter} = testFilters;

      info(`Prepare the new test scenario: ${event} ${url} ${JSON.stringify(testFilters)}`);
      win.location = "about:blank";

      extension.sendMessage("test-filter", event, {url: okFilter}, {url: failFilter});
      yield extension.awaitMessage("test-filter-ready");

      info(`Loading the test url: ${url}`);
      win.location = url;

      yield extension.awaitMessage("test-filter-next");

      info("Test scenario completed. Moving to the next test scenario.");
    }
  }

  const BASE_WEBNAV_EVENTS = [
    "onBeforeNavigate",
    "onCommitted",
    "onDOMContentLoaded",
    "onCompleted",
  ];

  info("WebNavigation event filters test scenarios starting...");

  for (let filterScenario of testFilterScenarios) {
    for (let event of BASE_WEBNAV_EVENTS) {
      yield runTestScenario(event, filterScenario);
    }
  }

  info("WebNavigation event filters test onReferenceFragmentUpdated scenario starting...");

  const BASE = "http://mochi.test:8888/tests/toolkit/components/extensions/test/mochitest";
  let url = BASE + "/file_WebNavigation_page3.html";

  let okFilter = [{urlContains: "_page3.html"}];
  let failFilter = [{ports: [444]}];
  let event = "onCompleted";

  info(`Loading the initial test url: ${url}`);
  extension.sendMessage("test-filter", event, {url: okFilter}, {url: failFilter});

  yield extension.awaitMessage("test-filter-ready");
  win.location = url;
  yield extension.awaitMessage("test-filter-next");

  event = "onReferenceFragmentUpdated";
  extension.sendMessage("test-filter", event, {url: okFilter}, {url: failFilter});

  yield extension.awaitMessage("test-filter-ready");
  win.location = url + "#ref1";
  yield extension.awaitMessage("test-filter-next");

  info("WebNavigation event filters test onHistoryStateUpdated scenario starting...");

  event = "onHistoryStateUpdated";
  extension.sendMessage("test-filter", event, {url: okFilter}, {url: failFilter});
  yield extension.awaitMessage("test-filter-ready");

  win.history.pushState({}, "", BASE + "/pushState_page3.html");
  yield extension.awaitMessage("test-filter-next");

  // TODO: add additional specific tests for the other webNavigation events:
  // onErrorOccurred (and onCreatedNavigationTarget on supported)

  info("WebNavigation event filters test scenarios completed.");

  yield extension.unload();

  win.close();
});

add_task(function* test_webnav_empty_filter_validation_error() {
  function background() {
    let catchedException;

    try {
      browser.webNavigation.onCompleted.addListener(
        // Empty callback (not really used)
        () => {},
        // Empty filter (which should raise a validation error exception).
        {url: []}
      );
    } catch (e) {
      catchedException = e;
      browser.test.log(`Got an exception`);
    }

    if (catchedException &&
        catchedException.message.includes("Type error for parameter filters") &&
        catchedException.message.includes("Array requires at least 1 items; you have 0")) {
      browser.test.notifyPass("webNav.emptyFilterValidationError");
    } else {
      browser.test.notifyFail("webNav.emptyFilterValidationError");
    }
  }

  let extension = ExtensionTestUtils.loadExtension({
    manifest: {
      permissions: [
        "webNavigation",
      ],
    },
    background,
  });

  yield extension.startup();

  yield extension.awaitFinish("webNav.emptyFilterValidationError");

  yield extension.unload();
});

</script>

</body>
</html>