tor-browser

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

test_ext_bookmarks.js (49487B)


      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  PlacesUtils: "resource://gre/modules/PlacesUtils.sys.mjs",
     11 });
     12 
     13 AddonTestUtils.init(this);
     14 AddonTestUtils.overrideCertDB();
     15 AddonTestUtils.createAppInfo(
     16  "xpcshell@tests.mozilla.org",
     17  "XPCShell",
     18  "1",
     19  "43"
     20 );
     21 
     22 add_task(async function test_bookmarks() {
     23  async function background() {
     24    let unsortedId, ourId;
     25    let initialBookmarkCount = 0;
     26    let createdBookmarks = new Set();
     27    let createdFolderId;
     28    let createdSeparatorId;
     29    let collectedEvents = [];
     30    const nonExistentId = "000000000000";
     31    const bookmarkGuids = {
     32      menuGuid: "menu________",
     33      toolbarGuid: "toolbar_____",
     34      unfiledGuid: "unfiled_____",
     35      rootGuid: "root________",
     36    };
     37 
     38    function checkOurBookmark(bookmark) {
     39      browser.test.assertEq(ourId, bookmark.id, "Bookmark has the expected Id");
     40      browser.test.assertTrue(
     41        "parentId" in bookmark,
     42        "Bookmark has a parentId"
     43      );
     44      browser.test.assertEq(
     45        0,
     46        bookmark.index,
     47        "Bookmark has the expected index"
     48      ); // We assume there are no other bookmarks.
     49      browser.test.assertEq(
     50        "http://example.org/",
     51        bookmark.url,
     52        "Bookmark has the expected url"
     53      );
     54      browser.test.assertEq(
     55        "test bookmark",
     56        bookmark.title,
     57        "Bookmark has the expected title"
     58      );
     59      browser.test.assertTrue(
     60        "dateAdded" in bookmark,
     61        "Bookmark has a dateAdded"
     62      );
     63      browser.test.assertFalse(
     64        "dateGroupModified" in bookmark,
     65        "Bookmark does not have a dateGroupModified"
     66      );
     67      browser.test.assertFalse(
     68        "unmodifiable" in bookmark,
     69        "Bookmark is not unmodifiable"
     70      );
     71      browser.test.assertEq(
     72        "bookmark",
     73        bookmark.type,
     74        "Bookmark is of type bookmark"
     75      );
     76    }
     77 
     78    function checkBookmark(expected, bookmark) {
     79      browser.test.assertEq(
     80        expected.url,
     81        bookmark.url,
     82        "Bookmark has the expected url"
     83      );
     84      browser.test.assertEq(
     85        expected.title,
     86        bookmark.title,
     87        "Bookmark has the expected title"
     88      );
     89      browser.test.assertEq(
     90        expected.index,
     91        bookmark.index,
     92        "Bookmark has expected index"
     93      );
     94      browser.test.assertEq(
     95        "bookmark",
     96        bookmark.type,
     97        "Bookmark is of type bookmark"
     98      );
     99      if ("parentId" in expected) {
    100        browser.test.assertEq(
    101          expected.parentId,
    102          bookmark.parentId,
    103          "Bookmark has the expected parentId"
    104        );
    105      }
    106    }
    107 
    108    function checkOnCreated(
    109      id,
    110      parentId,
    111      index,
    112      title,
    113      url,
    114      dateAdded,
    115      type = "bookmark"
    116    ) {
    117      let createdData = collectedEvents.pop();
    118      browser.test.assertEq(
    119        "onCreated",
    120        createdData.event,
    121        "onCreated was the last event received"
    122      );
    123      browser.test.assertEq(
    124        id,
    125        createdData.id,
    126        "onCreated event received the expected id"
    127      );
    128      let bookmark = createdData.bookmark;
    129      browser.test.assertEq(
    130        id,
    131        bookmark.id,
    132        "onCreated event received the expected bookmark id"
    133      );
    134      browser.test.assertEq(
    135        parentId,
    136        bookmark.parentId,
    137        "onCreated event received the expected bookmark parentId"
    138      );
    139      browser.test.assertEq(
    140        index,
    141        bookmark.index,
    142        "onCreated event received the expected bookmark index"
    143      );
    144      browser.test.assertEq(
    145        title,
    146        bookmark.title,
    147        "onCreated event received the expected bookmark title"
    148      );
    149      browser.test.assertEq(
    150        url,
    151        bookmark.url,
    152        "onCreated event received the expected bookmark url"
    153      );
    154      browser.test.assertEq(
    155        dateAdded,
    156        bookmark.dateAdded,
    157        "onCreated event received the expected bookmark dateAdded"
    158      );
    159      browser.test.assertEq(
    160        type,
    161        bookmark.type,
    162        "onCreated event received the expected bookmark type"
    163      );
    164    }
    165 
    166    function checkOnChanged(id, url, title) {
    167      // If both url and title are changed, then url is fired last.
    168      let changedData = collectedEvents.pop();
    169      browser.test.assertEq(
    170        "onChanged",
    171        changedData.event,
    172        "onChanged was the last event received"
    173      );
    174      browser.test.assertEq(
    175        id,
    176        changedData.id,
    177        "onChanged event received the expected id"
    178      );
    179      browser.test.assertEq(
    180        url,
    181        changedData.info.url,
    182        "onChanged event received the expected url"
    183      );
    184      // title is fired first.
    185      changedData = collectedEvents.pop();
    186      browser.test.assertEq(
    187        "onChanged",
    188        changedData.event,
    189        "onChanged was the last event received"
    190      );
    191      browser.test.assertEq(
    192        id,
    193        changedData.id,
    194        "onChanged event received the expected id"
    195      );
    196      browser.test.assertEq(
    197        title,
    198        changedData.info.title,
    199        "onChanged event received the expected title"
    200      );
    201    }
    202 
    203    function checkOnMoved(id, parentId, oldParentId, index, oldIndex) {
    204      let movedData = collectedEvents.pop();
    205      browser.test.assertEq(
    206        "onMoved",
    207        movedData.event,
    208        "onMoved was the last event received"
    209      );
    210      browser.test.assertEq(
    211        id,
    212        movedData.id,
    213        "onMoved event received the expected id"
    214      );
    215      let info = movedData.info;
    216      browser.test.assertEq(
    217        parentId,
    218        info.parentId,
    219        "onMoved event received the expected parentId"
    220      );
    221      browser.test.assertEq(
    222        oldParentId,
    223        info.oldParentId,
    224        "onMoved event received the expected oldParentId"
    225      );
    226      browser.test.assertEq(
    227        index,
    228        info.index,
    229        "onMoved event received the expected index"
    230      );
    231      browser.test.assertEq(
    232        oldIndex,
    233        info.oldIndex,
    234        "onMoved event received the expected oldIndex"
    235      );
    236    }
    237 
    238    function checkOnRemoved(id, parentId, index, title, url, type = "folder") {
    239      let removedData = collectedEvents.pop();
    240      browser.test.assertEq(
    241        "onRemoved",
    242        removedData.event,
    243        "onRemoved was the last event received"
    244      );
    245      browser.test.assertEq(
    246        id,
    247        removedData.id,
    248        "onRemoved event received the expected id"
    249      );
    250      let info = removedData.info;
    251      browser.test.assertEq(
    252        parentId,
    253        removedData.info.parentId,
    254        "onRemoved event received the expected parentId"
    255      );
    256      browser.test.assertEq(
    257        index,
    258        removedData.info.index,
    259        "onRemoved event received the expected index"
    260      );
    261      let node = info.node;
    262      browser.test.assertEq(
    263        id,
    264        node.id,
    265        "onRemoved event received the expected node id"
    266      );
    267      browser.test.assertEq(
    268        parentId,
    269        node.parentId,
    270        "onRemoved event received the expected node parentId"
    271      );
    272      browser.test.assertEq(
    273        index,
    274        node.index,
    275        "onRemoved event received the expected node index"
    276      );
    277      browser.test.assertEq(
    278        url,
    279        node.url,
    280        "onRemoved event received the expected node url"
    281      );
    282      browser.test.assertEq(
    283        title,
    284        node.title,
    285        "onRemoved event received the expected node title"
    286      );
    287      browser.test.assertEq(
    288        type,
    289        node.type,
    290        "onRemoved event received the expected node type"
    291      );
    292    }
    293 
    294    browser.bookmarks.onChanged.addListener((id, info) => {
    295      collectedEvents.push({ event: "onChanged", id, info });
    296    });
    297 
    298    browser.bookmarks.onCreated.addListener((id, bookmark) => {
    299      collectedEvents.push({ event: "onCreated", id, bookmark });
    300    });
    301 
    302    browser.bookmarks.onMoved.addListener((id, info) => {
    303      collectedEvents.push({ event: "onMoved", id, info });
    304    });
    305 
    306    browser.bookmarks.onRemoved.addListener((id, info) => {
    307      collectedEvents.push({ event: "onRemoved", id, info });
    308    });
    309 
    310    await browser.test.assertRejects(
    311      browser.bookmarks.get(["not-a-bookmark-guid"]),
    312      /Invalid value for property 'guid': "not-a-bookmark-guid"/,
    313      "Expected error thrown when trying to get a bookmark using an invalid guid"
    314    );
    315 
    316    await browser.test
    317      .assertRejects(
    318        browser.bookmarks.get([nonExistentId]),
    319        /Bookmark not found/,
    320        "Expected error thrown when trying to get a bookmark using a non-existent Id"
    321      )
    322      .then(() => {
    323        return browser.bookmarks.search({});
    324      })
    325      .then(results => {
    326        initialBookmarkCount = results.length;
    327        return browser.bookmarks.create({
    328          title: "test bookmark",
    329          url: "http://example.org",
    330          type: "bookmark",
    331        });
    332      })
    333      .then(result => {
    334        ourId = result.id;
    335        checkOurBookmark(result);
    336        browser.test.assertEq(
    337          1,
    338          collectedEvents.length,
    339          "1 expected event received"
    340        );
    341        checkOnCreated(
    342          ourId,
    343          bookmarkGuids.unfiledGuid,
    344          0,
    345          "test bookmark",
    346          "http://example.org/",
    347          result.dateAdded
    348        );
    349 
    350        return browser.bookmarks.get(ourId);
    351      })
    352      .then(results => {
    353        browser.test.assertEq(results.length, 1);
    354        checkOurBookmark(results[0]);
    355 
    356        unsortedId = results[0].parentId;
    357        return browser.bookmarks.get(unsortedId);
    358      })
    359      .then(results => {
    360        let folder = results[0];
    361        browser.test.assertEq(1, results.length, "1 bookmark was returned");
    362 
    363        browser.test.assertEq(
    364          unsortedId,
    365          folder.id,
    366          "Folder has the expected id"
    367        );
    368        browser.test.assertTrue("parentId" in folder, "Folder has a parentId");
    369        browser.test.assertTrue("index" in folder, "Folder has an index");
    370        browser.test.assertEq(
    371          undefined,
    372          folder.url,
    373          "Folder does not have a url"
    374        );
    375        browser.test.assertEq(
    376          "Other Bookmarks",
    377          folder.title,
    378          "Folder has the expected title"
    379        );
    380        browser.test.assertTrue(
    381          "dateAdded" in folder,
    382          "Folder has a dateAdded"
    383        );
    384        browser.test.assertTrue(
    385          "dateGroupModified" in folder,
    386          "Folder has a dateGroupModified"
    387        );
    388        browser.test.assertFalse(
    389          "unmodifiable" in folder,
    390          "Folder is not unmodifiable"
    391        ); // TODO: Do we want to enable this?
    392        browser.test.assertEq(
    393          "folder",
    394          folder.type,
    395          "Folder has a type of folder"
    396        );
    397 
    398        return browser.bookmarks.getChildren(unsortedId);
    399      })
    400      .then(async results => {
    401        browser.test.assertEq(1, results.length, "The folder has one child");
    402        checkOurBookmark(results[0]);
    403 
    404        await browser.test.assertRejects(
    405          browser.bookmarks.update(nonExistentId, { title: "new test title" }),
    406          /No bookmarks found for the provided GUID/,
    407          "Expected error thrown when trying to update a non-existent bookmark"
    408        );
    409        return browser.bookmarks.update(ourId, {
    410          title: "new test title",
    411          url: "http://example.com/",
    412        });
    413      })
    414      .then(async result => {
    415        browser.test.assertEq(
    416          "new test title",
    417          result.title,
    418          "Updated bookmark has the expected title"
    419        );
    420        browser.test.assertEq(
    421          "http://example.com/",
    422          result.url,
    423          "Updated bookmark has the expected URL"
    424        );
    425        browser.test.assertEq(
    426          ourId,
    427          result.id,
    428          "Updated bookmark has the expected id"
    429        );
    430        browser.test.assertEq(
    431          "bookmark",
    432          result.type,
    433          "Updated bookmark has a type of bookmark"
    434        );
    435 
    436        browser.test.assertEq(
    437          2,
    438          collectedEvents.length,
    439          "2 expected events received"
    440        );
    441        checkOnChanged(ourId, "http://example.com/", "new test title");
    442 
    443        await browser.test.assertRejects(
    444          browser.bookmarks.update(ourId, { url: "this is not a valid url" }),
    445          /Invalid bookmark:/,
    446          "Expected error thrown when trying update with an invalid url"
    447        );
    448        return browser.bookmarks.getTree();
    449      })
    450      .then(results => {
    451        browser.test.assertEq(1, results.length, "getTree returns one result");
    452        let bookmark = results[0].children.find(
    453          bookmarkItem => bookmarkItem.id == unsortedId
    454        );
    455        browser.test.assertEq(
    456          "Other Bookmarks",
    457          bookmark.title,
    458          "Folder returned from getTree has the expected title"
    459        );
    460        browser.test.assertEq(
    461          "folder",
    462          bookmark.type,
    463          "Folder returned from getTree has the expected type"
    464        );
    465 
    466        return browser.test.assertRejects(
    467          browser.bookmarks.create({ parentId: "invalid" }),
    468          error =>
    469            error.message.includes("Invalid bookmark") &&
    470            error.message.includes(`"parentGuid":"invalid"`),
    471          "Expected error thrown when trying to create a bookmark with an invalid parentId"
    472        );
    473      })
    474      .then(() => {
    475        return browser.bookmarks.remove(ourId);
    476      })
    477      .then(result => {
    478        browser.test.assertEq(
    479          undefined,
    480          result,
    481          "Removing a bookmark returns undefined"
    482        );
    483 
    484        browser.test.assertEq(
    485          1,
    486          collectedEvents.length,
    487          "1 expected events received"
    488        );
    489        checkOnRemoved(
    490          ourId,
    491          bookmarkGuids.unfiledGuid,
    492          0,
    493          "new test title",
    494          "http://example.com/",
    495          "bookmark"
    496        );
    497 
    498        return browser.test.assertRejects(
    499          browser.bookmarks.get(ourId),
    500          /Bookmark not found/,
    501          "Expected error thrown when trying to get a removed bookmark"
    502        );
    503      })
    504      .then(() => {
    505        return browser.test.assertRejects(
    506          browser.bookmarks.remove(nonExistentId),
    507          /No bookmarks found for the provided GUID/,
    508          "Expected error thrown when trying removed a non-existent bookmark"
    509        );
    510      })
    511      .then(() => {
    512        // test bookmarks.search
    513        return Promise.all([
    514          browser.bookmarks.create({
    515            title: "Μοζιλλας",
    516            url: "http://møzîllä.örg/",
    517          }),
    518          browser.bookmarks.create({
    519            title: "Example",
    520            url: "http://example.org/",
    521          }),
    522          browser.bookmarks.create({ title: "Mozilla Folder", type: "folder" }),
    523          browser.bookmarks.create({ title: "EFF", url: "http://eff.org/" }),
    524          browser.bookmarks.create({
    525            title: "Menu Item",
    526            url: "http://menu.org/",
    527            parentId: bookmarkGuids.menuGuid,
    528          }),
    529          browser.bookmarks.create({
    530            title: "Toolbar Item",
    531            url: "http://toolbar.org/",
    532            parentId: bookmarkGuids.toolbarGuid,
    533          }),
    534        ]);
    535      })
    536      .then(results => {
    537        browser.test.assertEq(
    538          6,
    539          collectedEvents.length,
    540          "6 expected events received"
    541        );
    542        checkOnCreated(
    543          results[5].id,
    544          bookmarkGuids.toolbarGuid,
    545          0,
    546          "Toolbar Item",
    547          "http://toolbar.org/",
    548          results[5].dateAdded
    549        );
    550        checkOnCreated(
    551          results[4].id,
    552          bookmarkGuids.menuGuid,
    553          0,
    554          "Menu Item",
    555          "http://menu.org/",
    556          results[4].dateAdded
    557        );
    558        checkOnCreated(
    559          results[3].id,
    560          bookmarkGuids.unfiledGuid,
    561          0,
    562          "EFF",
    563          "http://eff.org/",
    564          results[3].dateAdded
    565        );
    566        checkOnCreated(
    567          results[2].id,
    568          bookmarkGuids.unfiledGuid,
    569          0,
    570          "Mozilla Folder",
    571          undefined,
    572          results[2].dateAdded,
    573          "folder"
    574        );
    575        checkOnCreated(
    576          results[1].id,
    577          bookmarkGuids.unfiledGuid,
    578          0,
    579          "Example",
    580          "http://example.org/",
    581          results[1].dateAdded
    582        );
    583        checkOnCreated(
    584          results[0].id,
    585          bookmarkGuids.unfiledGuid,
    586          0,
    587          "Μοζιλλας",
    588          "http://xn--mzll-ooa1dud.xn--rg-eka/",
    589          results[0].dateAdded
    590        );
    591 
    592        for (let result of results) {
    593          if (result.title !== "Mozilla Folder") {
    594            createdBookmarks.add(result.id);
    595          }
    596        }
    597        let folderResult = results[2];
    598        createdFolderId = folderResult.id;
    599        return Promise.all([
    600          browser.bookmarks.create({
    601            title: "Mozilla",
    602            url: "http://allizom.org/",
    603            parentId: createdFolderId,
    604          }),
    605          browser.bookmarks.create({
    606            parentId: createdFolderId,
    607            type: "separator",
    608          }),
    609          browser.bookmarks.create({
    610            title: "Mozilla Corporation",
    611            url: "http://allizom.com/",
    612            parentId: createdFolderId,
    613          }),
    614          browser.bookmarks.create({
    615            title: "Firefox",
    616            url: "http://allizom.org/firefox/",
    617            parentId: createdFolderId,
    618          }),
    619        ])
    620          .then(newBookmarks => {
    621            browser.test.assertEq(
    622              4,
    623              collectedEvents.length,
    624              "4 expected events received"
    625            );
    626            checkOnCreated(
    627              newBookmarks[3].id,
    628              createdFolderId,
    629              0,
    630              "Firefox",
    631              "http://allizom.org/firefox/",
    632              newBookmarks[3].dateAdded
    633            );
    634            checkOnCreated(
    635              newBookmarks[2].id,
    636              createdFolderId,
    637              0,
    638              "Mozilla Corporation",
    639              "http://allizom.com/",
    640              newBookmarks[2].dateAdded
    641            );
    642            checkOnCreated(
    643              newBookmarks[1].id,
    644              createdFolderId,
    645              0,
    646              "",
    647              "data:",
    648              newBookmarks[1].dateAdded,
    649              "separator"
    650            );
    651            checkOnCreated(
    652              newBookmarks[0].id,
    653              createdFolderId,
    654              0,
    655              "Mozilla",
    656              "http://allizom.org/",
    657              newBookmarks[0].dateAdded
    658            );
    659 
    660            return browser.bookmarks.create({
    661              title: "About Mozilla",
    662              url: "http://allizom.org/about/",
    663              parentId: createdFolderId,
    664              index: 1,
    665            });
    666          })
    667          .then(result => {
    668            browser.test.assertEq(
    669              1,
    670              collectedEvents.length,
    671              "1 expected events received"
    672            );
    673            checkOnCreated(
    674              result.id,
    675              createdFolderId,
    676              1,
    677              "About Mozilla",
    678              "http://allizom.org/about/",
    679              result.dateAdded
    680            );
    681 
    682            // returns all items on empty object
    683            return browser.bookmarks.search({});
    684          })
    685          .then(async bookmarksSearchResults => {
    686            browser.test.assertTrue(
    687              bookmarksSearchResults.length >= 10,
    688              "At least as many bookmarks as added were returned by search({})"
    689            );
    690 
    691            await browser.test.assertRejects(
    692              browser.bookmarks.remove(createdFolderId),
    693              /Cannot remove a non-empty folder/,
    694              "Expected error thrown when trying to remove a non-empty folder"
    695            );
    696            return browser.bookmarks.getSubTree(createdFolderId);
    697          });
    698      })
    699      .then(results => {
    700        browser.test.assertEq(
    701          1,
    702          results.length,
    703          "Expected number of nodes returned by getSubTree"
    704        );
    705        browser.test.assertEq(
    706          "Mozilla Folder",
    707          results[0].title,
    708          "Folder has the expected title"
    709        );
    710        browser.test.assertEq(
    711          bookmarkGuids.unfiledGuid,
    712          results[0].parentId,
    713          "Folder has the expected parentId"
    714        );
    715        browser.test.assertEq(
    716          "folder",
    717          results[0].type,
    718          "Folder has the expected type"
    719        );
    720        let children = results[0].children;
    721        browser.test.assertEq(
    722          5,
    723          children.length,
    724          "Expected number of bookmarks returned by getSubTree"
    725        );
    726        browser.test.assertEq(
    727          "Firefox",
    728          children[0].title,
    729          "Bookmark has the expected title"
    730        );
    731        browser.test.assertEq(
    732          "bookmark",
    733          children[0].type,
    734          "Bookmark has the expected type"
    735        );
    736        browser.test.assertEq(
    737          "About Mozilla",
    738          children[1].title,
    739          "Bookmark has the expected title"
    740        );
    741        browser.test.assertEq(
    742          "bookmark",
    743          children[1].type,
    744          "Bookmark has the expected type"
    745        );
    746        browser.test.assertEq(
    747          1,
    748          children[1].index,
    749          "Bookmark has the expected index"
    750        );
    751        browser.test.assertEq(
    752          "Mozilla Corporation",
    753          children[2].title,
    754          "Bookmark has the expected title"
    755        );
    756        browser.test.assertEq(
    757          "",
    758          children[3].title,
    759          "Separator has the expected title"
    760        );
    761        browser.test.assertEq(
    762          "data:",
    763          children[3].url,
    764          "Separator has the expected url"
    765        );
    766        browser.test.assertEq(
    767          "separator",
    768          children[3].type,
    769          "Separator has the expected type"
    770        );
    771        browser.test.assertEq(
    772          "Mozilla",
    773          children[4].title,
    774          "Bookmark has the expected title"
    775        );
    776 
    777        // throws an error for invalid query objects
    778        browser.test.assertThrows(
    779          () => browser.bookmarks.search(),
    780          /Incorrect argument types for bookmarks.search/,
    781          "Expected error thrown when trying to search with no arguments"
    782        );
    783 
    784        browser.test.assertThrows(
    785          () => browser.bookmarks.search(null),
    786          /Incorrect argument types for bookmarks.search/,
    787          "Expected error thrown when trying to search with null as an argument"
    788        );
    789 
    790        browser.test.assertThrows(
    791          () => browser.bookmarks.search(() => {}),
    792          /Incorrect argument types for bookmarks.search/,
    793          "Expected error thrown when trying to search with a function as an argument"
    794        );
    795 
    796        browser.test.assertThrows(
    797          () => browser.bookmarks.search({ banana: "banana" }),
    798          /an unexpected "banana" property/,
    799          "Expected error thrown when trying to search with a banana as an argument"
    800        );
    801 
    802        browser.test.assertThrows(
    803          () => browser.bookmarks.search({ url: "spider-man vs. batman" }),
    804          /must match the format "url"/,
    805          "Expected error thrown when trying to search with a illegally formatted URL"
    806        );
    807        // queries the full url
    808        return browser.bookmarks.search("http://example.org/");
    809      })
    810      .then(results => {
    811        browser.test.assertEq(
    812          1,
    813          results.length,
    814          "Expected number of results returned for url search"
    815        );
    816        checkBookmark(
    817          { title: "Example", url: "http://example.org/", index: 2 },
    818          results[0]
    819        );
    820 
    821        // queries a partial url
    822        return browser.bookmarks.search("example.org");
    823      })
    824      .then(results => {
    825        browser.test.assertEq(
    826          1,
    827          results.length,
    828          "Expected number of results returned for url search"
    829        );
    830        checkBookmark(
    831          { title: "Example", url: "http://example.org/", index: 2 },
    832          results[0]
    833        );
    834 
    835        // queries the title
    836        return browser.bookmarks.search("EFF");
    837      })
    838      .then(results => {
    839        browser.test.assertEq(
    840          1,
    841          results.length,
    842          "Expected number of results returned for title search"
    843        );
    844        checkBookmark(
    845          {
    846            title: "EFF",
    847            url: "http://eff.org/",
    848            index: 0,
    849            parentId: bookmarkGuids.unfiledGuid,
    850          },
    851          results[0]
    852        );
    853 
    854        // finds menu items
    855        return browser.bookmarks.search("Menu Item");
    856      })
    857      .then(results => {
    858        browser.test.assertEq(
    859          1,
    860          results.length,
    861          "Expected number of results returned for menu item search"
    862        );
    863        checkBookmark(
    864          {
    865            title: "Menu Item",
    866            url: "http://menu.org/",
    867            index: 0,
    868            parentId: bookmarkGuids.menuGuid,
    869          },
    870          results[0]
    871        );
    872 
    873        // finds toolbar items
    874        return browser.bookmarks.search("Toolbar Item");
    875      })
    876      .then(results => {
    877        browser.test.assertEq(
    878          1,
    879          results.length,
    880          "Expected number of results returned for toolbar item search"
    881        );
    882        checkBookmark(
    883          {
    884            title: "Toolbar Item",
    885            url: "http://toolbar.org/",
    886            index: 0,
    887            parentId: bookmarkGuids.toolbarGuid,
    888          },
    889          results[0]
    890        );
    891 
    892        // finds folders
    893        return browser.bookmarks.search("Mozilla Folder");
    894      })
    895      .then(results => {
    896        browser.test.assertEq(
    897          1,
    898          results.length,
    899          "Expected number of folders returned"
    900        );
    901        browser.test.assertEq(
    902          "Mozilla Folder",
    903          results[0].title,
    904          "Folder has the expected title"
    905        );
    906        browser.test.assertEq(
    907          "folder",
    908          results[0].type,
    909          "Folder has the expected type"
    910        );
    911 
    912        // is case-insensitive
    913        return browser.bookmarks.search("corporation");
    914      })
    915      .then(results => {
    916        browser.test.assertEq(
    917          1,
    918          results.length,
    919          "Expected number of results returnedfor case-insensitive search"
    920        );
    921        browser.test.assertEq(
    922          "Mozilla Corporation",
    923          results[0].title,
    924          "Bookmark has the expected title"
    925        );
    926 
    927        // is case-insensitive for non-ascii
    928        return browser.bookmarks.search("ΜοΖΙΛΛΑς");
    929      })
    930      .then(results => {
    931        browser.test.assertEq(
    932          1,
    933          results.length,
    934          "Expected number of results returned for non-ascii search"
    935        );
    936        browser.test.assertEq(
    937          "Μοζιλλας",
    938          results[0].title,
    939          "Bookmark has the expected title"
    940        );
    941 
    942        // returns multiple results
    943        return browser.bookmarks.search("allizom");
    944      })
    945      .then(results => {
    946        browser.test.assertEq(
    947          4,
    948          results.length,
    949          "Expected number of multiple results returned"
    950        );
    951        browser.test.assertEq(
    952          "Mozilla",
    953          results[0].title,
    954          "Bookmark has the expected title"
    955        );
    956        browser.test.assertEq(
    957          "Mozilla Corporation",
    958          results[1].title,
    959          "Bookmark has the expected title"
    960        );
    961        browser.test.assertEq(
    962          "Firefox",
    963          results[2].title,
    964          "Bookmark has the expected title"
    965        );
    966        browser.test.assertEq(
    967          "About Mozilla",
    968          results[3].title,
    969          "Bookmark has the expected title"
    970        );
    971 
    972        // accepts a url field
    973        return browser.bookmarks.search({ url: "http://allizom.com/" });
    974      })
    975      .then(results => {
    976        browser.test.assertEq(
    977          1,
    978          results.length,
    979          "Expected number of results returned for url field"
    980        );
    981        checkBookmark(
    982          {
    983            title: "Mozilla Corporation",
    984            url: "http://allizom.com/",
    985            index: 2,
    986          },
    987          results[0]
    988        );
    989 
    990        // normalizes urls
    991        return browser.bookmarks.search({ url: "http://allizom.com" });
    992      })
    993      .then(results => {
    994        browser.test.assertEq(
    995          results.length,
    996          1,
    997          "Expected number of results returned for normalized url field"
    998        );
    999        checkBookmark(
   1000          {
   1001            title: "Mozilla Corporation",
   1002            url: "http://allizom.com/",
   1003            index: 2,
   1004          },
   1005          results[0]
   1006        );
   1007 
   1008        // normalizes urls even more
   1009        return browser.bookmarks.search({ url: "http:allizom.com" });
   1010      })
   1011      .then(results => {
   1012        browser.test.assertEq(
   1013          results.length,
   1014          1,
   1015          "Expected number of results returned for normalized url field"
   1016        );
   1017        checkBookmark(
   1018          {
   1019            title: "Mozilla Corporation",
   1020            url: "http://allizom.com/",
   1021            index: 2,
   1022          },
   1023          results[0]
   1024        );
   1025 
   1026        // accepts a title field
   1027        return browser.bookmarks.search({ title: "Mozilla" });
   1028      })
   1029      .then(results => {
   1030        browser.test.assertEq(
   1031          results.length,
   1032          1,
   1033          "Expected number of results returned for title field"
   1034        );
   1035        checkBookmark(
   1036          { title: "Mozilla", url: "http://allizom.org/", index: 4 },
   1037          results[0]
   1038        );
   1039 
   1040        // can combine title and query
   1041        return browser.bookmarks.search({ title: "Mozilla", query: "allizom" });
   1042      })
   1043      .then(results => {
   1044        browser.test.assertEq(
   1045          1,
   1046          results.length,
   1047          "Expected number of results returned for title and query fields"
   1048        );
   1049        checkBookmark(
   1050          { title: "Mozilla", url: "http://allizom.org/", index: 4 },
   1051          results[0]
   1052        );
   1053 
   1054        // uses AND conditions
   1055        return browser.bookmarks.search({ title: "EFF", query: "allizom" });
   1056      })
   1057      .then(results => {
   1058        browser.test.assertEq(
   1059          0,
   1060          results.length,
   1061          "Expected number of results returned for non-matching title and query fields"
   1062        );
   1063 
   1064        // returns an empty array on item not found
   1065        return browser.bookmarks.search("microsoft");
   1066      })
   1067      .then(results => {
   1068        browser.test.assertEq(
   1069          0,
   1070          results.length,
   1071          "Expected number of results returned for non-matching search"
   1072        );
   1073 
   1074        browser.test.assertThrows(
   1075          () => browser.bookmarks.getRecent(""),
   1076          /Incorrect argument types for bookmarks.getRecent/,
   1077          "Expected error thrown when calling getRecent with an empty string"
   1078        );
   1079      })
   1080      .then(() => {
   1081        browser.test.assertThrows(
   1082          () => browser.bookmarks.getRecent(1.234),
   1083          /Incorrect argument types for bookmarks.getRecent/,
   1084          "Expected error thrown when calling getRecent with a decimal number"
   1085        );
   1086      })
   1087      .then(() => {
   1088        return Promise.all([
   1089          browser.bookmarks.search("corporation"),
   1090          browser.bookmarks.getChildren(bookmarkGuids.menuGuid),
   1091        ]);
   1092      })
   1093      .then(results => {
   1094        let corporationBookmark = results[0][0];
   1095        let childCount = results[1].length;
   1096 
   1097        browser.test.assertEq(
   1098          2,
   1099          corporationBookmark.index,
   1100          "Bookmark has the expected index"
   1101        );
   1102 
   1103        return browser.bookmarks
   1104          .move(corporationBookmark.id, { index: 0 })
   1105          .then(result => {
   1106            browser.test.assertEq(
   1107              0,
   1108              result.index,
   1109              "Bookmark has the expected index"
   1110            );
   1111 
   1112            browser.test.assertEq(
   1113              1,
   1114              collectedEvents.length,
   1115              "1 expected events received"
   1116            );
   1117            checkOnMoved(
   1118              corporationBookmark.id,
   1119              createdFolderId,
   1120              createdFolderId,
   1121              0,
   1122              2
   1123            );
   1124 
   1125            return browser.bookmarks.move(corporationBookmark.id, {
   1126              parentId: bookmarkGuids.menuGuid,
   1127            });
   1128          })
   1129          .then(result => {
   1130            browser.test.assertEq(
   1131              bookmarkGuids.menuGuid,
   1132              result.parentId,
   1133              "Bookmark has the expected parent"
   1134            );
   1135            browser.test.assertEq(
   1136              childCount,
   1137              result.index,
   1138              "Bookmark has the expected index"
   1139            );
   1140 
   1141            browser.test.assertEq(
   1142              1,
   1143              collectedEvents.length,
   1144              "1 expected events received"
   1145            );
   1146            checkOnMoved(
   1147              corporationBookmark.id,
   1148              bookmarkGuids.menuGuid,
   1149              createdFolderId,
   1150              1,
   1151              0
   1152            );
   1153 
   1154            return browser.bookmarks.move(corporationBookmark.id, { index: 0 });
   1155          })
   1156          .then(result => {
   1157            browser.test.assertEq(
   1158              bookmarkGuids.menuGuid,
   1159              result.parentId,
   1160              "Bookmark has the expected parent"
   1161            );
   1162            browser.test.assertEq(
   1163              0,
   1164              result.index,
   1165              "Bookmark has the expected index"
   1166            );
   1167 
   1168            browser.test.assertEq(
   1169              1,
   1170              collectedEvents.length,
   1171              "1 expected events received"
   1172            );
   1173            checkOnMoved(
   1174              corporationBookmark.id,
   1175              bookmarkGuids.menuGuid,
   1176              bookmarkGuids.menuGuid,
   1177              0,
   1178              1
   1179            );
   1180 
   1181            return browser.bookmarks.move(corporationBookmark.id, {
   1182              parentId: bookmarkGuids.toolbarGuid,
   1183              index: 1,
   1184            });
   1185          })
   1186          .then(result => {
   1187            browser.test.assertEq(
   1188              bookmarkGuids.toolbarGuid,
   1189              result.parentId,
   1190              "Bookmark has the expected parent"
   1191            );
   1192            browser.test.assertEq(
   1193              1,
   1194              result.index,
   1195              "Bookmark has the expected index"
   1196            );
   1197 
   1198            browser.test.assertEq(
   1199              1,
   1200              collectedEvents.length,
   1201              "1 expected events received"
   1202            );
   1203            checkOnMoved(
   1204              corporationBookmark.id,
   1205              bookmarkGuids.toolbarGuid,
   1206              bookmarkGuids.menuGuid,
   1207              1,
   1208              0
   1209            );
   1210 
   1211            createdBookmarks.add(corporationBookmark.id);
   1212          });
   1213      })
   1214      .then(() => {
   1215        return browser.bookmarks.getRecent(4);
   1216      })
   1217      .then(results => {
   1218        browser.test.assertEq(
   1219          4,
   1220          results.length,
   1221          "Expected number of results returned by getRecent"
   1222        );
   1223        let prevDate = results[0].dateAdded;
   1224        for (let bookmark of results) {
   1225          browser.test.assertTrue(
   1226            bookmark.dateAdded <= prevDate,
   1227            "The recent bookmarks are sorted by dateAdded"
   1228          );
   1229          prevDate = bookmark.dateAdded;
   1230        }
   1231        let bookmarksByTitle = results.sort((a, b) => {
   1232          return a.title.localeCompare(b.title);
   1233        });
   1234        browser.test.assertEq(
   1235          "About Mozilla",
   1236          bookmarksByTitle[0].title,
   1237          "Bookmark has the expected title"
   1238        );
   1239        browser.test.assertEq(
   1240          "Firefox",
   1241          bookmarksByTitle[1].title,
   1242          "Bookmark has the expected title"
   1243        );
   1244        browser.test.assertEq(
   1245          "Mozilla",
   1246          bookmarksByTitle[2].title,
   1247          "Bookmark has the expected title"
   1248        );
   1249        browser.test.assertEq(
   1250          "Mozilla Corporation",
   1251          bookmarksByTitle[3].title,
   1252          "Bookmark has the expected title"
   1253        );
   1254 
   1255        return browser.bookmarks.search({});
   1256      })
   1257      .then(results => {
   1258        let startBookmarkCount = results.length;
   1259 
   1260        return browser.bookmarks
   1261          .search({ title: "Mozilla Folder" })
   1262          .then(result => {
   1263            return browser.bookmarks.removeTree(result[0].id);
   1264          })
   1265          .then(() => {
   1266            browser.test.assertEq(
   1267              1,
   1268              collectedEvents.length,
   1269              "1 expected events received"
   1270            );
   1271            checkOnRemoved(
   1272              createdFolderId,
   1273              bookmarkGuids.unfiledGuid,
   1274              1,
   1275              "Mozilla Folder"
   1276            );
   1277 
   1278            return browser.bookmarks.search({}).then(searchResults => {
   1279              browser.test.assertEq(
   1280                startBookmarkCount - 5,
   1281                searchResults.length,
   1282                "Expected number of results returned after removeTree"
   1283              );
   1284            });
   1285          });
   1286      })
   1287      .then(() => {
   1288        return browser.bookmarks.create({ title: "Empty Folder" });
   1289      })
   1290      .then(result => {
   1291        createdFolderId = result.id;
   1292 
   1293        browser.test.assertEq(
   1294          1,
   1295          collectedEvents.length,
   1296          "1 expected events received"
   1297        );
   1298        checkOnCreated(
   1299          createdFolderId,
   1300          bookmarkGuids.unfiledGuid,
   1301          3,
   1302          "Empty Folder",
   1303          undefined,
   1304          result.dateAdded,
   1305          "folder"
   1306        );
   1307 
   1308        browser.test.assertEq(
   1309          "Empty Folder",
   1310          result.title,
   1311          "Folder has the expected title"
   1312        );
   1313        browser.test.assertEq(
   1314          "folder",
   1315          result.type,
   1316          "Folder has the expected type"
   1317        );
   1318 
   1319        return browser.bookmarks.create({
   1320          parentId: createdFolderId,
   1321          type: "separator",
   1322        });
   1323      })
   1324      .then(result => {
   1325        createdSeparatorId = result.id;
   1326        browser.test.assertEq(
   1327          1,
   1328          collectedEvents.length,
   1329          "1 expected events received"
   1330        );
   1331        checkOnCreated(
   1332          createdSeparatorId,
   1333          createdFolderId,
   1334          0,
   1335          "",
   1336          "data:",
   1337          result.dateAdded,
   1338          "separator"
   1339        );
   1340        return browser.bookmarks.remove(createdSeparatorId);
   1341      })
   1342      .then(() => {
   1343        browser.test.assertEq(
   1344          1,
   1345          collectedEvents.length,
   1346          "1 expected events received"
   1347        );
   1348        checkOnRemoved(
   1349          createdSeparatorId,
   1350          createdFolderId,
   1351          0,
   1352          "",
   1353          "data:",
   1354          "separator"
   1355        );
   1356 
   1357        return browser.bookmarks.remove(createdFolderId);
   1358      })
   1359      .then(() => {
   1360        browser.test.assertEq(
   1361          1,
   1362          collectedEvents.length,
   1363          "1 expected events received"
   1364        );
   1365        checkOnRemoved(
   1366          createdFolderId,
   1367          bookmarkGuids.unfiledGuid,
   1368          3,
   1369          "Empty Folder"
   1370        );
   1371 
   1372        return browser.test.assertRejects(
   1373          browser.bookmarks.get(createdFolderId),
   1374          /Bookmark not found/,
   1375          "Expected error thrown when trying to get a removed folder"
   1376        );
   1377      })
   1378      .then(() => {
   1379        return browser.test.assertRejects(
   1380          browser.bookmarks.getChildren(nonExistentId),
   1381          /root is null/,
   1382          "Expected error thrown when trying to getChildren for a non-existent folder"
   1383        );
   1384      })
   1385      .then(() => {
   1386        return browser.test.assertRejects(
   1387          browser.bookmarks.move(nonExistentId, {}),
   1388          /No bookmarks found for the provided GUID/,
   1389          "Expected error thrown when calling move with a non-existent bookmark"
   1390        );
   1391      })
   1392      .then(() => {
   1393        return browser.test.assertRejects(
   1394          browser.bookmarks.create({
   1395            title: "test root folder",
   1396            parentId: bookmarkGuids.rootGuid,
   1397          }),
   1398          "The bookmark root cannot be modified",
   1399          "Expected error thrown when creating bookmark folder at the root"
   1400        );
   1401      })
   1402      .then(() => {
   1403        return browser.test.assertRejects(
   1404          browser.bookmarks.update(bookmarkGuids.rootGuid, {
   1405            title: "test update title",
   1406          }),
   1407          "The bookmark root cannot be modified",
   1408          "Expected error thrown when updating root"
   1409        );
   1410      })
   1411      .then(() => {
   1412        return browser.test.assertRejects(
   1413          browser.bookmarks.remove(bookmarkGuids.rootGuid),
   1414          "The bookmark root cannot be modified",
   1415          "Expected error thrown when removing root"
   1416        );
   1417      })
   1418      .then(() => {
   1419        return browser.test.assertRejects(
   1420          browser.bookmarks.removeTree(bookmarkGuids.rootGuid),
   1421          "The bookmark root cannot be modified",
   1422          "Expected error thrown when removing root tree"
   1423        );
   1424      })
   1425      .then(() => {
   1426        return browser.bookmarks.create({ title: "Empty Folder" });
   1427      })
   1428      .then(async result => {
   1429        createdFolderId = result.id;
   1430 
   1431        browser.test.assertEq(
   1432          1,
   1433          collectedEvents.length,
   1434          "1 expected events received"
   1435        );
   1436        checkOnCreated(
   1437          createdFolderId,
   1438          bookmarkGuids.unfiledGuid,
   1439          3,
   1440          "Empty Folder",
   1441          undefined,
   1442          result.dateAdded,
   1443          "folder"
   1444        );
   1445 
   1446        await browser.test.assertRejects(
   1447          browser.bookmarks.move(createdFolderId, {
   1448            parentId: bookmarkGuids.rootGuid,
   1449          }),
   1450          "The bookmark root cannot be modified",
   1451          "Expected error thrown when moving bookmark folder to the root"
   1452        );
   1453 
   1454        return browser.bookmarks.remove(createdFolderId);
   1455      })
   1456      .then(() => {
   1457        browser.test.assertEq(
   1458          1,
   1459          collectedEvents.length,
   1460          "1 expected events received"
   1461        );
   1462        checkOnRemoved(
   1463          createdFolderId,
   1464          bookmarkGuids.unfiledGuid,
   1465          3,
   1466          "Empty Folder",
   1467          undefined,
   1468          "folder"
   1469        );
   1470 
   1471        return browser.test.assertRejects(
   1472          browser.bookmarks.get(createdFolderId),
   1473          "Bookmark not found",
   1474          "Expected error thrown when trying to get a removed folder"
   1475        );
   1476      })
   1477      .then(() => {
   1478        return browser.test.assertRejects(
   1479          browser.bookmarks.move(bookmarkGuids.rootGuid, {
   1480            parentId: bookmarkGuids.unfiledGuid,
   1481          }),
   1482          "The bookmark root cannot be modified",
   1483          "Expected error thrown when moving root"
   1484        );
   1485      })
   1486      .then(() => {
   1487        // remove all created bookmarks
   1488        let promises = Array.from(createdBookmarks, guid =>
   1489          browser.bookmarks.remove(guid)
   1490        );
   1491        return Promise.all(promises);
   1492      })
   1493      .then(() => {
   1494        browser.test.assertEq(
   1495          createdBookmarks.size,
   1496          collectedEvents.length,
   1497          "expected number of events received"
   1498        );
   1499 
   1500        return browser.bookmarks.search({});
   1501      })
   1502      .then(results => {
   1503        browser.test.assertEq(
   1504          initialBookmarkCount,
   1505          results.length,
   1506          "All created bookmarks have been removed"
   1507        );
   1508 
   1509        return browser.test.notifyPass("bookmarks");
   1510      })
   1511      .catch(error => {
   1512        browser.test.fail(`Error: ${String(error)} :: ${error.stack}`);
   1513        browser.test.notifyFail("bookmarks");
   1514      });
   1515  }
   1516 
   1517  let extension = ExtensionTestUtils.loadExtension({
   1518    background,
   1519    manifest: {
   1520      permissions: ["bookmarks"],
   1521    },
   1522  });
   1523 
   1524  await extension.startup();
   1525  await extension.awaitFinish("bookmarks");
   1526  await extension.unload();
   1527 });
   1528 
   1529 add_task(async function test_get_recent_with_tag_and_query() {
   1530  function background() {
   1531    browser.bookmarks.getRecent(100).then(bookmarks => {
   1532      browser.test.sendMessage("bookmarks", bookmarks);
   1533    });
   1534  }
   1535 
   1536  let extension = ExtensionTestUtils.loadExtension({
   1537    background,
   1538    manifest: {
   1539      permissions: ["bookmarks"],
   1540    },
   1541  });
   1542 
   1543  // Start with an empty bookmarks database.
   1544  await PlacesUtils.bookmarks.eraseEverything();
   1545 
   1546  let createdBookmarks = [];
   1547  for (let i = 0; i < 3; i++) {
   1548    let bookmark = {
   1549      type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
   1550      url: `http://example.com/${i}`,
   1551      title: `My bookmark ${i}`,
   1552      parentGuid: PlacesUtils.bookmarks.unfiledGuid,
   1553    };
   1554    createdBookmarks.unshift(bookmark);
   1555    await PlacesUtils.bookmarks.insert(bookmark);
   1556  }
   1557 
   1558  // Add a tag to the most recent url to prove it doesn't get returned.
   1559  PlacesUtils.tagging.tagURI(NetUtil.newURI("http://example.com/${i}"), [
   1560    "Test Tag",
   1561  ]);
   1562 
   1563  // Add a query bookmark.
   1564  let queryURL = `place:parent=${PlacesUtils.bookmarks.menuGuid}&queryType=1`;
   1565  await PlacesUtils.bookmarks.insert({
   1566    parentGuid: PlacesUtils.bookmarks.unfiledGuid,
   1567    url: queryURL,
   1568    title: "a test query",
   1569  });
   1570 
   1571  await extension.startup();
   1572  let receivedBookmarks = await extension.awaitMessage("bookmarks");
   1573 
   1574  equal(
   1575    receivedBookmarks.length,
   1576    3,
   1577    "The expected number of bookmarks was returned."
   1578  );
   1579  for (let i = 0; i < 3; i++) {
   1580    let actual = receivedBookmarks[i];
   1581    let expected = createdBookmarks[i];
   1582    equal(actual.url, expected.url, "Bookmark has the expected url.");
   1583    equal(actual.title, expected.title, "Bookmark has the expected title.");
   1584    equal(
   1585      actual.parentId,
   1586      expected.parentGuid,
   1587      "Bookmark has the expected parentId."
   1588    );
   1589  }
   1590 
   1591  await extension.unload();
   1592 });
   1593 
   1594 add_task(async function test_tree_with_empty_folder() {
   1595  async function background() {
   1596    await browser.bookmarks.create({ title: "Empty Folder" });
   1597    let nonEmptyFolder = await browser.bookmarks.create({
   1598      title: "Non-Empty Folder",
   1599    });
   1600    await browser.bookmarks.create({
   1601      title: "A bookmark",
   1602      url: "http://example.com",
   1603      parentId: nonEmptyFolder.id,
   1604    });
   1605 
   1606    let tree = await browser.bookmarks.getSubTree(nonEmptyFolder.parentId);
   1607    browser.test.assertEq(
   1608      0,
   1609      tree[0].children[0].children.length,
   1610      "The empty folder returns an empty array for children."
   1611    );
   1612    browser.test.assertEq(
   1613      1,
   1614      tree[0].children[1].children.length,
   1615      "The non-empty folder returns a single item array for children."
   1616    );
   1617 
   1618    let children = await browser.bookmarks.getChildren(nonEmptyFolder.parentId);
   1619    // getChildren should only return immediate children. This is not tested in the
   1620    // monster test above.
   1621    for (let child of children) {
   1622      browser.test.assertEq(
   1623        undefined,
   1624        child.children,
   1625        "Child from getChildren does not contain any children."
   1626      );
   1627    }
   1628 
   1629    browser.test.sendMessage("done");
   1630  }
   1631 
   1632  let extension = ExtensionTestUtils.loadExtension({
   1633    background,
   1634    manifest: {
   1635      permissions: ["bookmarks"],
   1636    },
   1637  });
   1638 
   1639  // Start with an empty bookmarks database.
   1640  await PlacesUtils.bookmarks.eraseEverything();
   1641 
   1642  await extension.startup();
   1643  await extension.awaitMessage("done");
   1644 
   1645  await extension.unload();
   1646 });
   1647 
   1648 add_task(
   1649  {
   1650    pref_set: [["extensions.eventPages.enabled", true]],
   1651  },
   1652  async function test_bookmarks_event_page() {
   1653    await AddonTestUtils.promiseStartupManager();
   1654    let extension = ExtensionTestUtils.loadExtension({
   1655      useAddonManager: "permanent",
   1656      manifest: {
   1657        browser_specific_settings: { gecko: { id: "eventpage@bookmarks" } },
   1658        permissions: ["bookmarks"],
   1659        background: { persistent: false },
   1660      },
   1661      background() {
   1662        browser.bookmarks.onCreated.addListener(() => {
   1663          browser.test.sendMessage("onCreated");
   1664        });
   1665        browser.bookmarks.onRemoved.addListener(() => {
   1666          browser.test.sendMessage("onRemoved");
   1667        });
   1668        browser.bookmarks.onChanged.addListener(() => {});
   1669        browser.bookmarks.onMoved.addListener(() => {});
   1670        browser.test.sendMessage("ready");
   1671      },
   1672    });
   1673 
   1674    const EVENTS = ["onCreated", "onRemoved", "onChanged", "onMoved"];
   1675    await PlacesUtils.bookmarks.eraseEverything();
   1676 
   1677    await extension.startup();
   1678    await extension.awaitMessage("ready");
   1679    for (let event of EVENTS) {
   1680      assertPersistentListeners(extension, "bookmarks", event, {
   1681        primed: false,
   1682      });
   1683    }
   1684 
   1685    // test events waken background
   1686    await extension.terminateBackground();
   1687    for (let event of EVENTS) {
   1688      assertPersistentListeners(extension, "bookmarks", event, {
   1689        primed: true,
   1690      });
   1691    }
   1692 
   1693    let bookmark = {
   1694      type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
   1695      url: `http://example.com/12345`,
   1696      title: `My bookmark 12345`,
   1697      parentGuid: PlacesUtils.bookmarks.unfiledGuid,
   1698    };
   1699    await PlacesUtils.bookmarks.insert(bookmark);
   1700 
   1701    await extension.awaitMessage("ready");
   1702    await extension.awaitMessage("onCreated");
   1703    for (let event of EVENTS) {
   1704      assertPersistentListeners(extension, "bookmarks", event, {
   1705        primed: false,
   1706      });
   1707    }
   1708 
   1709    await AddonTestUtils.promiseRestartManager();
   1710    await extension.awaitStartup();
   1711 
   1712    for (let event of EVENTS) {
   1713      assertPersistentListeners(extension, "bookmarks", event, {
   1714        primed: true,
   1715      });
   1716    }
   1717 
   1718    await PlacesUtils.bookmarks.eraseEverything();
   1719    await extension.awaitMessage("ready");
   1720    await extension.awaitMessage("onRemoved");
   1721 
   1722    await extension.unload();
   1723    await AddonTestUtils.promiseShutdownManager();
   1724  }
   1725 );