дзеркало
https://github.com/l0ng-ai/openidea.git
синхронізовано 2026-11-08 19:02:17 +02:00
Compare with Branch or Revision only handled one file, so reviewing a folder meant opening each file. Folders, the project root and multiple selections now open a changes tree against the chosen revision, with per-file diffs on demand. A single file keeps its direct diff. Each path resolves against its own repository through the root registry. In a multi-repo workspace the picker offers shared revisions such as "main in 3 repositories" as well as per-repository ones, results are grouped by repository, and content outside any repository or a repository missing the revision is stated in the result. Listing is cancellable and off the UI thread, includes worktree and untracked changes, and a rename leaving the selection shows as a delete. Show Diff on folders reuses the same tree. Verified on macOS, and against a remote host over the server protocol. A remote window, Windows and Linux were not run. Fixes #567
75 рядки
3.4 KiB
TypeScript
75 рядки
3.4 KiB
TypeScript
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
|
|
const mocks = vi.hoisted(() => ({ scope: vi.fn(), choose: vi.fn(), open: vi.fn(), show: vi.fn(), notify: vi.fn() }));
|
|
vi.mock("@/platform/ipc", async (original) => {
|
|
const real = await original<typeof import("@/platform/ipc")>();
|
|
return { ...real, commands: { ...real.commands, vcsCompareScope: mocks.scope } };
|
|
});
|
|
vi.mock("../RevisionChooser", () => ({ chooseRepositoryRevision: mocks.choose }));
|
|
vi.mock("../diffInput", () => ({ openDiff: mocks.open }));
|
|
vi.mock("../operations", () => ({ showPathComparison: mocks.show }));
|
|
vi.mock("@/workbench/contributions", () => ({ notifications: () => ({ notify: mocks.notify }) }));
|
|
import { useProject } from "@/platform/project";
|
|
import { comparePathsWithRevision, showDirectoryWorkingDiff } from "../comparePaths";
|
|
|
|
afterEach(() => {
|
|
vi.clearAllMocks();
|
|
useProject.setState({ project: null });
|
|
});
|
|
|
|
describe("comparison flow", () => {
|
|
it("keeps a single file's direct revision → worktree diff and uses its own repository's picker", async () => {
|
|
mocks.scope.mockResolvedValue({
|
|
status: "ok",
|
|
data: { repositories: ["/server"], singleFile: true, skippedPaths: [] },
|
|
});
|
|
mocks.choose.mockResolvedValue({ rev: "main", repositories: ["/server"] });
|
|
await comparePathsWithRevision(["/server/a.ts"]);
|
|
expect(mocks.choose).toHaveBeenCalledWith("Compare with Branch or Revision", {
|
|
repositories: ["/server"],
|
|
tags: true,
|
|
});
|
|
expect(mocks.open).toHaveBeenCalledWith({
|
|
path: "/server/a.ts",
|
|
left: { type: "rev", rev: "main", label: "main" },
|
|
right: { type: "worktree" },
|
|
});
|
|
expect(mocks.show).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("applies shared revisions across the selection so missing revisions are reported, and preserves repo-specific choices", async () => {
|
|
mocks.scope.mockResolvedValue({
|
|
status: "ok",
|
|
data: { repositories: ["/client", "/server", "/admin"], singleFile: false, skippedPaths: [] },
|
|
});
|
|
mocks.choose.mockResolvedValue({ rev: "main", repositories: ["/client", "/server"] });
|
|
await comparePathsWithRevision(["/workspace"]);
|
|
expect(mocks.show).toHaveBeenLastCalledWith(["/workspace"], "main", null);
|
|
mocks.choose.mockResolvedValue({ rev: "feature", repositories: ["/server"] });
|
|
await comparePathsWithRevision(["/workspace"]);
|
|
expect(mocks.show).toHaveBeenLastCalledWith(["/workspace"], "feature", ["/server"]);
|
|
});
|
|
|
|
it("reports non-repository selections before opening a picker", async () => {
|
|
mocks.scope.mockResolvedValue({
|
|
status: "ok",
|
|
data: { repositories: [], singleFile: false, skippedPaths: ["/workspace/loose/"] },
|
|
});
|
|
useProject.setState({ project: { root: "/workspace", name: "workspace" } as never });
|
|
await comparePathsWithRevision(["/workspace/loose"]);
|
|
expect(mocks.notify).toHaveBeenCalledWith(
|
|
expect.objectContaining({ title: "Selection is outside Git repositories", body: "loose/" }),
|
|
);
|
|
expect(mocks.choose).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("reuses the tree against HEAD for Show Diff on folders", async () => {
|
|
mocks.scope.mockResolvedValue({
|
|
status: "ok",
|
|
data: { repositories: ["/server"], singleFile: false, skippedPaths: [] },
|
|
});
|
|
expect(await showDirectoryWorkingDiff(["/server/src"])).toBe(true);
|
|
expect(mocks.show).toHaveBeenCalledWith(["/server/src"], "HEAD", null);
|
|
});
|
|
});
|