diff options
Diffstat (limited to 'toolkit/components/places/tests/bookmarks/test_bookmarks_notifications.js')
-rw-r--r-- | toolkit/components/places/tests/bookmarks/test_bookmarks_notifications.js | 1130 |
1 files changed, 1130 insertions, 0 deletions
diff --git a/toolkit/components/places/tests/bookmarks/test_bookmarks_notifications.js b/toolkit/components/places/tests/bookmarks/test_bookmarks_notifications.js new file mode 100644 index 0000000000..21b34838ed --- /dev/null +++ b/toolkit/components/places/tests/bookmarks/test_bookmarks_notifications.js @@ -0,0 +1,1130 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +ChromeUtils.defineESModuleGetters(this, { + Preferences: "resource://gre/modules/Preferences.sys.mjs", +}); + +add_task(async function insert_separator_notification() { + let observer = expectPlacesObserverNotifications(["bookmark-added"]); + let bm = await PlacesUtils.bookmarks.insert({ + type: PlacesUtils.bookmarks.TYPE_SEPARATOR, + parentGuid: PlacesUtils.bookmarks.unfiledGuid, + }); + let itemId = await PlacesUtils.promiseItemId(bm.guid); + let parentId = await PlacesUtils.promiseItemId(bm.parentGuid); + observer.check([ + { + type: "bookmark-added", + id: itemId, + itemType: PlacesUtils.bookmarks.TYPE_SEPARATOR, + parentId, + index: bm.index, + url: bm.url, + title: bm.title, + dateAdded: bm.dateAdded, + guid: bm.guid, + parentGuid: bm.parentGuid, + source: Ci.nsINavBookmarksService.SOURCE_DEFAULT, + isTagging: false, + }, + ]); +}); + +add_task(async function insert_folder_notification() { + let observer = expectPlacesObserverNotifications(["bookmark-added"]); + let bm = await PlacesUtils.bookmarks.insert({ + type: PlacesUtils.bookmarks.TYPE_FOLDER, + parentGuid: PlacesUtils.bookmarks.unfiledGuid, + title: "a folder", + }); + let itemId = await PlacesUtils.promiseItemId(bm.guid); + let parentId = await PlacesUtils.promiseItemId(bm.parentGuid); + observer.check([ + { + type: "bookmark-added", + id: itemId, + itemType: PlacesUtils.bookmarks.TYPE_FOLDER, + parentId, + index: bm.index, + url: bm.url, + title: bm.title, + dateAdded: bm.dateAdded, + guid: bm.guid, + parentGuid: bm.parentGuid, + source: Ci.nsINavBookmarksService.SOURCE_DEFAULT, + isTagging: false, + }, + ]); +}); + +add_task(async function insert_folder_notitle_notification() { + let observer = expectPlacesObserverNotifications(["bookmark-added"]); + let bm = await PlacesUtils.bookmarks.insert({ + type: PlacesUtils.bookmarks.TYPE_FOLDER, + parentGuid: PlacesUtils.bookmarks.unfiledGuid, + }); + strictEqual(bm.title, "", "Should return empty string for untitled folder"); + let itemId = await PlacesUtils.promiseItemId(bm.guid); + let parentId = await PlacesUtils.promiseItemId(bm.parentGuid); + observer.check([ + { + type: "bookmark-added", + id: itemId, + itemType: PlacesUtils.bookmarks.TYPE_FOLDER, + parentId, + index: bm.index, + url: bm.url, + title: bm.title, + dateAdded: bm.dateAdded, + guid: bm.guid, + parentGuid: bm.parentGuid, + source: Ci.nsINavBookmarksService.SOURCE_DEFAULT, + isTagging: false, + }, + ]); +}); + +add_task(async function insert_bookmark_notification() { + let observer = expectPlacesObserverNotifications(["bookmark-added"]); + let bm = await PlacesUtils.bookmarks.insert({ + type: PlacesUtils.bookmarks.TYPE_BOOKMARK, + parentGuid: PlacesUtils.bookmarks.unfiledGuid, + url: new URL("http://example.com/"), + title: "a bookmark", + }); + let itemId = await PlacesUtils.promiseItemId(bm.guid); + let parentId = await PlacesUtils.promiseItemId(bm.parentGuid); + observer.check([ + { + type: "bookmark-added", + id: itemId, + itemType: PlacesUtils.bookmarks.TYPE_BOOKMARK, + parentId, + index: bm.index, + url: bm.url, + title: bm.title, + dateAdded: bm.dateAdded, + guid: bm.guid, + parentGuid: bm.parentGuid, + source: Ci.nsINavBookmarksService.SOURCE_DEFAULT, + isTagging: false, + }, + ]); +}); + +add_task(async function insert_bookmark_notitle_notification() { + let observer = expectPlacesObserverNotifications(["bookmark-added"]); + let bm = await PlacesUtils.bookmarks.insert({ + type: PlacesUtils.bookmarks.TYPE_BOOKMARK, + parentGuid: PlacesUtils.bookmarks.unfiledGuid, + url: new URL("http://example.com/"), + }); + strictEqual(bm.title, "", "Should return empty string for untitled bookmark"); + let itemId = await PlacesUtils.promiseItemId(bm.guid); + let parentId = await PlacesUtils.promiseItemId(bm.parentGuid); + observer.check([ + { + type: "bookmark-added", + id: itemId, + itemType: PlacesUtils.bookmarks.TYPE_BOOKMARK, + parentId, + index: bm.index, + url: bm.url, + title: bm.title, + dateAdded: bm.dateAdded, + guid: bm.guid, + parentGuid: bm.parentGuid, + source: Ci.nsINavBookmarksService.SOURCE_DEFAULT, + isTagging: false, + }, + ]); +}); + +add_task(async function insert_bookmark_tag_notification() { + let bm = await PlacesUtils.bookmarks.insert({ + type: PlacesUtils.bookmarks.TYPE_BOOKMARK, + parentGuid: PlacesUtils.bookmarks.unfiledGuid, + url: new URL("http://tag.example.com/"), + }); + let itemId = await PlacesUtils.promiseItemId(bm.guid); + + let tagFolder = await PlacesUtils.bookmarks.insert({ + type: PlacesUtils.bookmarks.TYPE_FOLDER, + parentGuid: PlacesUtils.bookmarks.tagsGuid, + title: "tag", + }); + const observer = expectPlacesObserverNotifications([ + "bookmark-added", + "bookmark-tags-changed", + ]); + let tag = await PlacesUtils.bookmarks.insert({ + type: PlacesUtils.bookmarks.TYPE_BOOKMARK, + parentGuid: tagFolder.guid, + url: new URL("http://tag.example.com/"), + }); + let tagId = await PlacesUtils.promiseItemId(tag.guid); + let tagParentId = await PlacesUtils.promiseItemId(tag.parentGuid); + + observer.check([ + { + type: "bookmark-added", + id: tagId, + parentId: tagParentId, + index: tag.index, + itemType: tag.type, + url: tag.url, + title: "", + dateAdded: tag.dateAdded, + guid: tag.guid, + parentGuid: tag.parentGuid, + source: Ci.nsINavBookmarksService.SOURCE_DEFAULT, + isTagging: true, + }, + { + type: "bookmark-tags-changed", + id: itemId, + itemType: bm.type, + url: bm.url, + guid: bm.guid, + parentGuid: bm.parentGuid, + tags: ["tag"], + lastModified: bm.lastModified, + source: Ci.nsINavBookmarksService.SOURCE_DEFAULT, + isTagging: false, + }, + ]); +}); + +add_task(async function update_bookmark_lastModified() { + let timerPrecision = Preferences.get("privacy.reduceTimerPrecision"); + Preferences.set("privacy.reduceTimerPrecision", false); + + registerCleanupFunction(function() { + Preferences.set("privacy.reduceTimerPrecision", timerPrecision); + }); + + let bm = await PlacesUtils.bookmarks.insert({ + type: PlacesUtils.bookmarks.TYPE_BOOKMARK, + parentGuid: PlacesUtils.bookmarks.unfiledGuid, + url: new URL("http://lastmod.example.com/"), + }); + const observer = expectPlacesObserverNotifications(["bookmark-time-changed"]); + bm = await PlacesUtils.bookmarks.update({ + guid: bm.guid, + lastModified: new Date(), + }); + let itemId = await PlacesUtils.promiseItemId(bm.guid); + + observer.check([ + { + type: "bookmark-time-changed", + id: itemId, + itemType: bm.type, + url: bm.url, + guid: bm.guid, + parentGuid: bm.parentGuid, + dateAdded: bm.dateAdded, + lastModified: bm.lastModified, + source: Ci.nsINavBookmarksService.SOURCE_DEFAULT, + isTagging: false, + }, + ]); +}); + +add_task(async function update_bookmark_title() { + let bm = await PlacesUtils.bookmarks.insert({ + type: PlacesUtils.bookmarks.TYPE_BOOKMARK, + parentGuid: PlacesUtils.bookmarks.unfiledGuid, + url: new URL("http://title.example.com/"), + }); + const observer = expectPlacesObserverNotifications([ + "bookmark-title-changed", + ]); + bm = await PlacesUtils.bookmarks.update({ + guid: bm.guid, + title: "new title", + }); + let itemId = await PlacesUtils.promiseItemId(bm.guid); + + observer.check([ + { + type: "bookmark-title-changed", + id: itemId, + itemType: bm.type, + url: bm.url, + title: bm.title, + guid: bm.guid, + parentGuid: bm.parentGuid, + lastModified: bm.lastModified, + source: Ci.nsINavBookmarksService.SOURCE_DEFAULT, + isTagging: false, + }, + ]); +}); + +add_task(async function update_bookmark_uri() { + let bm = await PlacesUtils.bookmarks.insert({ + type: PlacesUtils.bookmarks.TYPE_BOOKMARK, + parentGuid: PlacesUtils.bookmarks.unfiledGuid, + url: new URL("http://url.example.com/"), + }); + const observer = expectPlacesObserverNotifications(["bookmark-url-changed"]); + bm = await PlacesUtils.bookmarks.update({ + guid: bm.guid, + url: "http://mozilla.org/", + }); + let itemId = await PlacesUtils.promiseItemId(bm.guid); + + observer.check([ + { + type: "bookmark-url-changed", + id: itemId, + itemType: bm.type, + url: bm.url.href, + guid: bm.guid, + parentGuid: bm.parentGuid, + source: Ci.nsINavBookmarksService.SOURCE_DEFAULT, + isTagging: false, + lastModified: bm.lastModified, + }, + ]); +}); + +add_task(async function update_move_same_folder() { + // Ensure there are at least two items in place (others test do so for us, + // but we don't have to depend on that). + await PlacesUtils.bookmarks.insert({ + type: PlacesUtils.bookmarks.TYPE_SEPARATOR, + parentGuid: PlacesUtils.bookmarks.unfiledGuid, + }); + let bm = await PlacesUtils.bookmarks.insert({ + type: PlacesUtils.bookmarks.TYPE_BOOKMARK, + parentGuid: PlacesUtils.bookmarks.unfiledGuid, + url: new URL("http://move.example.com/"), + }); + let bmItemId = await PlacesUtils.promiseItemId(bm.guid); + let bmOldIndex = bm.index; + + let observer = expectPlacesObserverNotifications(["bookmark-moved"]); + + bm = await PlacesUtils.bookmarks.update({ + guid: bm.guid, + parentGuid: PlacesUtils.bookmarks.unfiledGuid, + index: 0, + }); + Assert.equal(bm.index, 0); + observer.check([ + { + type: "bookmark-moved", + id: bmItemId, + itemType: bm.type, + url: "http://move.example.com/", + guid: bm.guid, + parentGuid: bm.parentGuid, + source: Ci.nsINavBookmarksService.SOURCE_DEFAULT, + index: bm.index, + oldParentGuid: bm.parentGuid, + oldIndex: bmOldIndex, + isTagging: false, + }, + ]); + + // Test that we get the right index for DEFAULT_INDEX input. + bmOldIndex = 0; + observer = expectPlacesObserverNotifications(["bookmark-moved"]); + bm = await PlacesUtils.bookmarks.update({ + guid: bm.guid, + parentGuid: PlacesUtils.bookmarks.unfiledGuid, + index: PlacesUtils.bookmarks.DEFAULT_INDEX, + }); + Assert.ok(bm.index > 0); + observer.check([ + { + type: "bookmark-moved", + id: bmItemId, + itemType: bm.type, + url: bm.url, + guid: bm.guid, + parentGuid: bm.parentGuid, + source: Ci.nsINavBookmarksService.SOURCE_DEFAULT, + index: bm.index, + oldParentGuid: bm.parentGuid, + oldIndex: bmOldIndex, + isTagging: false, + }, + ]); +}); + +add_task(async function update_move_different_folder() { + let bm = await PlacesUtils.bookmarks.insert({ + type: PlacesUtils.bookmarks.TYPE_BOOKMARK, + parentGuid: PlacesUtils.bookmarks.unfiledGuid, + url: new URL("http://move.example.com/"), + }); + let folder = await PlacesUtils.bookmarks.insert({ + type: PlacesUtils.bookmarks.TYPE_FOLDER, + parentGuid: PlacesUtils.bookmarks.unfiledGuid, + }); + let bmItemId = await PlacesUtils.promiseItemId(bm.guid); + let bmOldIndex = bm.index; + + const observer = expectPlacesObserverNotifications(["bookmark-moved"]); + bm = await PlacesUtils.bookmarks.update({ + guid: bm.guid, + parentGuid: folder.guid, + index: PlacesUtils.bookmarks.DEFAULT_INDEX, + }); + Assert.equal(bm.index, 0); + observer.check([ + { + type: "bookmark-moved", + id: bmItemId, + itemType: bm.type, + url: "http://move.example.com/", + guid: bm.guid, + parentGuid: bm.parentGuid, + source: Ci.nsINavBookmarksService.SOURCE_DEFAULT, + index: bm.index, + oldParentGuid: PlacesUtils.bookmarks.unfiledGuid, + oldIndex: bmOldIndex, + isTagging: false, + }, + ]); +}); + +add_task(async function update_move_tag_folder() { + let bm = await PlacesUtils.bookmarks.insert({ + type: PlacesUtils.bookmarks.TYPE_BOOKMARK, + parentGuid: PlacesUtils.bookmarks.unfiledGuid, + url: new URL("http://move.example.com/"), + }); + let folder = await PlacesUtils.bookmarks.insert({ + type: PlacesUtils.bookmarks.TYPE_FOLDER, + parentGuid: PlacesUtils.bookmarks.tagsGuid, + title: "tag", + }); + let bmItemId = await PlacesUtils.promiseItemId(bm.guid); + let bmOldIndex = bm.index; + + const observer = expectPlacesObserverNotifications(["bookmark-moved"]); + bm = await PlacesUtils.bookmarks.update({ + guid: bm.guid, + parentGuid: folder.guid, + index: PlacesUtils.bookmarks.DEFAULT_INDEX, + }); + Assert.equal(bm.index, 0); + observer.check([ + { + type: "bookmark-moved", + id: bmItemId, + itemType: bm.type, + url: "http://move.example.com/", + guid: bm.guid, + parentGuid: bm.parentGuid, + source: Ci.nsINavBookmarksService.SOURCE_DEFAULT, + index: bm.index, + oldParentGuid: PlacesUtils.bookmarks.unfiledGuid, + oldIndex: bmOldIndex, + isTagging: true, + }, + ]); +}); + +add_task(async function remove_bookmark() { + let bm = await PlacesUtils.bookmarks.insert({ + type: PlacesUtils.bookmarks.TYPE_BOOKMARK, + parentGuid: PlacesUtils.bookmarks.unfiledGuid, + url: new URL("http://remove.example.com/"), + }); + let itemId = await PlacesUtils.promiseItemId(bm.guid); + let parentId = await PlacesUtils.promiseItemId(bm.parentGuid); + + let observer = expectPlacesObserverNotifications(["bookmark-removed"]); + await PlacesUtils.bookmarks.remove(bm.guid); + observer.check([ + { + type: "bookmark-removed", + id: itemId, + parentId, + index: bm.index, + url: bm.url, + guid: bm.guid, + parentGuid: bm.parentGuid, + source: Ci.nsINavBookmarksService.SOURCE_DEFAULT, + itemType: PlacesUtils.bookmarks.TYPE_BOOKMARK, + isTagging: false, + }, + ]); +}); + +add_task(async function remove_multiple_bookmarks() { + let bm1 = await PlacesUtils.bookmarks.insert({ + type: PlacesUtils.bookmarks.TYPE_BOOKMARK, + parentGuid: PlacesUtils.bookmarks.unfiledGuid, + url: "http://remove.example.com/", + }); + let bm2 = await PlacesUtils.bookmarks.insert({ + type: PlacesUtils.bookmarks.TYPE_BOOKMARK, + parentGuid: PlacesUtils.bookmarks.unfiledGuid, + url: "http://remove1.example.com/", + }); + let itemId1 = await PlacesUtils.promiseItemId(bm1.guid); + let parentId1 = await PlacesUtils.promiseItemId(bm1.parentGuid); + let itemId2 = await PlacesUtils.promiseItemId(bm2.guid); + let parentId2 = await PlacesUtils.promiseItemId(bm2.parentGuid); + + let observer = expectPlacesObserverNotifications(["bookmark-removed"]); + await PlacesUtils.bookmarks.remove([bm1, bm2]); + observer.check([ + { + type: "bookmark-removed", + id: itemId1, + parentId: parentId1, + index: bm1.index, + url: bm1.url, + guid: bm1.guid, + parentGuid: bm1.parentGuid, + source: Ci.nsINavBookmarksService.SOURCE_DEFAULT, + itemType: PlacesUtils.bookmarks.TYPE_BOOKMARK, + isTagging: false, + }, + { + type: "bookmark-removed", + id: itemId2, + parentId: parentId2, + index: bm2.index - 1, + url: bm2.url, + guid: bm2.guid, + parentGuid: bm2.parentGuid, + source: Ci.nsINavBookmarksService.SOURCE_DEFAULT, + itemType: PlacesUtils.bookmarks.TYPE_BOOKMARK, + isTagging: false, + }, + ]); +}); + +add_task(async function remove_folder() { + let bm = await PlacesUtils.bookmarks.insert({ + type: PlacesUtils.bookmarks.TYPE_FOLDER, + parentGuid: PlacesUtils.bookmarks.unfiledGuid, + }); + let itemId = await PlacesUtils.promiseItemId(bm.guid); + let parentId = await PlacesUtils.promiseItemId(bm.parentGuid); + + let observer = expectPlacesObserverNotifications(["bookmark-removed"]); + await PlacesUtils.bookmarks.remove(bm.guid); + observer.check([ + { + type: "bookmark-removed", + id: itemId, + parentId, + index: bm.index, + url: null, + guid: bm.guid, + parentGuid: bm.parentGuid, + source: Ci.nsINavBookmarksService.SOURCE_DEFAULT, + itemType: PlacesUtils.bookmarks.TYPE_FOLDER, + isTagging: false, + }, + ]); +}); + +add_task(async function remove_bookmark_tag_notification() { + let bm = await PlacesUtils.bookmarks.insert({ + type: PlacesUtils.bookmarks.TYPE_BOOKMARK, + parentGuid: PlacesUtils.bookmarks.unfiledGuid, + url: new URL("http://untag.example.com/"), + }); + let itemId = await PlacesUtils.promiseItemId(bm.guid); + + let tagFolder = await PlacesUtils.bookmarks.insert({ + type: PlacesUtils.bookmarks.TYPE_FOLDER, + parentGuid: PlacesUtils.bookmarks.tagsGuid, + title: "tag", + }); + let tag = await PlacesUtils.bookmarks.insert({ + type: PlacesUtils.bookmarks.TYPE_BOOKMARK, + parentGuid: tagFolder.guid, + url: new URL("http://untag.example.com/"), + }); + let tagId = await PlacesUtils.promiseItemId(tag.guid); + let tagParentId = await PlacesUtils.promiseItemId(tag.parentGuid); + + const observer = expectPlacesObserverNotifications([ + "bookmark-removed", + "bookmark-tags-changed", + ]); + await PlacesUtils.bookmarks.remove(tag.guid); + + observer.check([ + { + type: "bookmark-removed", + id: tagId, + parentId: tagParentId, + index: tag.index, + url: tag.url, + guid: tag.guid, + parentGuid: tag.parentGuid, + source: Ci.nsINavBookmarksService.SOURCE_DEFAULT, + itemType: PlacesUtils.bookmarks.TYPE_BOOKMARK, + isTagging: true, + }, + { + type: "bookmark-tags-changed", + id: itemId, + itemType: bm.type, + url: bm.url, + guid: bm.guid, + parentGuid: bm.parentGuid, + tags: [], + lastModified: bm.lastModified, + source: Ci.nsINavBookmarksService.SOURCE_DEFAULT, + isTagging: false, + }, + ]); +}); + +add_task(async function rename_bookmark_tag_notification() { + let bm = await PlacesUtils.bookmarks.insert({ + type: PlacesUtils.bookmarks.TYPE_BOOKMARK, + parentGuid: PlacesUtils.bookmarks.unfiledGuid, + url: new URL("http://renametag.example.com/"), + }); + let itemId = await PlacesUtils.promiseItemId(bm.guid); + + let tagFolder = await PlacesUtils.bookmarks.insert({ + type: PlacesUtils.bookmarks.TYPE_FOLDER, + parentGuid: PlacesUtils.bookmarks.tagsGuid, + title: "tag", + }); + let tag = await PlacesUtils.bookmarks.insert({ + type: PlacesUtils.bookmarks.TYPE_BOOKMARK, + parentGuid: tagFolder.guid, + url: new URL("http://renametag.example.com/"), + }); + let tagParentId = await PlacesUtils.promiseItemId(tag.parentGuid); + + const observer = expectPlacesObserverNotifications([ + "bookmark-title-changed", + "bookmark-tags-changed", + ]); + tagFolder = await PlacesUtils.bookmarks.update({ + guid: tagFolder.guid, + title: "renamed", + }); + + observer.check([ + { + type: "bookmark-title-changed", + id: tagParentId, + title: "renamed", + guid: tagFolder.guid, + url: "", + lastModified: tagFolder.lastModified, + parentGuid: tagFolder.parentGuid, + source: Ci.nsINavBookmarksService.SOURCE_DEFAULT, + itemType: PlacesUtils.bookmarks.TYPE_FOLDER, + isTagging: true, + }, + { + type: "bookmark-tags-changed", + id: itemId, + itemType: bm.type, + url: bm.url, + guid: bm.guid, + parentGuid: bm.parentGuid, + tags: ["renamed"], + lastModified: bm.lastModified, + source: Ci.nsINavBookmarksService.SOURCE_DEFAULT, + isTagging: false, + }, + ]); +}); + +add_task(async function remove_folder_notification() { + let folder1 = await PlacesUtils.bookmarks.insert({ + type: PlacesUtils.bookmarks.TYPE_FOLDER, + parentGuid: PlacesUtils.bookmarks.unfiledGuid, + }); + let folder1Id = await PlacesUtils.promiseItemId(folder1.guid); + let folder1ParentId = await PlacesUtils.promiseItemId(folder1.parentGuid); + + let bm = await PlacesUtils.bookmarks.insert({ + type: PlacesUtils.bookmarks.TYPE_BOOKMARK, + parentGuid: folder1.guid, + url: new URL("http://example.com/"), + }); + let bmItemId = await PlacesUtils.promiseItemId(bm.guid); + + let folder2 = await PlacesUtils.bookmarks.insert({ + type: PlacesUtils.bookmarks.TYPE_FOLDER, + parentGuid: folder1.guid, + }); + let folder2Id = await PlacesUtils.promiseItemId(folder2.guid); + + let bm2 = await PlacesUtils.bookmarks.insert({ + type: PlacesUtils.bookmarks.TYPE_BOOKMARK, + parentGuid: folder2.guid, + url: new URL("http://example.com/"), + }); + let bm2ItemId = await PlacesUtils.promiseItemId(bm2.guid); + + let observer = expectPlacesObserverNotifications(["bookmark-removed"]); + await PlacesUtils.bookmarks.remove(folder1.guid); + + observer.check([ + { + type: "bookmark-removed", + id: bm2ItemId, + parentId: folder2Id, + index: bm2.index, + url: bm2.url, + guid: bm2.guid, + parentGuid: bm2.parentGuid, + source: Ci.nsINavBookmarksService.SOURCE_DEFAULT, + itemType: PlacesUtils.bookmarks.TYPE_BOOKMARK, + isTagging: false, + }, + { + type: "bookmark-removed", + id: folder2Id, + parentId: folder1Id, + index: folder2.index, + url: null, + guid: folder2.guid, + parentGuid: folder2.parentGuid, + source: Ci.nsINavBookmarksService.SOURCE_DEFAULT, + itemType: PlacesUtils.bookmarks.TYPE_FOLDER, + isTagging: false, + }, + { + type: "bookmark-removed", + id: bmItemId, + parentId: folder1Id, + index: bm.index, + url: bm.url, + guid: bm.guid, + parentGuid: bm.parentGuid, + source: Ci.nsINavBookmarksService.SOURCE_DEFAULT, + itemType: PlacesUtils.bookmarks.TYPE_BOOKMARK, + isTagging: false, + }, + { + type: "bookmark-removed", + id: folder1Id, + parentId: folder1ParentId, + index: folder1.index, + url: null, + guid: folder1.guid, + parentGuid: folder1.parentGuid, + source: Ci.nsINavBookmarksService.SOURCE_DEFAULT, + itemType: PlacesUtils.bookmarks.TYPE_FOLDER, + isTagging: false, + }, + ]); +}); + +add_task(async function multiple_tags() { + const BOOKMARK_URL = "http://multipletags.example.com/"; + const TAG_NAMES = ["tag1", "tag2", "tag3", "tag4", "tag5", "tag6"]; + + const bm = await PlacesUtils.bookmarks.insert({ + type: PlacesUtils.bookmarks.TYPE_BOOKMARK, + parentGuid: PlacesUtils.bookmarks.unfiledGuid, + url: new URL(BOOKMARK_URL), + }); + const itemId = await PlacesUtils.promiseItemId(bm.guid); + + info("Register all tags"); + const tagFolders = await Promise.all( + TAG_NAMES.map(tagName => + PlacesUtils.bookmarks.insert({ + type: PlacesUtils.bookmarks.TYPE_FOLDER, + parentGuid: PlacesUtils.bookmarks.tagsGuid, + title: tagName, + }) + ) + ); + + info("Test adding tags to bookmark"); + for (let i = 0; i < tagFolders.length; i++) { + const tagFolder = tagFolders[i]; + const expectedTagNames = TAG_NAMES.slice(0, i + 1); + + const observer = expectPlacesObserverNotifications([ + "bookmark-tags-changed", + ]); + + await PlacesUtils.bookmarks.insert({ + type: PlacesUtils.bookmarks.TYPE_BOOKMARK, + parentGuid: tagFolder.guid, + url: new URL(BOOKMARK_URL), + }); + + observer.check([ + { + type: "bookmark-tags-changed", + id: itemId, + itemType: bm.type, + url: bm.url, + guid: bm.guid, + parentGuid: bm.parentGuid, + tags: expectedTagNames, + lastModified: bm.lastModified, + source: Ci.nsINavBookmarksService.SOURCE_DEFAULT, + isTagging: false, + }, + ]); + } + + info("Test removing tags from bookmark"); + for (const removedLength of [1, 2, 3]) { + const removedTags = tagFolders.splice(0, removedLength); + + const observer = expectPlacesObserverNotifications([ + "bookmark-tags-changed", + ]); + + // We can remove multiple tags at one time. + await PlacesUtils.bookmarks.remove(removedTags); + + const expectedResults = []; + + for (let i = 0; i < removedLength; i++) { + TAG_NAMES.splice(0, 1); + const expectedTagNames = [...TAG_NAMES]; + + expectedResults.push({ + type: "bookmark-tags-changed", + id: itemId, + itemType: bm.type, + url: bm.url, + guid: bm.guid, + parentGuid: bm.parentGuid, + tags: expectedTagNames, + lastModified: bm.lastModified, + source: Ci.nsINavBookmarksService.SOURCE_DEFAULT, + isTagging: false, + }); + } + + observer.check(expectedResults); + } +}); + +add_task(async function eraseEverything_notification() { + // Let's start from a clean situation. + await PlacesUtils.bookmarks.eraseEverything(); + + let folder1 = await PlacesUtils.bookmarks.insert({ + type: PlacesUtils.bookmarks.TYPE_FOLDER, + parentGuid: PlacesUtils.bookmarks.unfiledGuid, + }); + let folder1Id = await PlacesUtils.promiseItemId(folder1.guid); + let folder1ParentId = await PlacesUtils.promiseItemId(folder1.parentGuid); + + let bm = await PlacesUtils.bookmarks.insert({ + type: PlacesUtils.bookmarks.TYPE_BOOKMARK, + parentGuid: folder1.guid, + url: new URL("http://example.com/"), + }); + let itemId = await PlacesUtils.promiseItemId(bm.guid); + let parentId = await PlacesUtils.promiseItemId(bm.parentGuid); + + let folder2 = await PlacesUtils.bookmarks.insert({ + type: PlacesUtils.bookmarks.TYPE_FOLDER, + parentGuid: PlacesUtils.bookmarks.unfiledGuid, + }); + let folder2Id = await PlacesUtils.promiseItemId(folder2.guid); + let folder2ParentId = await PlacesUtils.promiseItemId(folder2.parentGuid); + + let toolbarBm = await PlacesUtils.bookmarks.insert({ + type: PlacesUtils.bookmarks.TYPE_BOOKMARK, + parentGuid: PlacesUtils.bookmarks.toolbarGuid, + url: new URL("http://example.com/"), + }); + let toolbarBmId = await PlacesUtils.promiseItemId(toolbarBm.guid); + let toolbarBmParentId = await PlacesUtils.promiseItemId(toolbarBm.parentGuid); + + let menuBm = await PlacesUtils.bookmarks.insert({ + type: PlacesUtils.bookmarks.TYPE_BOOKMARK, + parentGuid: PlacesUtils.bookmarks.menuGuid, + url: new URL("http://example.com/"), + }); + let menuBmId = await PlacesUtils.promiseItemId(menuBm.guid); + let menuBmParentId = await PlacesUtils.promiseItemId(menuBm.parentGuid); + + let observer = expectPlacesObserverNotifications(["bookmark-removed"]); + await PlacesUtils.bookmarks.eraseEverything(); + + // Bookmarks should always be notified before their parents. + observer.check([ + { + type: "bookmark-removed", + id: itemId, + parentId, + index: bm.index, + url: bm.url, + guid: bm.guid, + parentGuid: bm.parentGuid, + source: Ci.nsINavBookmarksService.SOURCE_DEFAULT, + itemType: PlacesUtils.bookmarks.TYPE_BOOKMARK, + isTagging: false, + }, + { + type: "bookmark-removed", + id: folder2Id, + parentId: folder2ParentId, + index: folder2.index, + url: null, + guid: folder2.guid, + parentGuid: folder2.parentGuid, + source: Ci.nsINavBookmarksService.SOURCE_DEFAULT, + itemType: PlacesUtils.bookmarks.TYPE_FOLDER, + isTagging: false, + }, + { + type: "bookmark-removed", + id: folder1Id, + parentId: folder1ParentId, + index: folder1.index, + url: null, + guid: folder1.guid, + parentGuid: folder1.parentGuid, + source: Ci.nsINavBookmarksService.SOURCE_DEFAULT, + itemType: PlacesUtils.bookmarks.TYPE_FOLDER, + isTagging: false, + }, + { + type: "bookmark-removed", + id: menuBmId, + parentId: menuBmParentId, + index: menuBm.index, + url: menuBm.url, + guid: menuBm.guid, + parentGuid: menuBm.parentGuid, + source: Ci.nsINavBookmarksService.SOURCE_DEFAULT, + itemType: PlacesUtils.bookmarks.TYPE_BOOKMARK, + isTagging: false, + }, + { + type: "bookmark-removed", + id: toolbarBmId, + parentId: toolbarBmParentId, + index: toolbarBm.index, + url: toolbarBm.url, + guid: toolbarBm.guid, + parentGuid: toolbarBm.parentGuid, + source: Ci.nsINavBookmarksService.SOURCE_DEFAULT, + itemType: PlacesUtils.bookmarks.TYPE_BOOKMARK, + isTagging: false, + }, + ]); +}); + +add_task(async function eraseEverything_reparented_notification() { + // Let's start from a clean situation. + await PlacesUtils.bookmarks.eraseEverything(); + + let folder1 = await PlacesUtils.bookmarks.insert({ + type: PlacesUtils.bookmarks.TYPE_FOLDER, + parentGuid: PlacesUtils.bookmarks.unfiledGuid, + }); + let folder1Id = await PlacesUtils.promiseItemId(folder1.guid); + let folder1ParentId = await PlacesUtils.promiseItemId(folder1.parentGuid); + + let bm = await PlacesUtils.bookmarks.insert({ + type: PlacesUtils.bookmarks.TYPE_BOOKMARK, + parentGuid: folder1.guid, + url: new URL("http://example.com/"), + }); + let itemId = await PlacesUtils.promiseItemId(bm.guid); + + let folder2 = await PlacesUtils.bookmarks.insert({ + type: PlacesUtils.bookmarks.TYPE_FOLDER, + parentGuid: PlacesUtils.bookmarks.unfiledGuid, + }); + let folder2Id = await PlacesUtils.promiseItemId(folder2.guid); + let folder2ParentId = await PlacesUtils.promiseItemId(folder2.parentGuid); + + bm.parentGuid = folder2.guid; + bm = await PlacesUtils.bookmarks.update(bm); + let parentId = await PlacesUtils.promiseItemId(bm.parentGuid); + + let observer = expectPlacesObserverNotifications(["bookmark-removed"]); + await PlacesUtils.bookmarks.eraseEverything(); + + // Bookmarks should always be notified before their parents. + observer.check([ + { + type: "bookmark-removed", + id: itemId, + parentId, + index: bm.index, + url: bm.url, + guid: bm.guid, + parentGuid: bm.parentGuid, + source: Ci.nsINavBookmarksService.SOURCE_DEFAULT, + itemType: PlacesUtils.bookmarks.TYPE_BOOKMARK, + isTagging: false, + }, + { + type: "bookmark-removed", + id: folder2Id, + parentId: folder2ParentId, + index: folder2.index, + url: null, + guid: folder2.guid, + parentGuid: folder2.parentGuid, + source: Ci.nsINavBookmarksService.SOURCE_DEFAULT, + itemType: PlacesUtils.bookmarks.TYPE_FOLDER, + isTagging: false, + }, + { + type: "bookmark-removed", + id: folder1Id, + parentId: folder1ParentId, + index: folder1.index, + url: null, + guid: folder1.guid, + parentGuid: folder1.parentGuid, + source: Ci.nsINavBookmarksService.SOURCE_DEFAULT, + itemType: PlacesUtils.bookmarks.TYPE_FOLDER, + isTagging: false, + }, + ]); +}); + +add_task(async function reorder_notification() { + let bookmarks = [ + { + type: PlacesUtils.bookmarks.TYPE_BOOKMARK, + url: "http://example1.com/", + parentGuid: PlacesUtils.bookmarks.unfiledGuid, + }, + { + type: PlacesUtils.bookmarks.TYPE_FOLDER, + parentGuid: PlacesUtils.bookmarks.unfiledGuid, + }, + { + type: PlacesUtils.bookmarks.TYPE_SEPARATOR, + parentGuid: PlacesUtils.bookmarks.unfiledGuid, + }, + { + type: PlacesUtils.bookmarks.TYPE_BOOKMARK, + url: "http://example2.com/", + parentGuid: PlacesUtils.bookmarks.unfiledGuid, + }, + { + type: PlacesUtils.bookmarks.TYPE_BOOKMARK, + url: "http://example3.com/", + parentGuid: PlacesUtils.bookmarks.unfiledGuid, + }, + ]; + let sorted = []; + for (let bm of bookmarks) { + sorted.push(await PlacesUtils.bookmarks.insert(bm)); + } + + // Randomly reorder the array. + sorted.sort(() => 0.5 - Math.random()); + + const observer = expectPlacesObserverNotifications(["bookmark-moved"]); + await PlacesUtils.bookmarks.reorder( + PlacesUtils.bookmarks.unfiledGuid, + sorted.map(bm => bm.guid) + ); + + let expectedNotifications = []; + for (let i = 0; i < sorted.length; ++i) { + let child = sorted[i]; + let childId = await PlacesUtils.promiseItemId(child.guid); + expectedNotifications.push({ + type: "bookmark-moved", + id: childId, + itemType: child.type, + url: child.url || "", + guid: child.guid, + parentGuid: child.parentGuid, + source: Ci.nsINavBookmarksService.SOURCE_DEFAULT, + index: i, + oldParentGuid: child.parentGuid, + oldIndex: child.index, + isTagging: false, + }); + } + + observer.check(expectedNotifications); +}); + +add_task(async function update_notitle_notification() { + let toolbarBmURI = Services.io.newURI("https://example.com"); + let toolbarItemId = await PlacesUtils.promiseItemId( + PlacesUtils.bookmarks.toolbarGuid + ); + let toolbarBmId = PlacesUtils.bookmarks.insertBookmark( + toolbarItemId, + toolbarBmURI, + 0, + "Bookmark" + ); + let toolbarBmGuid = await PlacesUtils.promiseItemGuid(toolbarBmId); + + let menuFolder = await PlacesUtils.bookmarks.insert({ + parentGuid: PlacesUtils.bookmarks.menuGuid, + type: PlacesUtils.bookmarks.TYPE_FOLDER, + index: 0, + title: "Folder", + }); + let menuFolderId = await PlacesUtils.promiseItemId(menuFolder.guid); + + const observer = expectPlacesObserverNotifications([ + "bookmark-title-changed", + ]); + + PlacesUtils.bookmarks.setItemTitle(toolbarBmId, null); + strictEqual( + PlacesUtils.bookmarks.getItemTitle(toolbarBmId), + "", + "Legacy API should return empty string for untitled bookmark" + ); + + let updatedMenuBm = await PlacesUtils.bookmarks.update({ + guid: menuFolder.guid, + title: null, + }); + strictEqual( + updatedMenuBm.title, + "", + "Async API should return empty string for untitled bookmark" + ); + + let toolbarBmModified = await PlacesUtils.bookmarks.fetch(toolbarBmGuid); + observer.check([ + { + type: "bookmark-title-changed", + id: toolbarBmId, + itemType: PlacesUtils.bookmarks.TYPE_BOOKMARK, + url: toolbarBmURI.spec, + title: "", + guid: toolbarBmGuid, + parentGuid: PlacesUtils.bookmarks.toolbarGuid, + lastModified: toolbarBmModified.lastModified, + source: Ci.nsINavBookmarksService.SOURCE_DEFAULT, + isTagging: false, + }, + { + type: "bookmark-title-changed", + id: menuFolderId, + itemType: PlacesUtils.bookmarks.TYPE_FOLDER, + url: "", + title: "", + guid: menuFolder.guid, + parentGuid: PlacesUtils.bookmarks.menuGuid, + lastModified: updatedMenuBm.lastModified, + source: Ci.nsINavBookmarksService.SOURCE_DEFAULT, + isTagging: false, + }, + ]); +}); |