Files
storkit/frontend/src/api/settings.test.ts

135 lines
3.7 KiB
TypeScript
Raw Normal View History

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",
);
});
});
});