/* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ */ "use strict"; const TEST_URL = "about:buildconfig"; add_setup(async function () { // The following initialization code is necessary to avoid a frequent // intermittent failure in verify-fission where, due to timings, we may or // may not import default bookmarks. info("Ensure Places init is complete"); let placesInitCompleteObserved = TestUtils.topicObserved( "places-browser-init-complete" ); Cc["@mozilla.org/browser/browserglue;1"] .getService(Ci.nsIObserver) .observe(null, "browser-glue-test", "places-browser-init-complete"); await placesInitCompleteObserved; // Clean before and after so we don't have anything in the folders. await PlacesUtils.bookmarks.eraseEverything(); registerCleanupFunction(async function () { await PlacesUtils.bookmarks.eraseEverything(); }); }); // Simulating actual drag and drop is hard for a xul tree as we can't get the // required source elements, so we have to do a lot more work by hand. async function simulateDrop( selectTargets, sourceBm, dropEffect, targetGuid, isVirtualRoot = false ) { await withSidebarTree("bookmarks", async function (tree) { for (let target of selectTargets) { tree.selectItems([target]); if (tree.selectedNode instanceof Ci.nsINavHistoryContainerResultNode) { tree.selectedNode.containerOpen = true; } } let dataTransfer = { _data: [], dropEffect, mozCursor: "auto", mozItemCount: 1, types: [PlacesUtils.TYPE_X_MOZ_PLACE], mozTypesAt(i) { return [this._data[0].type]; }, mozGetDataAt(i) { return this._data[0].data; }, mozSetDataAt(type, data, index) { this._data.push({ type, data, index, }); }, }; let event = { dataTransfer, preventDefault() {}, stopPropagation() {}, }; tree._controller.setDataTransfer(event); Assert.equal( dataTransfer.mozTypesAt(0), PlacesUtils.TYPE_X_MOZ_PLACE, "Should have x-moz-place as the first data type." ); let dataObject = JSON.parse(dataTransfer.mozGetDataAt(0)); let guid = isVirtualRoot ? dataObject.concreteGuid : dataObject.itemGuid; Assert.equal(guid, sourceBm.guid, "Should have the correct guid."); Assert.equal( dataObject.title, PlacesUtils.bookmarks.getLocalizedTitle(sourceBm), "Should have the correct title." ); Assert.equal(dataTransfer.dropEffect, dropEffect); let ip = new PlacesInsertionPoint({ parentId: await PlacesUtils.promiseItemId(targetGuid), parentGuid: targetGuid, index: 0, orientation: Ci.nsITreeView.DROP_ON, }); await PlacesControllerDragHelper.onDrop(ip, dataTransfer); }); } add_task(async function test_move_normal_bm_in_sidebar() { let bm = await PlacesUtils.bookmarks.insert({ parentGuid: PlacesUtils.bookmarks.toolbarGuid, title: "Fake", url: TEST_URL, }); await simulateDrop([bm.guid], bm, "move", PlacesUtils.bookmarks.unfiledGuid); let newBm = await PlacesUtils.bookmarks.fetch(bm.guid); Assert.equal( newBm.parentGuid, PlacesUtils.bookmarks.unfiledGuid, "Should have moved to the new parent." ); let oldLocationBm = await PlacesUtils.bookmarks.fetch({ parentGuid: PlacesUtils.bookmarks.toolbarGuid, index: 0, }); Assert.ok(!oldLocationBm, "Should not have a bookmark at the old location."); }); add_task(async function test_try_move_root_in_sidebar() { let menuFolder = await PlacesUtils.bookmarks.fetch( PlacesUtils.bookmarks.menuGuid ); await simulateDrop( [menuFolder.guid], menuFolder, "move", PlacesUtils.bookmarks.toolbarGuid, true ); menuFolder = await PlacesUtils.bookmarks.fetch( PlacesUtils.bookmarks.menuGuid ); Assert.equal( menuFolder.parentGuid, PlacesUtils.bookmarks.rootGuid, "Should have remained in the root" ); let newFolder = await PlacesUtils.bookmarks.fetch({ parentGuid: PlacesUtils.bookmarks.toolbarGuid, index: 0, }); Assert.notEqual( newFolder.guid, menuFolder.guid, "Should have created a different folder" ); Assert.equal( newFolder.title, PlacesUtils.bookmarks.getLocalizedTitle(menuFolder), "Should have copied the folder title." ); Assert.equal( newFolder.type, PlacesUtils.bookmarks.TYPE_BOOKMARK, "Should have a bookmark type (for a folder shortcut)." ); Assert.equal( newFolder.url, `place:parent=${PlacesUtils.bookmarks.menuGuid}`, "Should have the correct url for the folder shortcut." ); }); add_task(async function test_try_move_bm_within_two_root_folder_queries() { await PlacesUtils.bookmarks.eraseEverything(); let bookmark = await PlacesUtils.bookmarks.insert({ parentGuid: PlacesUtils.bookmarks.unfiledGuid, title: "Fake", url: TEST_URL, }); let queryType = Ci.nsINavHistoryQueryOptions.QUERY_TYPE_BOOKMARKS; let queries = await PlacesUtils.bookmarks.insertTree({ guid: PlacesUtils.bookmarks.toolbarGuid, children: [ { title: "Query", url: `place:queryType=${queryType}&terms=Fake`, }, ], }); await simulateDrop( [queries[0].guid, bookmark.guid], bookmark, "move", PlacesUtils.bookmarks.toolbarGuid ); let newBm = await PlacesUtils.bookmarks.fetch(bookmark.guid); Assert.equal( newBm.parentGuid, PlacesUtils.bookmarks.toolbarGuid, "should have moved the bookmark to a new folder." ); }); add_task(async function test_move_within_itself() { await PlacesUtils.bookmarks.eraseEverything(); let bookmarks = await PlacesUtils.bookmarks.insertTree({ guid: PlacesUtils.bookmarks.unfiledGuid, children: [ { title: "bm1", url: "http://www.example.com/bookmark1.html", }, { title: "bm2", url: "http://www.example.com/bookmark2.html", }, { title: "bm3", url: "http://www.example.com/bookmark3.html", }, ], }); await withSidebarTree("bookmarks", async function (tree) { // Select the folder containing the bookmarks // and save its index position tree.selectItems([PlacesUtils.bookmarks.unfiledGuid]); let unfiledFolderIndex = tree.view.treeIndexForNode(tree.selectedNode); let guids = bookmarks.map(bookmark => bookmark.guid); tree.selectItems(guids); let dataTransfer = { _data: [], dropEffect: "move", mozCursor: "auto", mozItemCount: bookmarks.length, types: [PlacesUtils.TYPE_X_MOZ_PLACE], mozTypesAt(i) { return [this._data[0].type]; }, mozGetDataAt(i) { return this._data[0].data; }, mozSetDataAt(type, data, index) { this._data.push({ type, data, index, }); }, }; bookmarks.forEach((bookmark, index) => { // Index positions of the newly created bookmarks bookmark.rowIndex = unfiledFolderIndex + index + 1; bookmark.node = tree.view.nodeForTreeIndex(bookmark.rowIndex); bookmark.cachedBookmarkIndex = bookmark.node.bookmarkIndex; }); let assertBookmarksHaveNotChangedPosition = () => { bookmarks.forEach(bookmark => { Assert.equal( bookmark.node.bookmarkIndex, bookmark.cachedBookmarkIndex, "should not have moved the bookmark." ); }); }; // Mimic "drag" events let dragStartEvent = new CustomEvent("dragstart", { bubbles: true, }); dragStartEvent.dataTransfer = dataTransfer; let dragEndEvent = new CustomEvent("dragend", { bubbles: true, }); let treeChildren = tree.view._element.children[1]; treeChildren.dispatchEvent(dragStartEvent); await tree.view.drop( bookmarks[1].rowIndex, Ci.nsITreeView.DROP_ON, dataTransfer ); treeChildren.dispatchEvent(dragEndEvent); assertBookmarksHaveNotChangedPosition(); treeChildren.dispatchEvent(dragStartEvent); await tree.view.drop( bookmarks[2].rowIndex, Ci.nsITreeView.DROP_ON, dataTransfer ); treeChildren.dispatchEvent(dragEndEvent); assertBookmarksHaveNotChangedPosition(); }); });