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:
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user