110 lines
3.8 KiB
TypeScript
110 lines
3.8 KiB
TypeScript
import { render, screen } from "@testing-library/react";
|
|
import userEvent from "@testing-library/user-event";
|
|
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
import { getSettings } from "./settings";
|
|
import SettingsGate from "./SettingsGate";
|
|
import { jsonResponse } from "./test/setup";
|
|
|
|
afterEach(() => {
|
|
vi.restoreAllMocks();
|
|
localStorage.clear();
|
|
});
|
|
|
|
function setup(): { connect: () => Promise<void> } {
|
|
render(<SettingsGate onSaved={() => undefined} />);
|
|
return {
|
|
connect: async (): Promise<void> => {
|
|
await userEvent.click(screen.getByRole("button", { name: "Connect" }));
|
|
},
|
|
};
|
|
}
|
|
|
|
describe("SettingsGate", () => {
|
|
it("defaults the server url to the current origin", () => {
|
|
setup();
|
|
const input = screen.getByLabelText("Server URL") as HTMLInputElement;
|
|
expect(input.value).toBe("http://localhost:3000");
|
|
});
|
|
|
|
it("requires a token", async () => {
|
|
setup();
|
|
await userEvent.click(screen.getByRole("button", { name: "Connect" }));
|
|
expect(screen.getByRole("alert")).toHaveTextContent("token required");
|
|
expect(getSettings()).toBeNull();
|
|
});
|
|
|
|
it("validation failure shows the server error and does not save", async () => {
|
|
const fetchMock = vi
|
|
.spyOn(globalThis, "fetch")
|
|
.mockResolvedValue(jsonResponse({ error: "unauthorized" }, 401));
|
|
setup();
|
|
await userEvent.type(screen.getByLabelText("Bearer token"), "bad");
|
|
await userEvent.click(screen.getByRole("button", { name: "Connect" }));
|
|
expect(screen.getByRole("alert")).toHaveTextContent(
|
|
"connection failed (401)",
|
|
);
|
|
expect(getSettings()).toBeNull();
|
|
expect(fetchMock).toHaveBeenCalledWith(
|
|
"http://localhost:3000/api/sessions",
|
|
expect.objectContaining({ headers: { Authorization: "Bearer bad" } }),
|
|
);
|
|
});
|
|
|
|
it("network rejection surfaces the thrown message", async () => {
|
|
vi.spyOn(globalThis, "fetch").mockRejectedValue(
|
|
new TypeError("fetch failed"),
|
|
);
|
|
setup();
|
|
await userEvent.type(screen.getByLabelText("Bearer token"), "tok");
|
|
await userEvent.click(screen.getByRole("button", { name: "Connect" }));
|
|
expect(screen.getByRole("alert")).toHaveTextContent("fetch failed");
|
|
});
|
|
|
|
it("saves normalized url + trimmed token and calls onSaved", async () => {
|
|
const fetchMock = vi
|
|
.spyOn(globalThis, "fetch")
|
|
.mockResolvedValue(jsonResponse([]));
|
|
const onSaved = vi.fn();
|
|
render(<SettingsGate onSaved={onSaved} />);
|
|
await userEvent.clear(screen.getByLabelText("Server URL"));
|
|
await userEvent.type(
|
|
screen.getByLabelText("Server URL"),
|
|
"http://daemon:8686///",
|
|
);
|
|
await userEvent.type(screen.getByLabelText("Bearer token"), " tok ");
|
|
await userEvent.click(screen.getByRole("button", { name: "Connect" }));
|
|
expect(fetchMock).toHaveBeenCalledWith(
|
|
"http://daemon:8686/api/sessions",
|
|
expect.anything(),
|
|
);
|
|
expect(getSettings()).toEqual({
|
|
serverUrl: "http://daemon:8686",
|
|
token: "tok",
|
|
});
|
|
expect(onSaved).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it("non-Error rejections stringify via String(err)", async () => {
|
|
vi.spyOn(globalThis, "fetch").mockRejectedValue("plain-string" as never);
|
|
setup();
|
|
await userEvent.type(screen.getByLabelText("Bearer token"), "tok");
|
|
await userEvent.click(screen.getByRole("button", { name: "Connect" }));
|
|
expect(screen.getByRole("alert")).toHaveTextContent("plain-string");
|
|
});
|
|
|
|
it("empty server url falls back to the current origin", async () => {
|
|
const fetchMock = vi
|
|
.spyOn(globalThis, "fetch")
|
|
.mockResolvedValue(jsonResponse([]));
|
|
setup();
|
|
await userEvent.clear(screen.getByLabelText("Server URL"));
|
|
await userEvent.type(screen.getByLabelText("Bearer token"), "tok");
|
|
await userEvent.click(screen.getByRole("button", { name: "Connect" }));
|
|
expect(fetchMock).toHaveBeenCalledWith(
|
|
"http://localhost:3000/api/sessions",
|
|
expect.anything(),
|
|
);
|
|
expect(getSettings()?.serverUrl).toBe("http://localhost:3000");
|
|
});
|
|
});
|