import { render, screen, waitFor } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { http, HttpResponse } from "msw"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { server } from "../test/msw"; import { SettingsDialog } from "./SettingsDialog"; function renderDialog() { const client = new QueryClient({ defaultOptions: { queries: { retry: false } } }); render( , ); } beforeEach(() => { server.use( http.get("http://localhost:8787/workspaces", () => HttpResponse.json([ { name: "psd", file: "psd.yaml" }, { name: "tht-test", file: "tht-test.yaml" }, ]), ), http.get("http://localhost:8787/models", () => HttpResponse.json({ models: [ { provider: "zai", id: "glm-5.2", name: "GLM 5.2", reasoning: true }, { provider: "anthropic", id: "claude-opus-4-8", name: "Claude Opus 4.8", reasoning: true }, ], }), ), http.get("http://localhost:8787/settings", () => HttpResponse.json({ workspace: "psd", provider: "zai", model: "glm-5.2", thinking: "medium" }), ), ); }); test("opens and pre-selects current settings", async () => { renderDialog(); await userEvent.click(screen.getByRole("button", { name: /settings/i })); const workspace = (await screen.findByLabelText(/workspace/i)) as HTMLSelectElement; expect(workspace.value).toBe("psd"); const thinking = screen.getByLabelText(/thinking/i) as HTMLSelectElement; expect(thinking.value).toBe("medium"); // thinking options are exactly low/medium/high expect(Array.from(thinking.options).map((o) => o.value)).toEqual(["low", "medium", "high"]); }); test("provider change filters the model list", async () => { renderDialog(); await userEvent.click(screen.getByRole("button", { name: /settings/i })); const provider = (await screen.findByLabelText(/provider/i)) as HTMLSelectElement; await userEvent.selectOptions(provider, "anthropic"); const model = screen.getByLabelText(/model/i) as HTMLSelectElement; const optionValues = Array.from(model.options).map((o) => o.value); expect(optionValues).toContain("claude-opus-4-8"); expect(optionValues).not.toContain("glm-5.2"); }); test("Salva PUTs the selected settings", async () => { let body: unknown = null; server.use( http.put("http://localhost:8787/settings", async ({ request }) => { body = await request.json(); return HttpResponse.json({ workspace: "psd", provider: "zai", model: "glm-5.2", thinking: "high" }); }), ); renderDialog(); await userEvent.click(screen.getByRole("button", { name: /settings/i })); await screen.findByLabelText(/workspace/i); await userEvent.selectOptions(screen.getByLabelText(/thinking/i), "high"); await userEvent.click(screen.getByRole("button", { name: /save/i })); await waitFor(() => expect(body).toEqual({ workspace: "psd", provider: "zai", model: "glm-5.2", thinking: "high" }), ); }); test("degrades to free-text provider/model when models list is empty", async () => { server.use( http.get("http://localhost:8787/models", () => HttpResponse.json({ models: [] })), http.get("http://localhost:8787/settings", () => HttpResponse.json({ workspace: "psd", provider: "", model: "", thinking: "low" }), ), ); renderDialog(); await userEvent.click(screen.getByRole("button", { name: /settings/i })); expect(await screen.findByTestId("provider-freetext")).toHaveProperty("tagName", "INPUT"); expect(screen.getByTestId("model-freetext")).toHaveProperty("tagName", "INPUT"); });