map: tickets 06+07 resolved; 05 partial (live spawn pending gitea token)
This commit is contained in:
@@ -6,82 +6,104 @@ import SettingsGate from "./SettingsGate";
|
||||
import { jsonResponse } from "./test/setup";
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
localStorage.clear();
|
||||
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" }));
|
||||
},
|
||||
};
|
||||
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("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("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("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("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("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("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");
|
||||
});
|
||||
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");
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user