Файли
openidea/src/features/deployment/remoteHost.test.ts
T
Florent Vтаflorentvdry 2d4d6ee6bf fix(deployment): accept absolute local paths in mappings and name menu entries after the server (#885)
A mapping's local path may now be an absolute path inside the project (the form IntelliJ writes), and a deployment path of . means the server root; absolute paths outside the project are kept as they are. The project-tree Deployment submenu names the default server (Upload to <server>, Download from <server>, Sync with Deployed to <server>…) and gains Sync with Deployed to Default Server. Remote Host downloads use the backend-resolved mapping, which fixes downloads under symlinked or case-different paths.

Fixes #877

Co-authored-by: florentvdry <[email protected]>
2026-11-03 23:35:43 +08:00

77 рядки
3.6 KiB
TypeScript

import { beforeEach, expect, it, vi } from "vitest";
import { DEFAULT_DEPLOYMENT_SERVER } from "@/platform/remoteSettings";
import { downloadToProject, ensureRoot } from "./remoteHost";
import { useDeployment } from "./store";
const ipc = vi.hoisted(() => ({ root: vi.fn(), list: vi.fn(), download: vi.fn(), notify: vi.fn() }));
vi.mock("./actions", () => ({ downloadPaths: ipc.download }));
vi.mock("./ssh", () => ({ withSsh: (_: string, run: () => unknown) => run() }));
vi.mock("@/ui", () => ({ copyText: vi.fn() }));
vi.mock("@/workbench/inputDialogs", () => ({ promptInput: vi.fn() }));
vi.mock("@/workbench/messages", () => ({ confirm: vi.fn() }));
vi.mock("@/platform/project", () => ({ useProject: { getState: () => ({ project: { root: "/project" } }) } }));
vi.mock("@/workbench/contributions", () => ({ notifications: () => ({ notify: ipc.notify }) }));
vi.mock("@/platform/ipc", async (original) => ({
...(await original<typeof import("@/platform/ipc")>()),
commands: { deployServerRoot: ipc.root, remoteList: ipc.list },
}));
beforeEach(() => {
useDeployment.setState({ trees: {} });
vi.clearAllMocks();
ipc.root.mockResolvedValue({ status: "ok", data: { root: "/srv", mappings: [] } });
ipc.list.mockResolvedValue({ status: "ok", data: [] });
});
it("reloads a server's tree when changing its filesystem type or root", async () => {
const server = { ...DEFAULT_DEPLOYMENT_SERVER, id: "existing", sshConfig: "ssh", rootPath: "/srv" };
await ensureRoot(server);
expect(ipc.list).toHaveBeenLastCalledWith({ kind: "sftp", ssh: "ssh" }, "/srv");
await ensureRoot(server);
expect(ipc.root).toHaveBeenCalledTimes(1);
const local = { ...server, kind: "local" as const };
await ensureRoot(local);
expect(ipc.list).toHaveBeenLastCalledWith({ kind: "local" }, "/srv");
ipc.root.mockResolvedValue({ status: "ok", data: { root: "/mounted", mappings: [] } });
await ensureRoot({ ...local, rootPath: "/mounted" });
expect(ipc.list).toHaveBeenLastCalledWith({ kind: "local" }, "/mounted");
expect(useDeployment.getState().trees.existing?.root).toBe("/mounted");
});
it("refreshes resolved mappings when the local mapping changes", async () => {
const server = { ...DEFAULT_DEPLOYMENT_SERVER, id: "local", kind: "local" as const };
await ensureRoot(server);
const mappings = [{ local: "/project/src", deployment: "/srv" }];
ipc.root.mockResolvedValue({ status: "ok", data: { root: "/srv", mappings } });
await ensureRoot({ ...server, mappings: [{ local: "/alias", deployment: "/", web: "" }] });
expect(ipc.root).toHaveBeenCalledTimes(2);
expect(useDeployment.getState().trees.local?.mappings).toEqual(mappings);
});
it("downloads using backend-resolved folders instead of the configured alias", async () => {
const server = {
...DEFAULT_DEPLOYMENT_SERVER,
id: "local",
kind: "local" as const,
mappings: [{ local: "/alias", deployment: ".", web: "" }],
};
const mappings = [{ local: "/project/src", deployment: "/srv" }];
ipc.root.mockResolvedValue({ status: "ok", data: { root: "/srv", mappings } });
const entry = {
path: "/srv/a.txt",
name: "a.txt",
isDir: false,
isSymlink: false,
size: 5,
mtime: null,
permissions: "rw-r--r--",
};
await downloadToProject(server, [entry]);
expect(ipc.download).toHaveBeenCalledWith(server, ["/project/src/a.txt"]);
ipc.download.mockClear();
ipc.root.mockResolvedValue({ status: "ok", data: { root: "/srv", mappings: [] } });
await downloadToProject(server, [entry]);
expect(ipc.download).not.toHaveBeenCalled();
expect(ipc.notify).toHaveBeenCalledWith(expect.objectContaining({ title: "Not mapped to a project path" }));
});