Bug 1406594 - Fix history.search and history.getVisited so that they find hidden items correctly. r?aswan draft
authorMasatoshi Kimura <VYV03354@nifty.ne.jp>
Sat, 07 Oct 2017 06:04:56 +0900
changeset 681605 0a771db6e266687b80fcd93322794c892af672b1
parent 679629 25aad10380b10b6efa50c2b4d97245f078d870a0
child 736181 ac2f4f083b2f1e7b721ffc7cb7ad45536ddad052
push id84866
push userVYV03354@nifty.ne.jp
push dateTue, 17 Oct 2017 13:29:01 +0000
reviewersaswan
bugs1406594
milestone58.0a1
Bug 1406594 - Fix history.search and history.getVisited so that they find hidden items correctly. r?aswan I had to add a mochitest because PlacesUtils.history.insertMany cannot create hidden redirects. I also added a support for the "reload" transition while I am here. MozReview-Commit-ID: ECQp6pW2r8v
browser/components/extensions/ext-history.js
browser/components/extensions/test/mochitest/.eslintrc.js
browser/components/extensions/test/mochitest/mochitest.ini
browser/components/extensions/test/mochitest/test_ext_history_redirect.html
browser/components/extensions/test/xpcshell/test_ext_history.js
--- a/browser/components/extensions/ext-history.js
+++ b/browser/components/extensions/ext-history.js
@@ -16,16 +16,17 @@ var {
 
 let nsINavHistoryService = Ci.nsINavHistoryService;
 const TRANSITION_TO_TRANSITION_TYPES_MAP = new Map([
   ["link", nsINavHistoryService.TRANSITION_LINK],
   ["typed", nsINavHistoryService.TRANSITION_TYPED],
   ["auto_bookmark", nsINavHistoryService.TRANSITION_BOOKMARK],
   ["auto_subframe", nsINavHistoryService.TRANSITION_EMBED],
   ["manual_subframe", nsINavHistoryService.TRANSITION_FRAMED_LINK],
+  ["reload", nsINavHistoryService.TRANSITION_RELOAD],
 ]);
 
 let TRANSITION_TYPE_TO_TRANSITIONS_MAP = new Map();
 for (let [transition, transitionType] of TRANSITION_TO_TRANSITION_TYPES_MAP) {
   TRANSITION_TYPE_TO_TRANSITIONS_MAP.set(transitionType, transition);
 }
 
 const getTransitionType = transition => {
@@ -184,16 +185,17 @@ this.history = class extends ExtensionAP
           let endTime = (query.endTime == null) ?
                           Number.MAX_VALUE :
                           PlacesUtils.toPRTime(normalizeTime(query.endTime));
           if (beginTime > endTime) {
             return Promise.reject({message: "The startTime cannot be after the endTime"});
           }
 
           let options = PlacesUtils.history.getNewQueryOptions();
+          options.includeHidden = true;
           options.sortingMode = options.SORT_BY_DATE_DESCENDING;
           options.maxResults = query.maxResults || 100;
 
           let historyQuery = PlacesUtils.history.getNewQuery();
           historyQuery.searchTerms = query.text;
           historyQuery.beginTime = beginTime;
           historyQuery.endTime = endTime;
           let queryResult = PlacesUtils.history.executeQuery(historyQuery, options).root;
@@ -203,16 +205,17 @@ this.history = class extends ExtensionAP
 
         getVisits: function(details) {
           let url = details.url;
           if (!url) {
             return Promise.reject({message: "A URL must be provided for getVisits"});
           }
 
           let options = PlacesUtils.history.getNewQueryOptions();
+          options.includeHidden = true;
           options.sortingMode = options.SORT_BY_DATE_DESCENDING;
           options.resultType = options.RESULTS_AS_VISIT;
 
           let historyQuery = PlacesUtils.history.getNewQuery();
           historyQuery.uri = Services.io.newURI(url);
           let queryResult = PlacesUtils.history.executeQuery(historyQuery, options).root;
           let results = convertNavHistoryContainerResultNode(queryResult, convertNodeToVisitItem);
           return Promise.resolve(results);
new file mode 100644
--- /dev/null
+++ b/browser/components/extensions/test/mochitest/.eslintrc.js
@@ -0,0 +1,10 @@
+"use strict";
+
+module.exports = {
+  "extends": "plugin:mozilla/mochitest-test",
+
+  "env": {
+    "browser": true,
+    "webextensions": true,
+  },
+};
--- a/browser/components/extensions/test/mochitest/mochitest.ini
+++ b/browser/components/extensions/test/mochitest/mochitest.ini
@@ -1,7 +1,9 @@
 [DEFAULT]
 support-files =
   ../../../../../toolkit/components/extensions/test/mochitest/test_ext_all_apis.js
   ../../../../../toolkit/components/extensions/test/mochitest/file_sample.html
+  ../../../../../toolkit/components/extensions/test/mochitest/redirection.sjs
 tags = webextensions
 
 [test_ext_all_apis.html]
+[test_ext_history_redirect.html]
new file mode 100644
--- /dev/null
+++ b/browser/components/extensions/test/mochitest/test_ext_history_redirect.html
@@ -0,0 +1,87 @@
+<!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>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+
+<script type="text/javascript">
+"use strict";
+
+const REDIRECT_URL = new URL("redirection.sjs", location).href;
+
+function waitForLoad(win) {
+  return new Promise(resolve => {
+    win.addEventListener("load", function() {
+      resolve();
+    }, {capture: true, once: true});
+  });
+}
+
+add_task(async function history_redirect() {
+  function background() {
+    browser.test.onMessage.addListener(async (msg, url) => {
+      switch (msg) {
+        case "delete-all": {
+          let results = await browser.history.deleteAll();
+          browser.test.sendMessage("delete-all-result", results);
+          break;
+        }
+        case "search": {
+          let results = await browser.history.search({text: url, startTime: new Date(0)});
+          browser.test.sendMessage("search-result", results);
+          break;
+        }
+        case "get-visits": {
+          let results = await browser.history.getVisits({url});
+          browser.test.sendMessage("get-visits-result", results);
+          break;
+        }
+      }
+    });
+
+    browser.test.sendMessage("ready");
+  }
+
+  let extensionData = {
+    manifest: {
+      permissions: [
+        "history",
+      ],
+    },
+    background,
+  };
+
+  let extension = ExtensionTestUtils.loadExtension(extensionData);
+
+  await Promise.all([extension.startup(), extension.awaitMessage("ready")]);
+  info("extension loaded");
+
+  extension.sendMessage("delete-all");
+  await extension.awaitMessage("delete-all-result");
+
+  let win = window.open(REDIRECT_URL);
+  await waitForLoad(win);
+
+  extension.sendMessage("search", REDIRECT_URL);
+  let results = await extension.awaitMessage("search-result");
+  is(results.length, 1, "search returned expected length of results");
+
+  extension.sendMessage("get-visits", REDIRECT_URL);
+  let visits = await extension.awaitMessage("get-visits-result");
+  is(visits.length, 1, "getVisits returned expected length of visits");
+
+  // cleanup phase
+  win.close();
+
+  await extension.unload();
+  info("extension unloaded");
+});
+</script>
+
+</body>
+</html>
--- a/browser/components/extensions/test/xpcshell/test_ext_history.js
+++ b/browser/components/extensions/test/xpcshell/test_ext_history.js
@@ -399,16 +399,93 @@ add_task(async function test_get_visits(
 
   await PlacesTestUtils.clearHistory();
   await extension.startup();
 
   await extension.awaitFinish("get-visits");
   await extension.unload();
 });
 
+add_task(async function test_transition_types() {
+  const VISIT_URL_PREFIX = "http://example.com/";
+  const TRANSITIONS = [
+    ["link", Ci.nsINavHistoryService.TRANSITION_LINK],
+    ["typed", Ci.nsINavHistoryService.TRANSITION_TYPED],
+    ["auto_bookmark", Ci.nsINavHistoryService.TRANSITION_BOOKMARK],
+    // Only session history contains TRANSITION_EMBED visits,
+    // So global history query cannot find them.
+    // ["auto_subframe", Ci.nsINavHistoryService.TRANSITION_EMBED],
+    // Redirects are not correctly tested here because History::UpdatePlaces
+    // will not make redirect entries hidden.
+    ["link", Ci.nsINavHistoryService.TRANSITION_REDIRECT_PERMANENT],
+    ["link", Ci.nsINavHistoryService.TRANSITION_REDIRECT_TEMPORARY],
+    ["link", Ci.nsINavHistoryService.TRANSITION_DOWNLOAD],
+    ["manual_subframe", Ci.nsINavHistoryService.TRANSITION_FRAMED_LINK],
+    ["reload", Ci.nsINavHistoryService.TRANSITION_RELOAD],
+  ];
+
+  // pages/visits to add via History.insertMany
+  let pageInfos = [];
+  let visitDate = new Date(1999, 9, 9, 9, 9).getTime();
+  for (let [, transitionType] of TRANSITIONS) {
+    pageInfos.push({
+      url: VISIT_URL_PREFIX + transitionType + "/",
+      visits: [
+        {transition: transitionType, date: new Date(visitDate -= 1000)},
+      ],
+    });
+  }
+
+  function background() {
+    browser.test.onMessage.addListener(async (msg, url) => {
+      switch (msg) {
+        case "search": {
+          let results = await browser.history.search({text: "", startTime: new Date(0)});
+          browser.test.sendMessage("search-result", results);
+          break;
+        }
+        case "get-visits": {
+          let results = await browser.history.getVisits({url});
+          browser.test.sendMessage("get-visits-result", results);
+          break;
+        }
+      }
+    });
+
+    browser.test.sendMessage("ready");
+  }
+
+  let extension = ExtensionTestUtils.loadExtension({
+    manifest: {
+      permissions: ["history"],
+    },
+    background,
+  });
+
+  await PlacesTestUtils.clearHistory();
+  await extension.startup();
+  await extension.awaitMessage("ready");
+
+  await PlacesUtils.history.insertMany(pageInfos);
+
+  extension.sendMessage("search");
+  let results = await extension.awaitMessage("search-result");
+  equal(results.length, pageInfos.length, "search returned expected length of results");
+  for (let i = 0; i < pageInfos.length; ++i) {
+    equal(results[i].url, pageInfos[i].url, "search returned the expected url");
+
+    extension.sendMessage("get-visits", pageInfos[i].url);
+    let visits = await extension.awaitMessage("get-visits-result");
+    equal(visits.length, 1, "getVisits returned expected length of visits");
+    equal(visits[0].transition, TRANSITIONS[i][0], "getVisits returned the expected transition");
+  }
+
+  await extension.unload();
+});
+
 add_task(async function test_on_visited() {
   const SINGLE_VISIT_URL = "http://example.com/1/";
   const DOUBLE_VISIT_URL = "http://example.com/2/";
   let visitDate = new Date(1999, 9, 9, 9, 9).getTime();
 
   // pages/visits to add via History.insertMany
   const PAGE_INFOS = [
     {