Files
Termix/src/ui/tests/api/guacamole-api.test.ts
T

120 lines
3.8 KiB
TypeScript
Raw Normal View History

+3
2026-08-06 14:41:39 -05:00
import { describe, expect, it, vi, beforeEach } from "vitest";
const authApiMock = vi.hoisted(() => ({
get: vi.fn(async () => ({ data: { guacd: { status: "disconnected" } } })),
post: vi.fn(async () => ({ data: { token: "local-token" } })),
}));
const remoteApiMock = vi.hoisted(() => ({
get: vi.fn(async () => ({ data: { guacd: { status: "connected" } } })),
post: vi.fn(async () => ({ data: { token: "remote-token" } })),
}));
const isElectronMock = vi.hoisted(() => vi.fn(() => false));
2026-08-22 19:47:40 -05:00
const resolveRemoteHostIdMock = vi.hoisted(() => vi.fn());
+3
2026-08-06 14:41:39 -05:00
vi.mock("@/main-axios", () => ({
authApi: authApiMock,
getRemoteGuacamoleApi: () => remoteApiMock,
isElectron: isElectronMock,
handleApiError: (error: unknown) => error,
}));
2026-08-22 19:47:40 -05:00
vi.mock("@/lib/remote-server-api", () => ({
resolveRemoteHostId: resolveRemoteHostIdMock,
}));
+3
2026-08-06 14:41:39 -05:00
import {
getGuacdStatus,
getGuacamoleTokenFromHost,
} from "../../api/guacamole-api";
beforeEach(() => {
authApiMock.get.mockClear();
authApiMock.post.mockClear();
remoteApiMock.get.mockClear();
remoteApiMock.post.mockClear();
2026-08-22 19:47:40 -05:00
resolveRemoteHostIdMock.mockReset();
+3
2026-08-06 14:41:39 -05:00
});
describe("guacamole API origin", () => {
it("uses the shared instance in the browser", async () => {
isElectronMock.mockReturnValue(false);
await getGuacdStatus();
await getGuacamoleTokenFromHost(9, "vnc");
expect(authApiMock.get).toHaveBeenCalledWith("/guacamole/status");
expect(authApiMock.post).toHaveBeenCalledOnce();
expect(remoteApiMock.get).not.toHaveBeenCalled();
expect(remoteApiMock.post).not.toHaveBeenCalled();
});
it("uses the connected remote server in the desktop app", async () => {
isElectronMock.mockReturnValue(true);
// The embedded backend has no guacd, so asking it reports "disconnected"
// even when the connected server can serve the session.
const status = await getGuacdStatus();
const token = await getGuacamoleTokenFromHost(9, "vnc");
expect(status.guacd.status).toBe("connected");
expect(token.token).toBe("remote-token");
expect(remoteApiMock.get).toHaveBeenCalledWith("/guacamole/status");
expect(remoteApiMock.post).toHaveBeenCalledOnce();
expect(authApiMock.get).not.toHaveBeenCalled();
expect(authApiMock.post).not.toHaveBeenCalled();
});
it("sends the connect-host payload unchanged to the remote server", async () => {
isElectronMock.mockReturnValue(true);
2026-08-22 19:47:40 -05:00
resolveRemoteHostIdMock.mockResolvedValue(41);
+3
2026-08-06 14:41:39 -05:00
2026-08-22 19:47:40 -05:00
await getGuacamoleTokenFromHost(
9,
"rdp",
{
username: "admin",
password: "secret",
domain: "EXAMPLE",
},
"host-sync-id",
);
+3
2026-08-06 14:41:39 -05:00
expect(remoteApiMock.post).toHaveBeenCalledWith(
2026-08-22 19:47:40 -05:00
"/guacamole/connect-host/41",
+3
2026-08-06 14:41:39 -05:00
{
protocol: "rdp",
promptedUsername: "admin",
promptedPassword: "secret",
+5
2026-08-19 14:12:06 -05:00
promptedDomain: "EXAMPLE",
+3
2026-08-06 14:41:39 -05:00
},
);
2026-08-22 19:47:40 -05:00
expect(resolveRemoteHostIdMock).toHaveBeenCalledWith("host-sync-id");
+3
2026-08-06 14:41:39 -05:00
});
+5
2026-08-19 14:12:06 -05:00
it("sends an empty prompted domain for local RDP accounts", async () => {
isElectronMock.mockReturnValue(false);
await getGuacamoleTokenFromHost(9, "rdp", {
username: "local-admin",
password: "secret",
domain: "",
});
expect(authApiMock.post).toHaveBeenCalledWith("/guacamole/connect-host/9", {
protocol: "rdp",
promptedUsername: "local-admin",
promptedPassword: "secret",
promptedDomain: "",
});
});
2026-08-22 19:47:40 -05:00
it("does not fall back to a colliding local id when sync resolution fails", async () => {
isElectronMock.mockReturnValue(true);
resolveRemoteHostIdMock.mockResolvedValue(null);
await expect(
getGuacamoleTokenFromHost(9, "rdp", undefined, "missing-sync-id"),
).rejects.toThrow("The synced host does not exist on the remote server");
expect(remoteApiMock.post).not.toHaveBeenCalled();
});
+3
2026-08-06 14:41:39 -05:00
});