summaryrefslogtreecommitdiffstats
path: root/browser/components/extensions/test/xpcshell/test_ext_bookmarks.js
diff options
context:
space:
mode:
Diffstat (limited to 'browser/components/extensions/test/xpcshell/test_ext_bookmarks.js')
-rw-r--r--browser/components/extensions/test/xpcshell/test_ext_bookmarks.js1725
1 files changed, 1725 insertions, 0 deletions
diff --git a/browser/components/extensions/test/xpcshell/test_ext_bookmarks.js b/browser/components/extensions/test/xpcshell/test_ext_bookmarks.js
new file mode 100644
index 0000000000..15d09d1163
--- /dev/null
+++ b/browser/components/extensions/test/xpcshell/test_ext_bookmarks.js
@@ -0,0 +1,1725 @@
+/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set sts=2 sw=2 et tw=80: */
+"use strict";
+
+const { AddonTestUtils } = ChromeUtils.importESModule(
+ "resource://testing-common/AddonTestUtils.sys.mjs"
+);
+
+ChromeUtils.defineESModuleGetters(this, {
+ PlacesUtils: "resource://gre/modules/PlacesUtils.sys.mjs",
+});
+
+AddonTestUtils.init(this);
+AddonTestUtils.overrideCertDB();
+AddonTestUtils.createAppInfo(
+ "xpcshell@tests.mozilla.org",
+ "XPCShell",
+ "1",
+ "43"
+);
+
+add_task(async function test_bookmarks() {
+ async function background() {
+ let unsortedId, ourId;
+ let initialBookmarkCount = 0;
+ let createdBookmarks = new Set();
+ let createdFolderId;
+ let createdSeparatorId;
+ let collectedEvents = [];
+ const nonExistentId = "000000000000";
+ const bookmarkGuids = {
+ menuGuid: "menu________",
+ toolbarGuid: "toolbar_____",
+ unfiledGuid: "unfiled_____",
+ rootGuid: "root________",
+ };
+
+ function checkOurBookmark(bookmark) {
+ browser.test.assertEq(ourId, bookmark.id, "Bookmark has the expected Id");
+ browser.test.assertTrue(
+ "parentId" in bookmark,
+ "Bookmark has a parentId"
+ );
+ browser.test.assertEq(
+ 0,
+ bookmark.index,
+ "Bookmark has the expected index"
+ ); // We assume there are no other bookmarks.
+ browser.test.assertEq(
+ "http://example.org/",
+ bookmark.url,
+ "Bookmark has the expected url"
+ );
+ browser.test.assertEq(
+ "test bookmark",
+ bookmark.title,
+ "Bookmark has the expected title"
+ );
+ browser.test.assertTrue(
+ "dateAdded" in bookmark,
+ "Bookmark has a dateAdded"
+ );
+ browser.test.assertFalse(
+ "dateGroupModified" in bookmark,
+ "Bookmark does not have a dateGroupModified"
+ );
+ browser.test.assertFalse(
+ "unmodifiable" in bookmark,
+ "Bookmark is not unmodifiable"
+ );
+ browser.test.assertEq(
+ "bookmark",
+ bookmark.type,
+ "Bookmark is of type bookmark"
+ );
+ }
+
+ function checkBookmark(expected, bookmark) {
+ browser.test.assertEq(
+ expected.url,
+ bookmark.url,
+ "Bookmark has the expected url"
+ );
+ browser.test.assertEq(
+ expected.title,
+ bookmark.title,
+ "Bookmark has the expected title"
+ );
+ browser.test.assertEq(
+ expected.index,
+ bookmark.index,
+ "Bookmark has expected index"
+ );
+ browser.test.assertEq(
+ "bookmark",
+ bookmark.type,
+ "Bookmark is of type bookmark"
+ );
+ if ("parentId" in expected) {
+ browser.test.assertEq(
+ expected.parentId,
+ bookmark.parentId,
+ "Bookmark has the expected parentId"
+ );
+ }
+ }
+
+ function checkOnCreated(
+ id,
+ parentId,
+ index,
+ title,
+ url,
+ dateAdded,
+ type = "bookmark"
+ ) {
+ let createdData = collectedEvents.pop();
+ browser.test.assertEq(
+ "onCreated",
+ createdData.event,
+ "onCreated was the last event received"
+ );
+ browser.test.assertEq(
+ id,
+ createdData.id,
+ "onCreated event received the expected id"
+ );
+ let bookmark = createdData.bookmark;
+ browser.test.assertEq(
+ id,
+ bookmark.id,
+ "onCreated event received the expected bookmark id"
+ );
+ browser.test.assertEq(
+ parentId,
+ bookmark.parentId,
+ "onCreated event received the expected bookmark parentId"
+ );
+ browser.test.assertEq(
+ index,
+ bookmark.index,
+ "onCreated event received the expected bookmark index"
+ );
+ browser.test.assertEq(
+ title,
+ bookmark.title,
+ "onCreated event received the expected bookmark title"
+ );
+ browser.test.assertEq(
+ url,
+ bookmark.url,
+ "onCreated event received the expected bookmark url"
+ );
+ browser.test.assertEq(
+ dateAdded,
+ bookmark.dateAdded,
+ "onCreated event received the expected bookmark dateAdded"
+ );
+ browser.test.assertEq(
+ type,
+ bookmark.type,
+ "onCreated event received the expected bookmark type"
+ );
+ }
+
+ function checkOnChanged(id, url, title) {
+ // If both url and title are changed, then url is fired last.
+ let changedData = collectedEvents.pop();
+ browser.test.assertEq(
+ "onChanged",
+ changedData.event,
+ "onChanged was the last event received"
+ );
+ browser.test.assertEq(
+ id,
+ changedData.id,
+ "onChanged event received the expected id"
+ );
+ browser.test.assertEq(
+ url,
+ changedData.info.url,
+ "onChanged event received the expected url"
+ );
+ // title is fired first.
+ changedData = collectedEvents.pop();
+ browser.test.assertEq(
+ "onChanged",
+ changedData.event,
+ "onChanged was the last event received"
+ );
+ browser.test.assertEq(
+ id,
+ changedData.id,
+ "onChanged event received the expected id"
+ );
+ browser.test.assertEq(
+ title,
+ changedData.info.title,
+ "onChanged event received the expected title"
+ );
+ }
+
+ function checkOnMoved(id, parentId, oldParentId, index, oldIndex) {
+ let movedData = collectedEvents.pop();
+ browser.test.assertEq(
+ "onMoved",
+ movedData.event,
+ "onMoved was the last event received"
+ );
+ browser.test.assertEq(
+ id,
+ movedData.id,
+ "onMoved event received the expected id"
+ );
+ let info = movedData.info;
+ browser.test.assertEq(
+ parentId,
+ info.parentId,
+ "onMoved event received the expected parentId"
+ );
+ browser.test.assertEq(
+ oldParentId,
+ info.oldParentId,
+ "onMoved event received the expected oldParentId"
+ );
+ browser.test.assertEq(
+ index,
+ info.index,
+ "onMoved event received the expected index"
+ );
+ browser.test.assertEq(
+ oldIndex,
+ info.oldIndex,
+ "onMoved event received the expected oldIndex"
+ );
+ }
+
+ function checkOnRemoved(id, parentId, index, title, url, type = "folder") {
+ let removedData = collectedEvents.pop();
+ browser.test.assertEq(
+ "onRemoved",
+ removedData.event,
+ "onRemoved was the last event received"
+ );
+ browser.test.assertEq(
+ id,
+ removedData.id,
+ "onRemoved event received the expected id"
+ );
+ let info = removedData.info;
+ browser.test.assertEq(
+ parentId,
+ removedData.info.parentId,
+ "onRemoved event received the expected parentId"
+ );
+ browser.test.assertEq(
+ index,
+ removedData.info.index,
+ "onRemoved event received the expected index"
+ );
+ let node = info.node;
+ browser.test.assertEq(
+ id,
+ node.id,
+ "onRemoved event received the expected node id"
+ );
+ browser.test.assertEq(
+ parentId,
+ node.parentId,
+ "onRemoved event received the expected node parentId"
+ );
+ browser.test.assertEq(
+ index,
+ node.index,
+ "onRemoved event received the expected node index"
+ );
+ browser.test.assertEq(
+ url,
+ node.url,
+ "onRemoved event received the expected node url"
+ );
+ browser.test.assertEq(
+ title,
+ node.title,
+ "onRemoved event received the expected node title"
+ );
+ browser.test.assertEq(
+ type,
+ node.type,
+ "onRemoved event received the expected node type"
+ );
+ }
+
+ browser.bookmarks.onChanged.addListener((id, info) => {
+ collectedEvents.push({ event: "onChanged", id, info });
+ });
+
+ browser.bookmarks.onCreated.addListener((id, bookmark) => {
+ collectedEvents.push({ event: "onCreated", id, bookmark });
+ });
+
+ browser.bookmarks.onMoved.addListener((id, info) => {
+ collectedEvents.push({ event: "onMoved", id, info });
+ });
+
+ browser.bookmarks.onRemoved.addListener((id, info) => {
+ collectedEvents.push({ event: "onRemoved", id, info });
+ });
+
+ await browser.test.assertRejects(
+ browser.bookmarks.get(["not-a-bookmark-guid"]),
+ /Invalid value for property 'guid': "not-a-bookmark-guid"/,
+ "Expected error thrown when trying to get a bookmark using an invalid guid"
+ );
+
+ await browser.test
+ .assertRejects(
+ browser.bookmarks.get([nonExistentId]),
+ /Bookmark not found/,
+ "Expected error thrown when trying to get a bookmark using a non-existent Id"
+ )
+ .then(() => {
+ return browser.bookmarks.search({});
+ })
+ .then(results => {
+ initialBookmarkCount = results.length;
+ return browser.bookmarks.create({
+ title: "test bookmark",
+ url: "http://example.org",
+ type: "bookmark",
+ });
+ })
+ .then(result => {
+ ourId = result.id;
+ checkOurBookmark(result);
+ browser.test.assertEq(
+ 1,
+ collectedEvents.length,
+ "1 expected event received"
+ );
+ checkOnCreated(
+ ourId,
+ bookmarkGuids.unfiledGuid,
+ 0,
+ "test bookmark",
+ "http://example.org/",
+ result.dateAdded
+ );
+
+ return browser.bookmarks.get(ourId);
+ })
+ .then(results => {
+ browser.test.assertEq(results.length, 1);
+ checkOurBookmark(results[0]);
+
+ unsortedId = results[0].parentId;
+ return browser.bookmarks.get(unsortedId);
+ })
+ .then(results => {
+ let folder = results[0];
+ browser.test.assertEq(1, results.length, "1 bookmark was returned");
+
+ browser.test.assertEq(
+ unsortedId,
+ folder.id,
+ "Folder has the expected id"
+ );
+ browser.test.assertTrue("parentId" in folder, "Folder has a parentId");
+ browser.test.assertTrue("index" in folder, "Folder has an index");
+ browser.test.assertEq(
+ undefined,
+ folder.url,
+ "Folder does not have a url"
+ );
+ browser.test.assertEq(
+ "Other Bookmarks",
+ folder.title,
+ "Folder has the expected title"
+ );
+ browser.test.assertTrue(
+ "dateAdded" in folder,
+ "Folder has a dateAdded"
+ );
+ browser.test.assertTrue(
+ "dateGroupModified" in folder,
+ "Folder has a dateGroupModified"
+ );
+ browser.test.assertFalse(
+ "unmodifiable" in folder,
+ "Folder is not unmodifiable"
+ ); // TODO: Do we want to enable this?
+ browser.test.assertEq(
+ "folder",
+ folder.type,
+ "Folder has a type of folder"
+ );
+
+ return browser.bookmarks.getChildren(unsortedId);
+ })
+ .then(async results => {
+ browser.test.assertEq(1, results.length, "The folder has one child");
+ checkOurBookmark(results[0]);
+
+ await browser.test.assertRejects(
+ browser.bookmarks.update(nonExistentId, { title: "new test title" }),
+ /No bookmarks found for the provided GUID/,
+ "Expected error thrown when trying to update a non-existent bookmark"
+ );
+ return browser.bookmarks.update(ourId, {
+ title: "new test title",
+ url: "http://example.com/",
+ });
+ })
+ .then(async result => {
+ browser.test.assertEq(
+ "new test title",
+ result.title,
+ "Updated bookmark has the expected title"
+ );
+ browser.test.assertEq(
+ "http://example.com/",
+ result.url,
+ "Updated bookmark has the expected URL"
+ );
+ browser.test.assertEq(
+ ourId,
+ result.id,
+ "Updated bookmark has the expected id"
+ );
+ browser.test.assertEq(
+ "bookmark",
+ result.type,
+ "Updated bookmark has a type of bookmark"
+ );
+
+ browser.test.assertEq(
+ 2,
+ collectedEvents.length,
+ "2 expected events received"
+ );
+ checkOnChanged(ourId, "http://example.com/", "new test title");
+
+ await browser.test.assertRejects(
+ browser.bookmarks.update(ourId, { url: "this is not a valid url" }),
+ /Invalid bookmark:/,
+ "Expected error thrown when trying update with an invalid url"
+ );
+ return browser.bookmarks.getTree();
+ })
+ .then(results => {
+ browser.test.assertEq(1, results.length, "getTree returns one result");
+ let bookmark = results[0].children.find(
+ bookmarkItem => bookmarkItem.id == unsortedId
+ );
+ browser.test.assertEq(
+ "Other Bookmarks",
+ bookmark.title,
+ "Folder returned from getTree has the expected title"
+ );
+ browser.test.assertEq(
+ "folder",
+ bookmark.type,
+ "Folder returned from getTree has the expected type"
+ );
+
+ return browser.test.assertRejects(
+ browser.bookmarks.create({ parentId: "invalid" }),
+ error =>
+ error.message.includes("Invalid bookmark") &&
+ error.message.includes(`"parentGuid":"invalid"`),
+ "Expected error thrown when trying to create a bookmark with an invalid parentId"
+ );
+ })
+ .then(() => {
+ return browser.bookmarks.remove(ourId);
+ })
+ .then(result => {
+ browser.test.assertEq(
+ undefined,
+ result,
+ "Removing a bookmark returns undefined"
+ );
+
+ browser.test.assertEq(
+ 1,
+ collectedEvents.length,
+ "1 expected events received"
+ );
+ checkOnRemoved(
+ ourId,
+ bookmarkGuids.unfiledGuid,
+ 0,
+ "new test title",
+ "http://example.com/",
+ "bookmark"
+ );
+
+ return browser.test.assertRejects(
+ browser.bookmarks.get(ourId),
+ /Bookmark not found/,
+ "Expected error thrown when trying to get a removed bookmark"
+ );
+ })
+ .then(() => {
+ return browser.test.assertRejects(
+ browser.bookmarks.remove(nonExistentId),
+ /No bookmarks found for the provided GUID/,
+ "Expected error thrown when trying removed a non-existent bookmark"
+ );
+ })
+ .then(() => {
+ // test bookmarks.search
+ return Promise.all([
+ browser.bookmarks.create({
+ title: "Μοζιλλας",
+ url: "http://møzîllä.örg/",
+ }),
+ browser.bookmarks.create({
+ title: "Example",
+ url: "http://example.org/",
+ }),
+ browser.bookmarks.create({ title: "Mozilla Folder", type: "folder" }),
+ browser.bookmarks.create({ title: "EFF", url: "http://eff.org/" }),
+ browser.bookmarks.create({
+ title: "Menu Item",
+ url: "http://menu.org/",
+ parentId: bookmarkGuids.menuGuid,
+ }),
+ browser.bookmarks.create({
+ title: "Toolbar Item",
+ url: "http://toolbar.org/",
+ parentId: bookmarkGuids.toolbarGuid,
+ }),
+ ]);
+ })
+ .then(results => {
+ browser.test.assertEq(
+ 6,
+ collectedEvents.length,
+ "6 expected events received"
+ );
+ checkOnCreated(
+ results[5].id,
+ bookmarkGuids.toolbarGuid,
+ 0,
+ "Toolbar Item",
+ "http://toolbar.org/",
+ results[5].dateAdded
+ );
+ checkOnCreated(
+ results[4].id,
+ bookmarkGuids.menuGuid,
+ 0,
+ "Menu Item",
+ "http://menu.org/",
+ results[4].dateAdded
+ );
+ checkOnCreated(
+ results[3].id,
+ bookmarkGuids.unfiledGuid,
+ 0,
+ "EFF",
+ "http://eff.org/",
+ results[3].dateAdded
+ );
+ checkOnCreated(
+ results[2].id,
+ bookmarkGuids.unfiledGuid,
+ 0,
+ "Mozilla Folder",
+ undefined,
+ results[2].dateAdded,
+ "folder"
+ );
+ checkOnCreated(
+ results[1].id,
+ bookmarkGuids.unfiledGuid,
+ 0,
+ "Example",
+ "http://example.org/",
+ results[1].dateAdded
+ );
+ checkOnCreated(
+ results[0].id,
+ bookmarkGuids.unfiledGuid,
+ 0,
+ "Μοζιλλας",
+ "http://xn--mzll-ooa1dud.xn--rg-eka/",
+ results[0].dateAdded
+ );
+
+ for (let result of results) {
+ if (result.title !== "Mozilla Folder") {
+ createdBookmarks.add(result.id);
+ }
+ }
+ let folderResult = results[2];
+ createdFolderId = folderResult.id;
+ return Promise.all([
+ browser.bookmarks.create({
+ title: "Mozilla",
+ url: "http://allizom.org/",
+ parentId: createdFolderId,
+ }),
+ browser.bookmarks.create({
+ parentId: createdFolderId,
+ type: "separator",
+ }),
+ browser.bookmarks.create({
+ title: "Mozilla Corporation",
+ url: "http://allizom.com/",
+ parentId: createdFolderId,
+ }),
+ browser.bookmarks.create({
+ title: "Firefox",
+ url: "http://allizom.org/firefox/",
+ parentId: createdFolderId,
+ }),
+ ])
+ .then(newBookmarks => {
+ browser.test.assertEq(
+ 4,
+ collectedEvents.length,
+ "4 expected events received"
+ );
+ checkOnCreated(
+ newBookmarks[3].id,
+ createdFolderId,
+ 0,
+ "Firefox",
+ "http://allizom.org/firefox/",
+ newBookmarks[3].dateAdded
+ );
+ checkOnCreated(
+ newBookmarks[2].id,
+ createdFolderId,
+ 0,
+ "Mozilla Corporation",
+ "http://allizom.com/",
+ newBookmarks[2].dateAdded
+ );
+ checkOnCreated(
+ newBookmarks[1].id,
+ createdFolderId,
+ 0,
+ "",
+ "data:",
+ newBookmarks[1].dateAdded,
+ "separator"
+ );
+ checkOnCreated(
+ newBookmarks[0].id,
+ createdFolderId,
+ 0,
+ "Mozilla",
+ "http://allizom.org/",
+ newBookmarks[0].dateAdded
+ );
+
+ return browser.bookmarks.create({
+ title: "About Mozilla",
+ url: "http://allizom.org/about/",
+ parentId: createdFolderId,
+ index: 1,
+ });
+ })
+ .then(result => {
+ browser.test.assertEq(
+ 1,
+ collectedEvents.length,
+ "1 expected events received"
+ );
+ checkOnCreated(
+ result.id,
+ createdFolderId,
+ 1,
+ "About Mozilla",
+ "http://allizom.org/about/",
+ result.dateAdded
+ );
+
+ // returns all items on empty object
+ return browser.bookmarks.search({});
+ })
+ .then(async bookmarksSearchResults => {
+ browser.test.assertTrue(
+ bookmarksSearchResults.length >= 10,
+ "At least as many bookmarks as added were returned by search({})"
+ );
+
+ await browser.test.assertRejects(
+ browser.bookmarks.remove(createdFolderId),
+ /Cannot remove a non-empty folder/,
+ "Expected error thrown when trying to remove a non-empty folder"
+ );
+ return browser.bookmarks.getSubTree(createdFolderId);
+ });
+ })
+ .then(results => {
+ browser.test.assertEq(
+ 1,
+ results.length,
+ "Expected number of nodes returned by getSubTree"
+ );
+ browser.test.assertEq(
+ "Mozilla Folder",
+ results[0].title,
+ "Folder has the expected title"
+ );
+ browser.test.assertEq(
+ bookmarkGuids.unfiledGuid,
+ results[0].parentId,
+ "Folder has the expected parentId"
+ );
+ browser.test.assertEq(
+ "folder",
+ results[0].type,
+ "Folder has the expected type"
+ );
+ let children = results[0].children;
+ browser.test.assertEq(
+ 5,
+ children.length,
+ "Expected number of bookmarks returned by getSubTree"
+ );
+ browser.test.assertEq(
+ "Firefox",
+ children[0].title,
+ "Bookmark has the expected title"
+ );
+ browser.test.assertEq(
+ "bookmark",
+ children[0].type,
+ "Bookmark has the expected type"
+ );
+ browser.test.assertEq(
+ "About Mozilla",
+ children[1].title,
+ "Bookmark has the expected title"
+ );
+ browser.test.assertEq(
+ "bookmark",
+ children[1].type,
+ "Bookmark has the expected type"
+ );
+ browser.test.assertEq(
+ 1,
+ children[1].index,
+ "Bookmark has the expected index"
+ );
+ browser.test.assertEq(
+ "Mozilla Corporation",
+ children[2].title,
+ "Bookmark has the expected title"
+ );
+ browser.test.assertEq(
+ "",
+ children[3].title,
+ "Separator has the expected title"
+ );
+ browser.test.assertEq(
+ "data:",
+ children[3].url,
+ "Separator has the expected url"
+ );
+ browser.test.assertEq(
+ "separator",
+ children[3].type,
+ "Separator has the expected type"
+ );
+ browser.test.assertEq(
+ "Mozilla",
+ children[4].title,
+ "Bookmark has the expected title"
+ );
+
+ // throws an error for invalid query objects
+ browser.test.assertThrows(
+ () => browser.bookmarks.search(),
+ /Incorrect argument types for bookmarks.search/,
+ "Expected error thrown when trying to search with no arguments"
+ );
+
+ browser.test.assertThrows(
+ () => browser.bookmarks.search(null),
+ /Incorrect argument types for bookmarks.search/,
+ "Expected error thrown when trying to search with null as an argument"
+ );
+
+ browser.test.assertThrows(
+ () => browser.bookmarks.search(() => {}),
+ /Incorrect argument types for bookmarks.search/,
+ "Expected error thrown when trying to search with a function as an argument"
+ );
+
+ browser.test.assertThrows(
+ () => browser.bookmarks.search({ banana: "banana" }),
+ /an unexpected "banana" property/,
+ "Expected error thrown when trying to search with a banana as an argument"
+ );
+
+ browser.test.assertThrows(
+ () => browser.bookmarks.search({ url: "spider-man vs. batman" }),
+ /must match the format "url"/,
+ "Expected error thrown when trying to search with a illegally formatted URL"
+ );
+ // queries the full url
+ return browser.bookmarks.search("http://example.org/");
+ })
+ .then(results => {
+ browser.test.assertEq(
+ 1,
+ results.length,
+ "Expected number of results returned for url search"
+ );
+ checkBookmark(
+ { title: "Example", url: "http://example.org/", index: 2 },
+ results[0]
+ );
+
+ // queries a partial url
+ return browser.bookmarks.search("example.org");
+ })
+ .then(results => {
+ browser.test.assertEq(
+ 1,
+ results.length,
+ "Expected number of results returned for url search"
+ );
+ checkBookmark(
+ { title: "Example", url: "http://example.org/", index: 2 },
+ results[0]
+ );
+
+ // queries the title
+ return browser.bookmarks.search("EFF");
+ })
+ .then(results => {
+ browser.test.assertEq(
+ 1,
+ results.length,
+ "Expected number of results returned for title search"
+ );
+ checkBookmark(
+ {
+ title: "EFF",
+ url: "http://eff.org/",
+ index: 0,
+ parentId: bookmarkGuids.unfiledGuid,
+ },
+ results[0]
+ );
+
+ // finds menu items
+ return browser.bookmarks.search("Menu Item");
+ })
+ .then(results => {
+ browser.test.assertEq(
+ 1,
+ results.length,
+ "Expected number of results returned for menu item search"
+ );
+ checkBookmark(
+ {
+ title: "Menu Item",
+ url: "http://menu.org/",
+ index: 0,
+ parentId: bookmarkGuids.menuGuid,
+ },
+ results[0]
+ );
+
+ // finds toolbar items
+ return browser.bookmarks.search("Toolbar Item");
+ })
+ .then(results => {
+ browser.test.assertEq(
+ 1,
+ results.length,
+ "Expected number of results returned for toolbar item search"
+ );
+ checkBookmark(
+ {
+ title: "Toolbar Item",
+ url: "http://toolbar.org/",
+ index: 0,
+ parentId: bookmarkGuids.toolbarGuid,
+ },
+ results[0]
+ );
+
+ // finds folders
+ return browser.bookmarks.search("Mozilla Folder");
+ })
+ .then(results => {
+ browser.test.assertEq(
+ 1,
+ results.length,
+ "Expected number of folders returned"
+ );
+ browser.test.assertEq(
+ "Mozilla Folder",
+ results[0].title,
+ "Folder has the expected title"
+ );
+ browser.test.assertEq(
+ "folder",
+ results[0].type,
+ "Folder has the expected type"
+ );
+
+ // is case-insensitive
+ return browser.bookmarks.search("corporation");
+ })
+ .then(results => {
+ browser.test.assertEq(
+ 1,
+ results.length,
+ "Expected number of results returnedfor case-insensitive search"
+ );
+ browser.test.assertEq(
+ "Mozilla Corporation",
+ results[0].title,
+ "Bookmark has the expected title"
+ );
+
+ // is case-insensitive for non-ascii
+ return browser.bookmarks.search("ΜοΖΙΛΛΑς");
+ })
+ .then(results => {
+ browser.test.assertEq(
+ 1,
+ results.length,
+ "Expected number of results returned for non-ascii search"
+ );
+ browser.test.assertEq(
+ "Μοζιλλας",
+ results[0].title,
+ "Bookmark has the expected title"
+ );
+
+ // returns multiple results
+ return browser.bookmarks.search("allizom");
+ })
+ .then(results => {
+ browser.test.assertEq(
+ 4,
+ results.length,
+ "Expected number of multiple results returned"
+ );
+ browser.test.assertEq(
+ "Mozilla",
+ results[0].title,
+ "Bookmark has the expected title"
+ );
+ browser.test.assertEq(
+ "Mozilla Corporation",
+ results[1].title,
+ "Bookmark has the expected title"
+ );
+ browser.test.assertEq(
+ "Firefox",
+ results[2].title,
+ "Bookmark has the expected title"
+ );
+ browser.test.assertEq(
+ "About Mozilla",
+ results[3].title,
+ "Bookmark has the expected title"
+ );
+
+ // accepts a url field
+ return browser.bookmarks.search({ url: "http://allizom.com/" });
+ })
+ .then(results => {
+ browser.test.assertEq(
+ 1,
+ results.length,
+ "Expected number of results returned for url field"
+ );
+ checkBookmark(
+ {
+ title: "Mozilla Corporation",
+ url: "http://allizom.com/",
+ index: 2,
+ },
+ results[0]
+ );
+
+ // normalizes urls
+ return browser.bookmarks.search({ url: "http://allizom.com" });
+ })
+ .then(results => {
+ browser.test.assertEq(
+ results.length,
+ 1,
+ "Expected number of results returned for normalized url field"
+ );
+ checkBookmark(
+ {
+ title: "Mozilla Corporation",
+ url: "http://allizom.com/",
+ index: 2,
+ },
+ results[0]
+ );
+
+ // normalizes urls even more
+ return browser.bookmarks.search({ url: "http:allizom.com" });
+ })
+ .then(results => {
+ browser.test.assertEq(
+ results.length,
+ 1,
+ "Expected number of results returned for normalized url field"
+ );
+ checkBookmark(
+ {
+ title: "Mozilla Corporation",
+ url: "http://allizom.com/",
+ index: 2,
+ },
+ results[0]
+ );
+
+ // accepts a title field
+ return browser.bookmarks.search({ title: "Mozilla" });
+ })
+ .then(results => {
+ browser.test.assertEq(
+ results.length,
+ 1,
+ "Expected number of results returned for title field"
+ );
+ checkBookmark(
+ { title: "Mozilla", url: "http://allizom.org/", index: 4 },
+ results[0]
+ );
+
+ // can combine title and query
+ return browser.bookmarks.search({ title: "Mozilla", query: "allizom" });
+ })
+ .then(results => {
+ browser.test.assertEq(
+ 1,
+ results.length,
+ "Expected number of results returned for title and query fields"
+ );
+ checkBookmark(
+ { title: "Mozilla", url: "http://allizom.org/", index: 4 },
+ results[0]
+ );
+
+ // uses AND conditions
+ return browser.bookmarks.search({ title: "EFF", query: "allizom" });
+ })
+ .then(results => {
+ browser.test.assertEq(
+ 0,
+ results.length,
+ "Expected number of results returned for non-matching title and query fields"
+ );
+
+ // returns an empty array on item not found
+ return browser.bookmarks.search("microsoft");
+ })
+ .then(results => {
+ browser.test.assertEq(
+ 0,
+ results.length,
+ "Expected number of results returned for non-matching search"
+ );
+
+ browser.test.assertThrows(
+ () => browser.bookmarks.getRecent(""),
+ /Incorrect argument types for bookmarks.getRecent/,
+ "Expected error thrown when calling getRecent with an empty string"
+ );
+ })
+ .then(() => {
+ browser.test.assertThrows(
+ () => browser.bookmarks.getRecent(1.234),
+ /Incorrect argument types for bookmarks.getRecent/,
+ "Expected error thrown when calling getRecent with a decimal number"
+ );
+ })
+ .then(() => {
+ return Promise.all([
+ browser.bookmarks.search("corporation"),
+ browser.bookmarks.getChildren(bookmarkGuids.menuGuid),
+ ]);
+ })
+ .then(results => {
+ let corporationBookmark = results[0][0];
+ let childCount = results[1].length;
+
+ browser.test.assertEq(
+ 2,
+ corporationBookmark.index,
+ "Bookmark has the expected index"
+ );
+
+ return browser.bookmarks
+ .move(corporationBookmark.id, { index: 0 })
+ .then(result => {
+ browser.test.assertEq(
+ 0,
+ result.index,
+ "Bookmark has the expected index"
+ );
+
+ browser.test.assertEq(
+ 1,
+ collectedEvents.length,
+ "1 expected events received"
+ );
+ checkOnMoved(
+ corporationBookmark.id,
+ createdFolderId,
+ createdFolderId,
+ 0,
+ 2
+ );
+
+ return browser.bookmarks.move(corporationBookmark.id, {
+ parentId: bookmarkGuids.menuGuid,
+ });
+ })
+ .then(result => {
+ browser.test.assertEq(
+ bookmarkGuids.menuGuid,
+ result.parentId,
+ "Bookmark has the expected parent"
+ );
+ browser.test.assertEq(
+ childCount,
+ result.index,
+ "Bookmark has the expected index"
+ );
+
+ browser.test.assertEq(
+ 1,
+ collectedEvents.length,
+ "1 expected events received"
+ );
+ checkOnMoved(
+ corporationBookmark.id,
+ bookmarkGuids.menuGuid,
+ createdFolderId,
+ 1,
+ 0
+ );
+
+ return browser.bookmarks.move(corporationBookmark.id, { index: 0 });
+ })
+ .then(result => {
+ browser.test.assertEq(
+ bookmarkGuids.menuGuid,
+ result.parentId,
+ "Bookmark has the expected parent"
+ );
+ browser.test.assertEq(
+ 0,
+ result.index,
+ "Bookmark has the expected index"
+ );
+
+ browser.test.assertEq(
+ 1,
+ collectedEvents.length,
+ "1 expected events received"
+ );
+ checkOnMoved(
+ corporationBookmark.id,
+ bookmarkGuids.menuGuid,
+ bookmarkGuids.menuGuid,
+ 0,
+ 1
+ );
+
+ return browser.bookmarks.move(corporationBookmark.id, {
+ parentId: bookmarkGuids.toolbarGuid,
+ index: 1,
+ });
+ })
+ .then(result => {
+ browser.test.assertEq(
+ bookmarkGuids.toolbarGuid,
+ result.parentId,
+ "Bookmark has the expected parent"
+ );
+ browser.test.assertEq(
+ 1,
+ result.index,
+ "Bookmark has the expected index"
+ );
+
+ browser.test.assertEq(
+ 1,
+ collectedEvents.length,
+ "1 expected events received"
+ );
+ checkOnMoved(
+ corporationBookmark.id,
+ bookmarkGuids.toolbarGuid,
+ bookmarkGuids.menuGuid,
+ 1,
+ 0
+ );
+
+ createdBookmarks.add(corporationBookmark.id);
+ });
+ })
+ .then(() => {
+ return browser.bookmarks.getRecent(4);
+ })
+ .then(results => {
+ browser.test.assertEq(
+ 4,
+ results.length,
+ "Expected number of results returned by getRecent"
+ );
+ let prevDate = results[0].dateAdded;
+ for (let bookmark of results) {
+ browser.test.assertTrue(
+ bookmark.dateAdded <= prevDate,
+ "The recent bookmarks are sorted by dateAdded"
+ );
+ prevDate = bookmark.dateAdded;
+ }
+ let bookmarksByTitle = results.sort((a, b) => {
+ return a.title.localeCompare(b.title);
+ });
+ browser.test.assertEq(
+ "About Mozilla",
+ bookmarksByTitle[0].title,
+ "Bookmark has the expected title"
+ );
+ browser.test.assertEq(
+ "Firefox",
+ bookmarksByTitle[1].title,
+ "Bookmark has the expected title"
+ );
+ browser.test.assertEq(
+ "Mozilla",
+ bookmarksByTitle[2].title,
+ "Bookmark has the expected title"
+ );
+ browser.test.assertEq(
+ "Mozilla Corporation",
+ bookmarksByTitle[3].title,
+ "Bookmark has the expected title"
+ );
+
+ return browser.bookmarks.search({});
+ })
+ .then(results => {
+ let startBookmarkCount = results.length;
+
+ return browser.bookmarks
+ .search({ title: "Mozilla Folder" })
+ .then(result => {
+ return browser.bookmarks.removeTree(result[0].id);
+ })
+ .then(() => {
+ browser.test.assertEq(
+ 1,
+ collectedEvents.length,
+ "1 expected events received"
+ );
+ checkOnRemoved(
+ createdFolderId,
+ bookmarkGuids.unfiledGuid,
+ 1,
+ "Mozilla Folder"
+ );
+
+ return browser.bookmarks.search({}).then(searchResults => {
+ browser.test.assertEq(
+ startBookmarkCount - 5,
+ searchResults.length,
+ "Expected number of results returned after removeTree"
+ );
+ });
+ });
+ })
+ .then(() => {
+ return browser.bookmarks.create({ title: "Empty Folder" });
+ })
+ .then(result => {
+ createdFolderId = result.id;
+
+ browser.test.assertEq(
+ 1,
+ collectedEvents.length,
+ "1 expected events received"
+ );
+ checkOnCreated(
+ createdFolderId,
+ bookmarkGuids.unfiledGuid,
+ 3,
+ "Empty Folder",
+ undefined,
+ result.dateAdded,
+ "folder"
+ );
+
+ browser.test.assertEq(
+ "Empty Folder",
+ result.title,
+ "Folder has the expected title"
+ );
+ browser.test.assertEq(
+ "folder",
+ result.type,
+ "Folder has the expected type"
+ );
+
+ return browser.bookmarks.create({
+ parentId: createdFolderId,
+ type: "separator",
+ });
+ })
+ .then(result => {
+ createdSeparatorId = result.id;
+ browser.test.assertEq(
+ 1,
+ collectedEvents.length,
+ "1 expected events received"
+ );
+ checkOnCreated(
+ createdSeparatorId,
+ createdFolderId,
+ 0,
+ "",
+ "data:",
+ result.dateAdded,
+ "separator"
+ );
+ return browser.bookmarks.remove(createdSeparatorId);
+ })
+ .then(() => {
+ browser.test.assertEq(
+ 1,
+ collectedEvents.length,
+ "1 expected events received"
+ );
+ checkOnRemoved(
+ createdSeparatorId,
+ createdFolderId,
+ 0,
+ "",
+ "data:",
+ "separator"
+ );
+
+ return browser.bookmarks.remove(createdFolderId);
+ })
+ .then(() => {
+ browser.test.assertEq(
+ 1,
+ collectedEvents.length,
+ "1 expected events received"
+ );
+ checkOnRemoved(
+ createdFolderId,
+ bookmarkGuids.unfiledGuid,
+ 3,
+ "Empty Folder"
+ );
+
+ return browser.test.assertRejects(
+ browser.bookmarks.get(createdFolderId),
+ /Bookmark not found/,
+ "Expected error thrown when trying to get a removed folder"
+ );
+ })
+ .then(() => {
+ return browser.test.assertRejects(
+ browser.bookmarks.getChildren(nonExistentId),
+ /root is null/,
+ "Expected error thrown when trying to getChildren for a non-existent folder"
+ );
+ })
+ .then(() => {
+ return browser.test.assertRejects(
+ browser.bookmarks.move(nonExistentId, {}),
+ /No bookmarks found for the provided GUID/,
+ "Expected error thrown when calling move with a non-existent bookmark"
+ );
+ })
+ .then(() => {
+ return browser.test.assertRejects(
+ browser.bookmarks.create({
+ title: "test root folder",
+ parentId: bookmarkGuids.rootGuid,
+ }),
+ "The bookmark root cannot be modified",
+ "Expected error thrown when creating bookmark folder at the root"
+ );
+ })
+ .then(() => {
+ return browser.test.assertRejects(
+ browser.bookmarks.update(bookmarkGuids.rootGuid, {
+ title: "test update title",
+ }),
+ "The bookmark root cannot be modified",
+ "Expected error thrown when updating root"
+ );
+ })
+ .then(() => {
+ return browser.test.assertRejects(
+ browser.bookmarks.remove(bookmarkGuids.rootGuid),
+ "The bookmark root cannot be modified",
+ "Expected error thrown when removing root"
+ );
+ })
+ .then(() => {
+ return browser.test.assertRejects(
+ browser.bookmarks.removeTree(bookmarkGuids.rootGuid),
+ "The bookmark root cannot be modified",
+ "Expected error thrown when removing root tree"
+ );
+ })
+ .then(() => {
+ return browser.bookmarks.create({ title: "Empty Folder" });
+ })
+ .then(async result => {
+ createdFolderId = result.id;
+
+ browser.test.assertEq(
+ 1,
+ collectedEvents.length,
+ "1 expected events received"
+ );
+ checkOnCreated(
+ createdFolderId,
+ bookmarkGuids.unfiledGuid,
+ 3,
+ "Empty Folder",
+ undefined,
+ result.dateAdded,
+ "folder"
+ );
+
+ await browser.test.assertRejects(
+ browser.bookmarks.move(createdFolderId, {
+ parentId: bookmarkGuids.rootGuid,
+ }),
+ "The bookmark root cannot be modified",
+ "Expected error thrown when moving bookmark folder to the root"
+ );
+
+ return browser.bookmarks.remove(createdFolderId);
+ })
+ .then(() => {
+ browser.test.assertEq(
+ 1,
+ collectedEvents.length,
+ "1 expected events received"
+ );
+ checkOnRemoved(
+ createdFolderId,
+ bookmarkGuids.unfiledGuid,
+ 3,
+ "Empty Folder",
+ undefined,
+ "folder"
+ );
+
+ return browser.test.assertRejects(
+ browser.bookmarks.get(createdFolderId),
+ "Bookmark not found",
+ "Expected error thrown when trying to get a removed folder"
+ );
+ })
+ .then(() => {
+ return browser.test.assertRejects(
+ browser.bookmarks.move(bookmarkGuids.rootGuid, {
+ parentId: bookmarkGuids.unfiledGuid,
+ }),
+ "The bookmark root cannot be modified",
+ "Expected error thrown when moving root"
+ );
+ })
+ .then(() => {
+ // remove all created bookmarks
+ let promises = Array.from(createdBookmarks, guid =>
+ browser.bookmarks.remove(guid)
+ );
+ return Promise.all(promises);
+ })
+ .then(() => {
+ browser.test.assertEq(
+ createdBookmarks.size,
+ collectedEvents.length,
+ "expected number of events received"
+ );
+
+ return browser.bookmarks.search({});
+ })
+ .then(results => {
+ browser.test.assertEq(
+ initialBookmarkCount,
+ results.length,
+ "All created bookmarks have been removed"
+ );
+
+ return browser.test.notifyPass("bookmarks");
+ })
+ .catch(error => {
+ browser.test.fail(`Error: ${String(error)} :: ${error.stack}`);
+ browser.test.notifyFail("bookmarks");
+ });
+ }
+
+ let extension = ExtensionTestUtils.loadExtension({
+ background,
+ manifest: {
+ permissions: ["bookmarks"],
+ },
+ });
+
+ await extension.startup();
+ await extension.awaitFinish("bookmarks");
+ await extension.unload();
+});
+
+add_task(async function test_get_recent_with_tag_and_query() {
+ function background() {
+ browser.bookmarks.getRecent(100).then(bookmarks => {
+ browser.test.sendMessage("bookmarks", bookmarks);
+ });
+ }
+
+ let extension = ExtensionTestUtils.loadExtension({
+ background,
+ manifest: {
+ permissions: ["bookmarks"],
+ },
+ });
+
+ // Start with an empty bookmarks database.
+ await PlacesUtils.bookmarks.eraseEverything();
+
+ let createdBookmarks = [];
+ for (let i = 0; i < 3; i++) {
+ let bookmark = {
+ type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
+ url: `http://example.com/${i}`,
+ title: `My bookmark ${i}`,
+ parentGuid: PlacesUtils.bookmarks.unfiledGuid,
+ };
+ createdBookmarks.unshift(bookmark);
+ await PlacesUtils.bookmarks.insert(bookmark);
+ }
+
+ // Add a tag to the most recent url to prove it doesn't get returned.
+ PlacesUtils.tagging.tagURI(NetUtil.newURI("http://example.com/${i}"), [
+ "Test Tag",
+ ]);
+
+ // Add a query bookmark.
+ let queryURL = `place:parent=${PlacesUtils.bookmarks.menuGuid}&queryType=1`;
+ await PlacesUtils.bookmarks.insert({
+ parentGuid: PlacesUtils.bookmarks.unfiledGuid,
+ url: queryURL,
+ title: "a test query",
+ });
+
+ await extension.startup();
+ let receivedBookmarks = await extension.awaitMessage("bookmarks");
+
+ equal(
+ receivedBookmarks.length,
+ 3,
+ "The expected number of bookmarks was returned."
+ );
+ for (let i = 0; i < 3; i++) {
+ let actual = receivedBookmarks[i];
+ let expected = createdBookmarks[i];
+ equal(actual.url, expected.url, "Bookmark has the expected url.");
+ equal(actual.title, expected.title, "Bookmark has the expected title.");
+ equal(
+ actual.parentId,
+ expected.parentGuid,
+ "Bookmark has the expected parentId."
+ );
+ }
+
+ await extension.unload();
+});
+
+add_task(async function test_tree_with_empty_folder() {
+ async function background() {
+ await browser.bookmarks.create({ title: "Empty Folder" });
+ let nonEmptyFolder = await browser.bookmarks.create({
+ title: "Non-Empty Folder",
+ });
+ await browser.bookmarks.create({
+ title: "A bookmark",
+ url: "http://example.com",
+ parentId: nonEmptyFolder.id,
+ });
+
+ let tree = await browser.bookmarks.getSubTree(nonEmptyFolder.parentId);
+ browser.test.assertEq(
+ 0,
+ tree[0].children[0].children.length,
+ "The empty folder returns an empty array for children."
+ );
+ browser.test.assertEq(
+ 1,
+ tree[0].children[1].children.length,
+ "The non-empty folder returns a single item array for children."
+ );
+
+ let children = await browser.bookmarks.getChildren(nonEmptyFolder.parentId);
+ // getChildren should only return immediate children. This is not tested in the
+ // monster test above.
+ for (let child of children) {
+ browser.test.assertEq(
+ undefined,
+ child.children,
+ "Child from getChildren does not contain any children."
+ );
+ }
+
+ browser.test.sendMessage("done");
+ }
+
+ let extension = ExtensionTestUtils.loadExtension({
+ background,
+ manifest: {
+ permissions: ["bookmarks"],
+ },
+ });
+
+ // Start with an empty bookmarks database.
+ await PlacesUtils.bookmarks.eraseEverything();
+
+ await extension.startup();
+ await extension.awaitMessage("done");
+
+ await extension.unload();
+});
+
+add_task(
+ {
+ pref_set: [["extensions.eventPages.enabled", true]],
+ },
+ async function test_bookmarks_event_page() {
+ await AddonTestUtils.promiseStartupManager();
+ let extension = ExtensionTestUtils.loadExtension({
+ useAddonManager: "permanent",
+ manifest: {
+ browser_specific_settings: { gecko: { id: "eventpage@bookmarks" } },
+ permissions: ["bookmarks"],
+ background: { persistent: false },
+ },
+ background() {
+ browser.bookmarks.onCreated.addListener(() => {
+ browser.test.sendMessage("onCreated");
+ });
+ browser.bookmarks.onRemoved.addListener(() => {
+ browser.test.sendMessage("onRemoved");
+ });
+ browser.bookmarks.onChanged.addListener(() => {});
+ browser.bookmarks.onMoved.addListener(() => {});
+ browser.test.sendMessage("ready");
+ },
+ });
+
+ const EVENTS = ["onCreated", "onRemoved", "onChanged", "onMoved"];
+ await PlacesUtils.bookmarks.eraseEverything();
+
+ await extension.startup();
+ await extension.awaitMessage("ready");
+ for (let event of EVENTS) {
+ assertPersistentListeners(extension, "bookmarks", event, {
+ primed: false,
+ });
+ }
+
+ // test events waken background
+ await extension.terminateBackground();
+ for (let event of EVENTS) {
+ assertPersistentListeners(extension, "bookmarks", event, {
+ primed: true,
+ });
+ }
+
+ let bookmark = {
+ type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
+ url: `http://example.com/12345`,
+ title: `My bookmark 12345`,
+ parentGuid: PlacesUtils.bookmarks.unfiledGuid,
+ };
+ await PlacesUtils.bookmarks.insert(bookmark);
+
+ await extension.awaitMessage("ready");
+ await extension.awaitMessage("onCreated");
+ for (let event of EVENTS) {
+ assertPersistentListeners(extension, "bookmarks", event, {
+ primed: false,
+ });
+ }
+
+ await AddonTestUtils.promiseRestartManager();
+ await extension.awaitStartup();
+
+ for (let event of EVENTS) {
+ assertPersistentListeners(extension, "bookmarks", event, {
+ primed: true,
+ });
+ }
+
+ await PlacesUtils.bookmarks.eraseEverything();
+ await extension.awaitMessage("ready");
+ await extension.awaitMessage("onRemoved");
+
+ await extension.unload();
+ await AddonTestUtils.promiseShutdownManager();
+ }
+);