mirror of
https://github.com/l0ng-ai/openidea.git
synced 2026-11-08 08:52:12 +00:00
Sync with Deployed opens in its own window, one per project window. It lists local files next to the server's copies, with filters, content and binary comparison, and an embedded side-by-side diff whose local side can be edited. The selected file can be synchronized (Enter) without closing the window. The window is the `deployment` kind of the auxiliary windows that Settings and comparisons use. A cancelled close in it stops its project window from closing. The preview uses the vcs diff viewer through its `diff` editor kind. Also covers #811 (compare with the deployed versions). Co-authored-by: marianomd <[email protected]>
108 lines
4.3 KiB
TypeScript
108 lines
4.3 KiB
TypeScript
import { afterEach, beforeEach, expect, it, vi } from "vitest";
|
|
import { useProject } from "@/platform/project";
|
|
import { useDeployment } from "./store";
|
|
import { DEFAULT_DEPLOYMENT_SERVER } from "@/platform/remoteSettings";
|
|
|
|
const mocks = vi.hoisted(() => ({
|
|
launch: vi.fn(),
|
|
project: vi.fn(),
|
|
open: vi.fn(),
|
|
cancel: vi.fn(),
|
|
ask: vi.fn(),
|
|
error: vi.fn(),
|
|
dirty: vi.fn(),
|
|
save: vi.fn(),
|
|
dispose: vi.fn(),
|
|
destroy: vi.fn(),
|
|
close: vi.fn(),
|
|
title: vi.fn(),
|
|
emit: vi.fn(async () => {}),
|
|
closeRequested: null as null | ((event: { preventDefault(): void }) => Promise<void>),
|
|
}));
|
|
vi.mock("@tauri-apps/api/webviewWindow", () => ({
|
|
getCurrentWebviewWindow: () => ({
|
|
label: "deployment-project-2",
|
|
listen: async () => () => {},
|
|
onCloseRequested: async (callback: typeof mocks.closeRequested) => {
|
|
mocks.closeRequested = callback;
|
|
return () => {};
|
|
},
|
|
setTitle: mocks.title,
|
|
close: mocks.close,
|
|
destroy: mocks.destroy,
|
|
}),
|
|
}));
|
|
vi.mock("@/platform/ipc", () => ({
|
|
isTauri: () => true,
|
|
commands: { windowTakeLaunch: mocks.launch, projectCurrent: mocks.project },
|
|
}));
|
|
vi.mock("@tauri-apps/api/event", () => ({ emitTo: mocks.emit }));
|
|
vi.mock("@/editor/core/embeddedDocuments", () => ({
|
|
activateEmbeddedDocuments: () => ({ dirty: mocks.dirty, save: mocks.save, dispose: mocks.dispose }),
|
|
}));
|
|
vi.mock("@/workbench/messages", () => ({ ask: mocks.ask, showError: mocks.error }));
|
|
vi.mock("./actions", () => ({ openSync: mocks.open, closeSync: mocks.cancel }));
|
|
vi.mock("./windowBridge", () => ({ openDeploymentSource: vi.fn() }));
|
|
vi.mock("./Dialogs", () => ({ SecretDialog: () => null }));
|
|
vi.mock("./SyncDialog", () => ({ SyncDialog: () => null }));
|
|
vi.mock("@/workbench/OverlayHost", () => ({ OverlayHost: () => null }));
|
|
vi.mock("@/workbench/TitleBar", () => ({ TitleBar: () => null }));
|
|
|
|
import { activateDeploymentWindow } from "./window";
|
|
|
|
let stop: (() => void) | undefined;
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
mocks.launch.mockResolvedValue(null);
|
|
mocks.dirty.mockReturnValue(false);
|
|
mocks.save.mockResolvedValue(undefined);
|
|
mocks.dispose.mockResolvedValue(undefined);
|
|
mocks.ask.mockResolvedValue({ button: "cancel" });
|
|
useProject.setState({ project: null, settings: { files: { autoSave: false } } as never });
|
|
useDeployment.setState({ sync: null });
|
|
});
|
|
afterEach(() => {
|
|
stop?.();
|
|
stop = undefined;
|
|
});
|
|
|
|
it("loads the parent project before comparing the launched server and local selection", async () => {
|
|
const server = { ...DEFAULT_DEPLOYMENT_SERVER, id: "s2", name: "Second project" };
|
|
const project = { root: "/second", settings: { deployment: { servers: [server] } } };
|
|
mocks.project.mockResolvedValue(project);
|
|
mocks.launch.mockResolvedValueOnce({ deployment: { server: "s2", paths: ["/second/a.php"] } });
|
|
mocks.open.mockImplementation(async () => useDeployment.setState({ sync: { server: "s2" } as never }));
|
|
stop = activateDeploymentWindow("project-2");
|
|
await vi.waitFor(() =>
|
|
expect(mocks.open).toHaveBeenCalledWith(expect.objectContaining({ id: "s2" }), ["/second/a.php"]),
|
|
);
|
|
expect(useProject.getState().project).toBe(project);
|
|
});
|
|
|
|
it("keeps the window and unsaved local edits when closing is cancelled or saving fails", async () => {
|
|
mocks.dirty.mockReturnValue(true);
|
|
stop = activateDeploymentWindow("project-2");
|
|
const event = { preventDefault: vi.fn() };
|
|
await mocks.closeRequested!(event);
|
|
expect(event.preventDefault).toHaveBeenCalled();
|
|
expect(mocks.save).not.toHaveBeenCalled();
|
|
expect(mocks.destroy).not.toHaveBeenCalled();
|
|
// The project window waiting to close stops.
|
|
expect(mocks.emit).toHaveBeenCalledWith(
|
|
"project-2",
|
|
"openidea://auxiliary/closed",
|
|
expect.objectContaining({ label: "deployment-project-2", closed: false }),
|
|
);
|
|
mocks.ask.mockResolvedValue({ button: "save" });
|
|
mocks.save.mockRejectedValueOnce(new Error("Disk full"));
|
|
await mocks.closeRequested!(event);
|
|
expect(mocks.error).toHaveBeenCalledWith("Cannot close deployment comparison", "Disk full");
|
|
expect(mocks.dispose).not.toHaveBeenCalled();
|
|
expect(mocks.destroy).not.toHaveBeenCalled();
|
|
await mocks.closeRequested!(event);
|
|
expect(mocks.cancel).toHaveBeenCalledOnce();
|
|
expect(mocks.dispose).toHaveBeenCalledOnce();
|
|
expect(mocks.destroy).toHaveBeenCalledOnce();
|
|
expect(mocks.save.mock.invocationCallOrder.at(-1)).toBeLessThan(mocks.destroy.mock.invocationCallOrder[0]!);
|
|
});
|