135 lines
3.7 KiB
TypeScript
135 lines
3.7 KiB
TypeScript
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
import { settingsApi } from "./settings";
|
|
|
|
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("settingsApi", () => {
|
|
describe("getEditorCommand", () => {
|
|
it("sends GET to /settings/editor and returns editor settings", async () => {
|
|
const expected = { editor_command: "zed" };
|
|
mockFetch.mockResolvedValueOnce(okResponse(expected));
|
|
|
|
const result = await settingsApi.getEditorCommand();
|
|
|
|
expect(mockFetch).toHaveBeenCalledWith(
|
|
"/api/settings/editor",
|
|
expect.objectContaining({
|
|
headers: expect.objectContaining({
|
|
"Content-Type": "application/json",
|
|
}),
|
|
}),
|
|
);
|
|
expect(result).toEqual(expected);
|
|
});
|
|
|
|
it("returns null editor_command when not configured", async () => {
|
|
const expected = { editor_command: null };
|
|
mockFetch.mockResolvedValueOnce(okResponse(expected));
|
|
|
|
const result = await settingsApi.getEditorCommand();
|
|
expect(result.editor_command).toBeNull();
|
|
});
|
|
|
|
it("uses custom baseUrl when provided", async () => {
|
|
mockFetch.mockResolvedValueOnce(okResponse({ editor_command: "code" }));
|
|
|
|
await settingsApi.getEditorCommand("http://localhost:4000/api");
|
|
|
|
expect(mockFetch).toHaveBeenCalledWith(
|
|
"http://localhost:4000/api/settings/editor",
|
|
expect.anything(),
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("setEditorCommand", () => {
|
|
it("sends PUT to /settings/editor with command body", async () => {
|
|
const expected = { editor_command: "zed" };
|
|
mockFetch.mockResolvedValueOnce(okResponse(expected));
|
|
|
|
const result = await settingsApi.setEditorCommand("zed");
|
|
|
|
expect(mockFetch).toHaveBeenCalledWith(
|
|
"/api/settings/editor",
|
|
expect.objectContaining({
|
|
method: "PUT",
|
|
body: JSON.stringify({ editor_command: "zed" }),
|
|
}),
|
|
);
|
|
expect(result).toEqual(expected);
|
|
});
|
|
|
|
it("sends PUT with null to clear the editor command", async () => {
|
|
const expected = { editor_command: null };
|
|
mockFetch.mockResolvedValueOnce(okResponse(expected));
|
|
|
|
const result = await settingsApi.setEditorCommand(null);
|
|
|
|
expect(mockFetch).toHaveBeenCalledWith(
|
|
"/api/settings/editor",
|
|
expect.objectContaining({
|
|
method: "PUT",
|
|
body: JSON.stringify({ editor_command: null }),
|
|
}),
|
|
);
|
|
expect(result.editor_command).toBeNull();
|
|
});
|
|
|
|
it("uses custom baseUrl when provided", async () => {
|
|
mockFetch.mockResolvedValueOnce(okResponse({ editor_command: "vim" }));
|
|
|
|
await settingsApi.setEditorCommand("vim", "http://localhost:4000/api");
|
|
|
|
expect(mockFetch).toHaveBeenCalledWith(
|
|
"http://localhost:4000/api/settings/editor",
|
|
expect.objectContaining({ method: "PUT" }),
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("error handling", () => {
|
|
it("throws with response body text on non-ok response", async () => {
|
|
mockFetch.mockResolvedValueOnce(errorResponse(400, "Bad Request"));
|
|
|
|
await expect(settingsApi.getEditorCommand()).rejects.toThrow(
|
|
"Bad Request",
|
|
);
|
|
});
|
|
|
|
it("throws with status code message when response body is empty", async () => {
|
|
mockFetch.mockResolvedValueOnce(errorResponse(500, ""));
|
|
|
|
await expect(settingsApi.getEditorCommand()).rejects.toThrow(
|
|
"Request failed (500)",
|
|
);
|
|
});
|
|
|
|
it("throws on setEditorCommand error", async () => {
|
|
mockFetch.mockResolvedValueOnce(errorResponse(403, "Forbidden"));
|
|
|
|
await expect(settingsApi.setEditorCommand("code")).rejects.toThrow(
|
|
"Forbidden",
|
|
);
|
|
});
|
|
});
|
|
});
|