Files
Termix/src/ui/tests/lib/remote-server-api.test.ts
T

114 lines
3.3 KiB
TypeScript
Raw Normal View History

+5
2026-08-19 14:12:06 -05:00
import { beforeEach, describe, expect, it, vi } from "vitest";
import type { SSHHost } from "@/types/index";
const isElectron = vi.hoisted(() => vi.fn());
const remoteApi = vi.hoisted(() => ({ get: vi.fn() }));
vi.mock("@/lib/electron", () => ({ isElectron }));
vi.mock("@/main-axios", () => ({ getRemoteStatsApi: () => remoteApi }));
import {
getConnectedRemoteApi,
+17
2026-09-20 14:56:39 -05:00
hydrateLocalSharedHostAuth,
+5
2026-08-19 14:12:06 -05:00
markRemoteSharedHosts,
resolveRemoteHostId,
} from "@/lib/remote-server-api";
describe("remote server API", () => {
const invoke = vi.fn();
beforeEach(() => {
isElectron.mockReset();
remoteApi.get.mockReset();
invoke.mockReset();
Object.defineProperty(window, "electronAPI", {
configurable: true,
value: { invoke },
});
});
it("is available only for a configured Electron sync server", async () => {
isElectron.mockReturnValue(false);
await expect(getConnectedRemoteApi()).resolves.toBeNull();
isElectron.mockReturnValue(true);
invoke.mockResolvedValueOnce({ serverUrl: "https://termix.example" });
await expect(getConnectedRemoteApi()).resolves.toBe(remoteApi);
});
it("maps a local host to the remote numeric id by syncId", async () => {
isElectron.mockReturnValue(true);
invoke.mockResolvedValue({ serverUrl: "https://termix.example" });
remoteApi.get.mockResolvedValue({
data: { rows: [{ id: 41, syncId: "host-a" }] },
});
await expect(resolveRemoteHostId("host-a")).resolves.toBe(41);
await expect(resolveRemoteHostId("missing")).resolves.toBeNull();
expect(remoteApi.get).toHaveBeenCalledWith("/sync/hosts");
});
it("keeps only shared remote hosts and gives them collision-free ids", () => {
const rows = markRemoteSharedHosts([
{ id: 4, isShared: false },
+17
2026-09-20 14:56:39 -05:00
{
id: 9,
isShared: true,
syncId: "shared-host",
connectionOrigin: "local",
},
+5
2026-08-19 14:12:06 -05:00
] as SSHHost[]);
expect(rows).toEqual([
expect.objectContaining({
id: -9,
syncId: "shared-host",
+17
2026-09-20 14:56:39 -05:00
connectionOrigin: "local",
+5
2026-08-19 14:12:06 -05:00
}),
]);
});
+17
2026-09-20 14:56:39 -05:00
it("hydrates a remote shared host for a local connection without persisting remote ids", async () => {
isElectron.mockReturnValue(true);
invoke.mockResolvedValue({ serverUrl: "https://termix.example" });
remoteApi.get.mockResolvedValue({
data: {
username: "recipient",
authType: "key",
key: "PRIVATE KEY",
keyPassword: "passphrase",
keyType: "ed25519",
},
});
const result = await hydrateLocalSharedHostAuth({
id: -9,
isShared: true,
syncId: "shared-host",
credentialId: 77,
username: "owner",
authType: "key",
});
expect(remoteApi.get).toHaveBeenCalledWith(
"/host/db/host/9/local-connection-auth",
);
expect(result).toEqual(
expect.objectContaining({
id: -9,
syncId: null,
credentialId: undefined,
username: "recipient",
key: "PRIVATE KEY",
keyPassword: "passphrase",
}),
);
});
it("leaves local and owned hosts untouched", async () => {
const host = { id: 9, isShared: false, username: "root" };
await expect(hydrateLocalSharedHostAuth(host)).resolves.toBe(host);
expect(remoteApi.get).not.toHaveBeenCalled();
});
+5
2026-08-19 14:12:06 -05:00
});