139 lines
3.4 KiB
TypeScript
139 lines
3.4 KiB
TypeScript
|
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||
|
|
import { api } from "./client";
|
||
|
|
|
||
|
|
const mockFetch = vi.fn();
|
||
|
|
|
||
|
|
beforeEach(() => {
|
||
|
|
vi.stubGlobal("fetch", mockFetch);
|
||
|
|
});
|
||
|
|
|
||
|
|
afterEach(() => {
|
||
|
|
vi.restoreAllMocks();
|
||
|
|
});
|
||
|
|
|
||
|
|
function okResponse(body: unknown) {
|
||
|
|
return new Response(JSON.stringify(body), {
|
||
|
|
status: 200,
|
||
|
|
headers: { "Content-Type": "application/json" },
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
function errorResponse(status: number, text: string) {
|
||
|
|
return new Response(text, { status });
|
||
|
|
}
|
||
|
|
|
||
|
|
describe("api client", () => {
|
||
|
|
describe("getCurrentProject", () => {
|
||
|
|
it("sends GET to /project", async () => {
|
||
|
|
mockFetch.mockResolvedValueOnce(okResponse("/home/user/project"));
|
||
|
|
|
||
|
|
const result = await api.getCurrentProject();
|
||
|
|
|
||
|
|
expect(mockFetch).toHaveBeenCalledWith(
|
||
|
|
"/api/project",
|
||
|
|
expect.objectContaining({}),
|
||
|
|
);
|
||
|
|
expect(result).toBe("/home/user/project");
|
||
|
|
});
|
||
|
|
|
||
|
|
it("returns null when no project open", async () => {
|
||
|
|
mockFetch.mockResolvedValueOnce(okResponse(null));
|
||
|
|
|
||
|
|
const result = await api.getCurrentProject();
|
||
|
|
expect(result).toBeNull();
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
describe("openProject", () => {
|
||
|
|
it("sends POST with path", async () => {
|
||
|
|
mockFetch.mockResolvedValueOnce(okResponse("/home/user/project"));
|
||
|
|
|
||
|
|
await api.openProject("/home/user/project");
|
||
|
|
|
||
|
|
expect(mockFetch).toHaveBeenCalledWith(
|
||
|
|
"/api/project",
|
||
|
|
expect.objectContaining({
|
||
|
|
method: "POST",
|
||
|
|
body: JSON.stringify({ path: "/home/user/project" }),
|
||
|
|
}),
|
||
|
|
);
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
describe("closeProject", () => {
|
||
|
|
it("sends DELETE to /project", async () => {
|
||
|
|
mockFetch.mockResolvedValueOnce(okResponse(true));
|
||
|
|
|
||
|
|
await api.closeProject();
|
||
|
|
|
||
|
|
expect(mockFetch).toHaveBeenCalledWith(
|
||
|
|
"/api/project",
|
||
|
|
expect.objectContaining({ method: "DELETE" }),
|
||
|
|
);
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
describe("getKnownProjects", () => {
|
||
|
|
it("returns array of project paths", async () => {
|
||
|
|
mockFetch.mockResolvedValueOnce(okResponse(["/a", "/b"]));
|
||
|
|
|
||
|
|
const result = await api.getKnownProjects();
|
||
|
|
expect(result).toEqual(["/a", "/b"]);
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
describe("error handling", () => {
|
||
|
|
it("throws on non-ok response with body text", async () => {
|
||
|
|
mockFetch.mockResolvedValueOnce(errorResponse(404, "Not found"));
|
||
|
|
|
||
|
|
await expect(api.getCurrentProject()).rejects.toThrow("Not found");
|
||
|
|
});
|
||
|
|
|
||
|
|
it("throws with status code when no body", async () => {
|
||
|
|
mockFetch.mockResolvedValueOnce(errorResponse(500, ""));
|
||
|
|
|
||
|
|
await expect(api.getCurrentProject()).rejects.toThrow(
|
||
|
|
"Request failed (500)",
|
||
|
|
);
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
describe("searchFiles", () => {
|
||
|
|
it("sends POST with query", async () => {
|
||
|
|
mockFetch.mockResolvedValueOnce(
|
||
|
|
okResponse([{ path: "src/main.rs", matches: 1 }]),
|
||
|
|
);
|
||
|
|
|
||
|
|
const result = await api.searchFiles("hello");
|
||
|
|
|
||
|
|
expect(mockFetch).toHaveBeenCalledWith(
|
||
|
|
"/api/fs/search",
|
||
|
|
expect.objectContaining({
|
||
|
|
method: "POST",
|
||
|
|
body: JSON.stringify({ query: "hello" }),
|
||
|
|
}),
|
||
|
|
);
|
||
|
|
expect(result).toHaveLength(1);
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
describe("execShell", () => {
|
||
|
|
it("sends POST with command and args", async () => {
|
||
|
|
mockFetch.mockResolvedValueOnce(
|
||
|
|
okResponse({ stdout: "output", stderr: "", exit_code: 0 }),
|
||
|
|
);
|
||
|
|
|
||
|
|
const result = await api.execShell("ls", ["-la"]);
|
||
|
|
|
||
|
|
expect(mockFetch).toHaveBeenCalledWith(
|
||
|
|
"/api/shell/exec",
|
||
|
|
expect.objectContaining({
|
||
|
|
method: "POST",
|
||
|
|
body: JSON.stringify({ command: "ls", args: ["-la"] }),
|
||
|
|
}),
|
||
|
|
);
|
||
|
|
expect(result.exit_code).toBe(0);
|
||
|
|
});
|
||
|
|
});
|
||
|
|
});
|