project_panel: Add tests for cross worktree drag-and-drop (#42704)

Add missing tests for cross worktree drag-and-drop:

- file -> directory
- file -> file (drops into parent directory)
- whole directory move
- multi selection move

Release Notes:

- N/A
This commit is contained in:
Smit Barmase
2025-11-14 13:31:44 +05:30
committed by GitHub
parent ead4f26b52
commit 020f518231
@@ -4173,6 +4173,106 @@ async fn test_dragged_selection_resolve_entry(cx: &mut gpui::TestAppContext) {
);
}
#[gpui::test]
async fn test_drag_entries_between_different_worktrees(cx: &mut gpui::TestAppContext) {
init_test(cx);
let fs = FakeFs::new(cx.executor());
fs.insert_tree(
"/root_a",
json!({
"src": {
"lib.rs": "",
"main.rs": ""
},
"docs": {
"guide.md": ""
},
"multi": {
"alpha.txt": "",
"beta.txt": ""
}
}),
)
.await;
fs.insert_tree(
"/root_b",
json!({
"dst": {
"existing.md": ""
},
"target.txt": ""
}),
)
.await;
let project = Project::test(fs.clone(), ["/root_a".as_ref(), "/root_b".as_ref()], cx).await;
let workspace = cx.add_window(|window, cx| Workspace::test_new(project.clone(), window, cx));
let cx = &mut VisualTestContext::from_window(*workspace, cx);
let panel = workspace.update(cx, ProjectPanel::new).unwrap();
cx.run_until_parked();
// Case 1: move a file onto a directory in another worktree.
select_path(&panel, "root_a/src/main.rs", cx);
drag_selection_to(&panel, "root_b/dst", false, cx);
assert!(
find_project_entry(&panel, "root_b/dst/main.rs", cx).is_some(),
"Dragged file should appear under destination worktree"
);
assert_eq!(
find_project_entry(&panel, "root_a/src/main.rs", cx),
None,
"Dragged file should be removed from the source worktree"
);
// Case 2: drop a file onto another worktree file so it lands in the parent directory.
select_path(&panel, "root_a/docs/guide.md", cx);
drag_selection_to(&panel, "root_b/dst/existing.md", true, cx);
assert!(
find_project_entry(&panel, "root_b/dst/guide.md", cx).is_some(),
"Dropping onto a file should place the entry beside the target file"
);
assert_eq!(
find_project_entry(&panel, "root_a/docs/guide.md", cx),
None,
"Source file should be removed after the move"
);
// Case 3: move an entire directory.
select_path(&panel, "root_a/src", cx);
drag_selection_to(&panel, "root_b/dst", false, cx);
assert!(
find_project_entry(&panel, "root_b/dst/src/lib.rs", cx).is_some(),
"Dragging a directory should move its nested contents"
);
assert_eq!(
find_project_entry(&panel, "root_a/src", cx),
None,
"Directory should no longer exist in the source worktree"
);
// Case 4: multi-selection drag between worktrees.
panel.update(cx, |panel, _| panel.marked_entries.clear());
select_path_with_mark(&panel, "root_a/multi/alpha.txt", cx);
select_path_with_mark(&panel, "root_a/multi/beta.txt", cx);
drag_selection_to(&panel, "root_b/dst", false, cx);
assert!(
find_project_entry(&panel, "root_b/dst/alpha.txt", cx).is_some()
&& find_project_entry(&panel, "root_b/dst/beta.txt", cx).is_some(),
"All marked entries should move to the destination worktree"
);
assert_eq!(
find_project_entry(&panel, "root_a/multi/alpha.txt", cx),
None,
"Marked entries should be removed from the origin worktree"
);
assert_eq!(
find_project_entry(&panel, "root_a/multi/beta.txt", cx),
None,
"Marked entries should be removed from the origin worktree"
);
}
#[gpui::test]
async fn test_autoreveal_and_gitignored_files(cx: &mut gpui::TestAppContext) {
init_test_with_editor(cx);
@@ -7496,6 +7596,32 @@ fn select_path_with_mark(panel: &Entity<ProjectPanel>, path: &str, cx: &mut Visu
});
}
fn drag_selection_to(
panel: &Entity<ProjectPanel>,
target_path: &str,
is_file: bool,
cx: &mut VisualTestContext,
) {
let target_entry = find_project_entry(panel, target_path, cx)
.unwrap_or_else(|| panic!("no entry for target path {target_path:?}"));
panel.update_in(cx, |panel, window, cx| {
let selection = panel
.state
.selection
.expect("a selection is required before dragging");
let drag = DraggedSelection {
active_selection: SelectedEntry {
worktree_id: selection.worktree_id,
entry_id: panel.resolve_entry(selection.entry_id),
},
marked_selections: Arc::from(panel.marked_entries.clone()),
};
panel.drag_onto(&drag, target_entry, is_file, window, cx);
});
cx.executor().run_until_parked();
}
fn find_project_entry(
panel: &Entity<ProjectPanel>,
path: &str,