tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

test_ext_history.js (24610B)


      1 /* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
      2 /* vim: set sts=2 sw=2 et tw=80: */
      3 "use strict";
      4 
      5 const { AddonTestUtils } = ChromeUtils.importESModule(
      6  "resource://testing-common/AddonTestUtils.sys.mjs"
      7 );
      8 
      9 ChromeUtils.defineESModuleGetters(this, {
     10  ExtensionCommon: "resource://gre/modules/ExtensionCommon.sys.mjs",
     11  PlacesTestUtils: "resource://testing-common/PlacesTestUtils.sys.mjs",
     12  PlacesUtils: "resource://gre/modules/PlacesUtils.sys.mjs",
     13 });
     14 
     15 AddonTestUtils.init(this);
     16 AddonTestUtils.overrideCertDB();
     17 AddonTestUtils.createAppInfo(
     18  "xpcshell@tests.mozilla.org",
     19  "XPCShell",
     20  "1",
     21  "43"
     22 );
     23 
     24 add_task(async function test_delete() {
     25  function background() {
     26    let historyClearedCount = 0;
     27    let removedUrls = [];
     28 
     29    browser.history.onVisitRemoved.addListener(data => {
     30      if (data.allHistory) {
     31        historyClearedCount++;
     32        browser.test.assertEq(
     33          0,
     34          data.urls.length,
     35          "onVisitRemoved received an empty urls array"
     36        );
     37      } else {
     38        removedUrls.push(...data.urls);
     39      }
     40    });
     41 
     42    browser.test.onMessage.addListener((msg, arg) => {
     43      if (msg === "delete-url") {
     44        browser.history.deleteUrl({ url: arg }).then(result => {
     45          browser.test.assertEq(
     46            undefined,
     47            result,
     48            "browser.history.deleteUrl returns nothing"
     49          );
     50          browser.test.sendMessage("url-deleted");
     51        });
     52      } else if (msg === "delete-range") {
     53        browser.history.deleteRange(arg).then(result => {
     54          browser.test.assertEq(
     55            undefined,
     56            result,
     57            "browser.history.deleteRange returns nothing"
     58          );
     59          browser.test.sendMessage("range-deleted", removedUrls);
     60        });
     61      } else if (msg === "delete-all") {
     62        browser.history.deleteAll().then(result => {
     63          browser.test.assertEq(
     64            undefined,
     65            result,
     66            "browser.history.deleteAll returns nothing"
     67          );
     68          browser.test.sendMessage("history-cleared", [
     69            historyClearedCount,
     70            removedUrls,
     71          ]);
     72        });
     73      }
     74    });
     75 
     76    browser.test.sendMessage("ready");
     77  }
     78 
     79  const BASE_URL = "http://mozilla.com/test_history/";
     80 
     81  let extension = ExtensionTestUtils.loadExtension({
     82    manifest: {
     83      permissions: ["history"],
     84    },
     85    background: `(${background})()`,
     86  });
     87 
     88  await extension.startup();
     89  await extension.awaitMessage("ready");
     90  await PlacesUtils.history.clear();
     91 
     92  let historyClearedCount;
     93  let visits = [];
     94  let visitDate = new Date(1999, 9, 9, 9, 9).getTime();
     95 
     96  function pushVisit(subvisits) {
     97    visitDate += 1000;
     98    subvisits.push({ date: new Date(visitDate) });
     99  }
    100 
    101  // Add 5 visits for one uri and 3 visits for 3 others
    102  for (let i = 0; i < 4; ++i) {
    103    let visit = {
    104      url: `${BASE_URL}${i}`,
    105      title: "visit " + i,
    106      visits: [],
    107    };
    108    if (i === 0) {
    109      for (let j = 0; j < 5; ++j) {
    110        pushVisit(visit.visits);
    111      }
    112    } else {
    113      pushVisit(visit.visits);
    114    }
    115    visits.push(visit);
    116  }
    117 
    118  await PlacesUtils.history.insertMany(visits);
    119  equal(
    120    await PlacesTestUtils.visitsInDB(visits[0].url),
    121    5,
    122    "5 visits for uri found in history database"
    123  );
    124 
    125  let testUrl = visits[2].url;
    126  ok(
    127    await PlacesTestUtils.isPageInDB(testUrl),
    128    "expected url found in history database"
    129  );
    130 
    131  extension.sendMessage("delete-url", testUrl);
    132  await extension.awaitMessage("url-deleted");
    133  equal(
    134    await PlacesTestUtils.isPageInDB(testUrl),
    135    false,
    136    "expected url not found in history database"
    137  );
    138 
    139  // delete 3 of the 5 visits for url 1
    140  let filter = {
    141    startTime: visits[0].visits[0].date,
    142    endTime: visits[0].visits[2].date,
    143  };
    144 
    145  extension.sendMessage("delete-range", filter);
    146  let removedUrls = await extension.awaitMessage("range-deleted");
    147  ok(
    148    !removedUrls.includes(visits[0].url),
    149    `${visits[0].url} not received by onVisitRemoved`
    150  );
    151  ok(
    152    await PlacesTestUtils.isPageInDB(visits[0].url),
    153    "expected uri found in history database"
    154  );
    155  equal(
    156    await PlacesTestUtils.visitsInDB(visits[0].url),
    157    2,
    158    "2 visits for uri found in history database"
    159  );
    160  ok(
    161    await PlacesTestUtils.isPageInDB(visits[1].url),
    162    "expected uri found in history database"
    163  );
    164  equal(
    165    await PlacesTestUtils.visitsInDB(visits[1].url),
    166    1,
    167    "1 visit for uri found in history database"
    168  );
    169 
    170  // delete the rest of the visits for url 1, and the visit for url 2
    171  filter.startTime = visits[0].visits[0].date;
    172  filter.endTime = visits[1].visits[0].date;
    173 
    174  extension.sendMessage("delete-range", filter);
    175  await extension.awaitMessage("range-deleted");
    176 
    177  equal(
    178    await PlacesTestUtils.isPageInDB(visits[0].url),
    179    false,
    180    "expected uri not found in history database"
    181  );
    182  equal(
    183    await PlacesTestUtils.visitsInDB(visits[0].url),
    184    0,
    185    "0 visits for uri found in history database"
    186  );
    187  equal(
    188    await PlacesTestUtils.isPageInDB(visits[1].url),
    189    false,
    190    "expected uri not found in history database"
    191  );
    192  equal(
    193    await PlacesTestUtils.visitsInDB(visits[1].url),
    194    0,
    195    "0 visits for uri found in history database"
    196  );
    197 
    198  ok(
    199    await PlacesTestUtils.isPageInDB(visits[3].url),
    200    "expected uri found in history database"
    201  );
    202 
    203  extension.sendMessage("delete-all");
    204  [historyClearedCount, removedUrls] =
    205    await extension.awaitMessage("history-cleared");
    206  equal(
    207    historyClearedCount,
    208    2,
    209    "onVisitRemoved called for each clearing of history"
    210  );
    211  equal(
    212    removedUrls.length,
    213    3,
    214    "onVisitRemoved called the expected number of times"
    215  );
    216  for (let i = 1; i < 3; ++i) {
    217    let url = visits[i].url;
    218    ok(removedUrls.includes(url), `${url} received by onVisitRemoved`);
    219  }
    220  await extension.unload();
    221 });
    222 
    223 const SINGLE_VISIT_URL = "http://example.com/";
    224 const DOUBLE_VISIT_URL = "http://example.com/2/";
    225 const MOZILLA_VISIT_URL = "http://mozilla.com/";
    226 const REFERENCE_DATE = new Date();
    227 // pages/visits to add via History.insert
    228 const PAGE_INFOS = [
    229  {
    230    url: SINGLE_VISIT_URL,
    231    title: `test visit for ${SINGLE_VISIT_URL}`,
    232    visits: [{ date: new Date(Number(REFERENCE_DATE) - 1000) }],
    233  },
    234  {
    235    url: DOUBLE_VISIT_URL,
    236    title: `test visit for ${DOUBLE_VISIT_URL}`,
    237    visits: [
    238      { date: REFERENCE_DATE },
    239      { date: new Date(Number(REFERENCE_DATE) - 2000) },
    240    ],
    241  },
    242  {
    243    url: MOZILLA_VISIT_URL,
    244    title: `test visit for ${MOZILLA_VISIT_URL}`,
    245    visits: [{ date: new Date(Number(REFERENCE_DATE) - 3000) }],
    246  },
    247 ];
    248 
    249 add_task(async function test_search() {
    250  function background(BGSCRIPT_REFERENCE_DATE) {
    251    const futureTime = Date.now() + 24 * 60 * 60 * 1000;
    252 
    253    browser.test.onMessage.addListener(() => {
    254      browser.history
    255        .search({ text: "" })
    256        .then(results => {
    257          browser.test.sendMessage("empty-search", results);
    258          return browser.history.search({ text: "mozilla.com" });
    259        })
    260        .then(results => {
    261          browser.test.sendMessage("text-search", results);
    262          return browser.history.search({ text: "example.com", maxResults: 1 });
    263        })
    264        .then(results => {
    265          browser.test.sendMessage("max-results-search", results);
    266          return browser.history.search({
    267            text: "",
    268            startTime: BGSCRIPT_REFERENCE_DATE - 2000,
    269            endTime: BGSCRIPT_REFERENCE_DATE - 1000,
    270          });
    271        })
    272        .then(results => {
    273          browser.test.sendMessage("date-range-search", results);
    274          return browser.history.search({ text: "", startTime: futureTime });
    275        })
    276        .then(results => {
    277          browser.test.assertEq(
    278            0,
    279            results.length,
    280            "no results returned for late start time"
    281          );
    282          return browser.history.search({ text: "", endTime: 0 });
    283        })
    284        .then(results => {
    285          browser.test.assertEq(
    286            0,
    287            results.length,
    288            "no results returned for early end time"
    289          );
    290          return browser.history.search({
    291            text: "",
    292            startTime: Date.now(),
    293            endTime: 0,
    294          });
    295        })
    296        .then(
    297          () => {
    298            browser.test.fail(
    299              "history.search rejects with startTime that is after the endTime"
    300            );
    301          },
    302          error => {
    303            browser.test.assertEq(
    304              "The startTime cannot be after the endTime",
    305              error.message,
    306              "history.search rejects with startTime that is after the endTime"
    307            );
    308          }
    309        )
    310        .then(() => {
    311          browser.test.notifyPass("search");
    312        });
    313    });
    314 
    315    browser.test.sendMessage("ready");
    316  }
    317 
    318  let extension = ExtensionTestUtils.loadExtension({
    319    manifest: {
    320      permissions: ["history"],
    321    },
    322    background: `(${background})(${Number(REFERENCE_DATE)})`,
    323  });
    324 
    325  function findResult(url, results) {
    326    return results.find(r => r.url === url);
    327  }
    328 
    329  function checkResult(results, url, expectedCount) {
    330    let result = findResult(url, results);
    331    notEqual(result, null, `history.search result was found for ${url}`);
    332    equal(
    333      result.visitCount,
    334      expectedCount,
    335      `history.search reports ${expectedCount} visit(s)`
    336    );
    337    equal(
    338      result.title,
    339      `test visit for ${url}`,
    340      "title for search result is correct"
    341    );
    342  }
    343 
    344  await extension.startup();
    345  await extension.awaitMessage("ready");
    346  await PlacesUtils.history.clear();
    347 
    348  await PlacesUtils.history.insertMany(PAGE_INFOS);
    349 
    350  extension.sendMessage("check-history");
    351 
    352  let results = await extension.awaitMessage("empty-search");
    353  equal(results.length, 3, "history.search with empty text returned 3 results");
    354  checkResult(results, SINGLE_VISIT_URL, 1);
    355  checkResult(results, DOUBLE_VISIT_URL, 2);
    356  checkResult(results, MOZILLA_VISIT_URL, 1);
    357 
    358  results = await extension.awaitMessage("text-search");
    359  equal(
    360    results.length,
    361    1,
    362    "history.search with specific text returned 1 result"
    363  );
    364  checkResult(results, MOZILLA_VISIT_URL, 1);
    365 
    366  results = await extension.awaitMessage("max-results-search");
    367  equal(results.length, 1, "history.search with maxResults returned 1 result");
    368  checkResult(results, DOUBLE_VISIT_URL, 2);
    369 
    370  results = await extension.awaitMessage("date-range-search");
    371  equal(
    372    results.length,
    373    2,
    374    "history.search with a date range returned 2 result"
    375  );
    376  checkResult(results, DOUBLE_VISIT_URL, 2);
    377  checkResult(results, SINGLE_VISIT_URL, 1);
    378 
    379  await extension.awaitFinish("search");
    380  await extension.unload();
    381  await PlacesUtils.history.clear();
    382 });
    383 
    384 add_task(async function test_add_url() {
    385  function background() {
    386    const TEST_DOMAIN = "http://example.com/";
    387 
    388    browser.test.onMessage.addListener((msg, testData) => {
    389      let [details, type] = testData;
    390      details.url = details.url || `${TEST_DOMAIN}${type}`;
    391      if (msg === "add-url") {
    392        details.title = `Title for ${type}`;
    393        browser.history
    394          .addUrl(details)
    395          .then(() => {
    396            return browser.history.search({ text: details.url });
    397          })
    398          .then(results => {
    399            browser.test.assertEq(
    400              1,
    401              results.length,
    402              "1 result found when searching for added URL"
    403            );
    404            browser.test.sendMessage("url-added", {
    405              details,
    406              result: results[0],
    407            });
    408          });
    409      } else if (msg === "expect-failure") {
    410        let expectedMsg = testData[2];
    411        browser.history.addUrl(details).then(
    412          () => {
    413            browser.test.fail(`Expected error thrown for ${type}`);
    414          },
    415          error => {
    416            browser.test.assertTrue(
    417              error.message.includes(expectedMsg),
    418              `"Expected error thrown when trying to add a URL with  ${type}`
    419            );
    420            browser.test.sendMessage("add-failed");
    421          }
    422        );
    423      }
    424    });
    425 
    426    browser.test.sendMessage("ready");
    427  }
    428 
    429  let addTestData = [
    430    [{}, "default"],
    431    [{ visitTime: new Date() }, "with_date"],
    432    [{ visitTime: Date.now() }, "with_ms_number"],
    433    [{ visitTime: new Date().toISOString() }, "with_iso_string"],
    434    [{ transition: "typed" }, "valid_transition"],
    435  ];
    436 
    437  let failTestData = [
    438    [
    439      { transition: "generated" },
    440      "an invalid transition",
    441      "|generated| is not a supported transition for history",
    442    ],
    443    [{ visitTime: Date.now() + 1000000 }, "a future date", "Invalid value"],
    444    [{ url: "about.config" }, "an invalid url", "Invalid value"],
    445  ];
    446 
    447  async function checkUrl(results) {
    448    ok(
    449      await PlacesTestUtils.isPageInDB(results.details.url),
    450      `${results.details.url} found in history database`
    451    );
    452    ok(
    453      PlacesUtils.isValidGuid(results.result.id),
    454      "URL was added with a valid id"
    455    );
    456    equal(
    457      results.result.title,
    458      results.details.title,
    459      "URL was added with the correct title"
    460    );
    461    if (results.details.visitTime) {
    462      equal(
    463        results.result.lastVisitTime,
    464        Number(ExtensionCommon.normalizeTime(results.details.visitTime)),
    465        "URL was added with the correct date"
    466      );
    467    }
    468  }
    469 
    470  let extension = ExtensionTestUtils.loadExtension({
    471    manifest: {
    472      permissions: ["history"],
    473    },
    474    background: `(${background})()`,
    475  });
    476 
    477  await PlacesUtils.history.clear();
    478  await extension.startup();
    479  await extension.awaitMessage("ready");
    480 
    481  for (let data of addTestData) {
    482    extension.sendMessage("add-url", data);
    483    let results = await extension.awaitMessage("url-added");
    484    await checkUrl(results);
    485  }
    486 
    487  for (let data of failTestData) {
    488    extension.sendMessage("expect-failure", data);
    489    await extension.awaitMessage("add-failed");
    490  }
    491 
    492  await extension.unload();
    493 });
    494 
    495 add_task(async function test_get_visits() {
    496  async function background() {
    497    const TEST_DOMAIN = "http://example.com/";
    498    const FIRST_DATE = Date.now();
    499    const INITIAL_DETAILS = {
    500      url: TEST_DOMAIN,
    501      visitTime: FIRST_DATE,
    502      transition: "link",
    503    };
    504 
    505    let visitIds = new Set();
    506 
    507    async function checkVisit(visit, expected) {
    508      visitIds.add(visit.visitId);
    509      browser.test.assertEq(
    510        expected.visitTime,
    511        visit.visitTime,
    512        "visit has the correct visitTime"
    513      );
    514      browser.test.assertEq(
    515        expected.transition,
    516        visit.transition,
    517        "visit has the correct transition"
    518      );
    519      let results = await browser.history.search({ text: expected.url });
    520      // all results will have the same id, so we only need to use the first one
    521      browser.test.assertEq(
    522        results[0].id,
    523        visit.id,
    524        "visit has the correct id"
    525      );
    526    }
    527 
    528    let details = Object.assign({}, INITIAL_DETAILS);
    529 
    530    await browser.history.addUrl(details);
    531    let results = await browser.history.getVisits({ url: details.url });
    532 
    533    browser.test.assertEq(
    534      1,
    535      results.length,
    536      "the expected number of visits were returned"
    537    );
    538    await checkVisit(results[0], details);
    539 
    540    details.url = `${TEST_DOMAIN}/1/`;
    541    await browser.history.addUrl(details);
    542 
    543    results = await browser.history.getVisits({ url: details.url });
    544    browser.test.assertEq(
    545      1,
    546      results.length,
    547      "the expected number of visits were returned"
    548    );
    549    await checkVisit(results[0], details);
    550 
    551    details.visitTime = FIRST_DATE - 1000;
    552    details.transition = "typed";
    553    await browser.history.addUrl(details);
    554    results = await browser.history.getVisits({ url: details.url });
    555 
    556    browser.test.assertEq(
    557      2,
    558      results.length,
    559      "the expected number of visits were returned"
    560    );
    561    await checkVisit(results[0], INITIAL_DETAILS);
    562    await checkVisit(results[1], details);
    563    browser.test.assertEq(3, visitIds.size, "each visit has a unique visitId");
    564    await browser.test.notifyPass("get-visits");
    565  }
    566 
    567  let extension = ExtensionTestUtils.loadExtension({
    568    manifest: {
    569      permissions: ["history"],
    570    },
    571    background: `(${background})()`,
    572  });
    573 
    574  await PlacesUtils.history.clear();
    575  await extension.startup();
    576 
    577  await extension.awaitFinish("get-visits");
    578  await extension.unload();
    579 });
    580 
    581 add_task(async function test_transition_types() {
    582  const VISIT_URL_PREFIX = "http://example.com/";
    583  const TRANSITIONS = [
    584    ["link", Ci.nsINavHistoryService.TRANSITION_LINK],
    585    ["typed", Ci.nsINavHistoryService.TRANSITION_TYPED],
    586    ["auto_bookmark", Ci.nsINavHistoryService.TRANSITION_BOOKMARK],
    587    // Only session history contains TRANSITION_EMBED visits,
    588    // So global history query cannot find them.
    589    // ["auto_subframe", Ci.nsINavHistoryService.TRANSITION_EMBED],
    590    // Redirects are not correctly tested here because History
    591    // will not make redirect entries hidden.
    592    ["link", Ci.nsINavHistoryService.TRANSITION_REDIRECT_PERMANENT],
    593    ["link", Ci.nsINavHistoryService.TRANSITION_REDIRECT_TEMPORARY],
    594    ["link", Ci.nsINavHistoryService.TRANSITION_DOWNLOAD],
    595    ["manual_subframe", Ci.nsINavHistoryService.TRANSITION_FRAMED_LINK],
    596    ["reload", Ci.nsINavHistoryService.TRANSITION_RELOAD],
    597  ];
    598 
    599  // pages/visits to add via History.insertMany
    600  let pageInfos = [];
    601  let visitDate = new Date(1999, 9, 9, 9, 9).getTime();
    602  for (let [, transitionType] of TRANSITIONS) {
    603    pageInfos.push({
    604      url: VISIT_URL_PREFIX + transitionType + "/",
    605      visits: [
    606        { transition: transitionType, date: new Date((visitDate -= 1000)) },
    607      ],
    608    });
    609  }
    610 
    611  function background() {
    612    browser.test.onMessage.addListener(async (msg, url) => {
    613      switch (msg) {
    614        case "search": {
    615          let results = await browser.history.search({
    616            text: "",
    617            startTime: new Date(0),
    618          });
    619          browser.test.sendMessage("search-result", results);
    620          break;
    621        }
    622        case "get-visits": {
    623          let results = await browser.history.getVisits({ url });
    624          browser.test.sendMessage("get-visits-result", results);
    625          break;
    626        }
    627      }
    628    });
    629 
    630    browser.test.sendMessage("ready");
    631  }
    632 
    633  let extension = ExtensionTestUtils.loadExtension({
    634    manifest: {
    635      permissions: ["history"],
    636    },
    637    background,
    638  });
    639 
    640  await PlacesUtils.history.clear();
    641  await extension.startup();
    642  await extension.awaitMessage("ready");
    643 
    644  await PlacesUtils.history.insertMany(pageInfos);
    645 
    646  extension.sendMessage("search");
    647  let results = await extension.awaitMessage("search-result");
    648  equal(
    649    results.length,
    650    pageInfos.length,
    651    "search returned expected length of results"
    652  );
    653  for (let i = 0; i < pageInfos.length; ++i) {
    654    equal(results[i].url, pageInfos[i].url, "search returned the expected url");
    655 
    656    extension.sendMessage("get-visits", pageInfos[i].url);
    657    let visits = await extension.awaitMessage("get-visits-result");
    658    equal(visits.length, 1, "getVisits returned expected length of visits");
    659    equal(
    660      visits[0].transition,
    661      TRANSITIONS[i][0],
    662      "getVisits returned the expected transition"
    663    );
    664  }
    665 
    666  await extension.unload();
    667 });
    668 
    669 add_task(async function test_on_visited() {
    670  const SINGLE_VISIT_URL = "http://example.com/1/";
    671  const DOUBLE_VISIT_URL = "http://example.com/2/";
    672  let visitDate = new Date(1999, 9, 9, 9, 9).getTime();
    673 
    674  // pages/visits to add via History.insertMany
    675  const PAGE_INFOS = [
    676    {
    677      url: SINGLE_VISIT_URL,
    678      title: `visit to ${SINGLE_VISIT_URL}`,
    679      visits: [{ date: new Date(visitDate) }],
    680    },
    681    {
    682      url: DOUBLE_VISIT_URL,
    683      title: `visit to ${DOUBLE_VISIT_URL}`,
    684      visits: [
    685        { date: new Date((visitDate += 1000)) },
    686        { date: new Date((visitDate += 1000)) },
    687      ],
    688    },
    689    {
    690      url: SINGLE_VISIT_URL,
    691      title: "Title Changed",
    692      visits: [{ date: new Date(visitDate) }],
    693    },
    694  ];
    695 
    696  function background() {
    697    let onVisitedData = [];
    698 
    699    browser.history.onVisited.addListener(data => {
    700      if (data.url.includes("moz-extension")) {
    701        return;
    702      }
    703      onVisitedData.push(data);
    704      if (onVisitedData.length == 4) {
    705        browser.test.sendMessage("on-visited-data", onVisitedData);
    706      }
    707    });
    708 
    709    // Verifying onTitleChange Event along with onVisited event
    710    browser.history.onTitleChanged.addListener(data => {
    711      browser.test.sendMessage("on-title-changed-data", data);
    712    });
    713 
    714    browser.test.sendMessage("ready");
    715  }
    716 
    717  let extension = ExtensionTestUtils.loadExtension({
    718    manifest: {
    719      permissions: ["history"],
    720    },
    721    background: `(${background})()`,
    722  });
    723 
    724  await PlacesUtils.history.clear();
    725  await extension.startup();
    726  await extension.awaitMessage("ready");
    727 
    728  await PlacesUtils.history.insertMany(PAGE_INFOS);
    729 
    730  let onVisitedData = await extension.awaitMessage("on-visited-data");
    731 
    732  function checkOnVisitedData(index, expected) {
    733    let onVisited = onVisitedData[index];
    734    ok(PlacesUtils.isValidGuid(onVisited.id), "onVisited received a valid id");
    735    equal(onVisited.url, expected.url, "onVisited received the expected url");
    736    equal(
    737      onVisited.title,
    738      expected.title,
    739      "onVisited received the expected title"
    740    );
    741    equal(
    742      onVisited.lastVisitTime,
    743      expected.time,
    744      "onVisited received the expected time"
    745    );
    746    equal(
    747      onVisited.visitCount,
    748      expected.visitCount,
    749      "onVisited received the expected visitCount"
    750    );
    751  }
    752 
    753  let expected = {
    754    url: PAGE_INFOS[0].url,
    755    title: PAGE_INFOS[0].title,
    756    time: PAGE_INFOS[0].visits[0].date.getTime(),
    757    visitCount: 1,
    758  };
    759  checkOnVisitedData(0, expected);
    760 
    761  expected.url = PAGE_INFOS[1].url;
    762  expected.title = PAGE_INFOS[1].title;
    763  expected.time = PAGE_INFOS[1].visits[0].date.getTime();
    764  checkOnVisitedData(1, expected);
    765 
    766  expected.time = PAGE_INFOS[1].visits[1].date.getTime();
    767  expected.visitCount = 2;
    768  checkOnVisitedData(2, expected);
    769 
    770  expected.url = PAGE_INFOS[2].url;
    771  expected.title = PAGE_INFOS[2].title;
    772  expected.time = PAGE_INFOS[2].visits[0].date.getTime();
    773  expected.visitCount = 2;
    774  checkOnVisitedData(3, expected);
    775 
    776  let onTitleChangedData = await extension.awaitMessage(
    777    "on-title-changed-data"
    778  );
    779  Assert.deepEqual(
    780    {
    781      id: onVisitedData[3].id,
    782      url: SINGLE_VISIT_URL,
    783      title: "Title Changed",
    784    },
    785    onTitleChangedData,
    786    "expected event data for onTitleChanged"
    787  );
    788 
    789  await extension.unload();
    790 });
    791 
    792 add_task(
    793  {
    794    pref_set: [["extensions.eventPages.enabled", true]],
    795  },
    796  async function test_history_event_page() {
    797    await AddonTestUtils.promiseStartupManager();
    798    let extension = ExtensionTestUtils.loadExtension({
    799      useAddonManager: "permanent",
    800      manifest: {
    801        browser_specific_settings: { gecko: { id: "eventpage@history" } },
    802        permissions: ["history"],
    803        background: { persistent: false },
    804      },
    805      background() {
    806        browser.history.onVisited.addListener(() => {
    807          browser.test.sendMessage("onVisited");
    808        });
    809        browser.history.onVisitRemoved.addListener(() => {
    810          browser.test.sendMessage("onVisitRemoved");
    811        });
    812        browser.history.onTitleChanged.addListener(() => {});
    813        browser.test.sendMessage("ready");
    814      },
    815    });
    816 
    817    const EVENTS = ["onVisited", "onVisitRemoved", "onTitleChanged"];
    818    await PlacesUtils.history.clear();
    819 
    820    await extension.startup();
    821    await extension.awaitMessage("ready");
    822    for (let event of EVENTS) {
    823      assertPersistentListeners(extension, "history", event, {
    824        primed: false,
    825      });
    826    }
    827 
    828    // test events waken background
    829    await extension.terminateBackground();
    830    for (let event of EVENTS) {
    831      assertPersistentListeners(extension, "history", event, {
    832        primed: true,
    833      });
    834    }
    835 
    836    await PlacesUtils.history.insertMany(PAGE_INFOS);
    837 
    838    await extension.awaitMessage("ready");
    839    await extension.awaitMessage("onVisited");
    840    ok(true, "persistent event woke background");
    841    for (let event of EVENTS) {
    842      assertPersistentListeners(extension, "history", event, {
    843        primed: false,
    844      });
    845    }
    846 
    847    await AddonTestUtils.promiseRestartManager();
    848    await extension.awaitStartup();
    849 
    850    for (let event of EVENTS) {
    851      assertPersistentListeners(extension, "history", event, {
    852        primed: true,
    853      });
    854    }
    855 
    856    await PlacesUtils.history.clear();
    857    await extension.awaitMessage("ready");
    858    await extension.awaitMessage("onVisitRemoved");
    859 
    860    await extension.unload();
    861    await AddonTestUtils.promiseShutdownManager();
    862  }
    863 );