68 lines
2.0 KiB
TypeScript
68 lines
2.0 KiB
TypeScript
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
|
|
import { api, ApiError } from "./client";
|
|
|
|
afterEach(() => {
|
|
vi.unstubAllGlobals();
|
|
});
|
|
|
|
describe("api client", () => {
|
|
it("uses the single API prefix", async () => {
|
|
const fetchMock = vi.fn().mockResolvedValue(
|
|
new Response(JSON.stringify({ status: "ok" }), {
|
|
status: 200,
|
|
headers: { "Content-Type": "application/json" },
|
|
}),
|
|
);
|
|
vi.stubGlobal("fetch", fetchMock);
|
|
|
|
await expect(api.get<{ status: string }>("/health")).resolves.toEqual({ status: "ok" });
|
|
expect(fetchMock).toHaveBeenCalledWith(
|
|
"/api/health",
|
|
expect.objectContaining({ credentials: "same-origin" }),
|
|
);
|
|
});
|
|
|
|
it("normalizes safe server errors", async () => {
|
|
vi.stubGlobal(
|
|
"fetch",
|
|
vi.fn().mockResolvedValue(
|
|
new Response(
|
|
JSON.stringify({
|
|
error: { code: "unavailable", message: "暂不可用", request_id: "abc" },
|
|
}),
|
|
{ status: 503, headers: { "Content-Type": "application/json" } },
|
|
),
|
|
),
|
|
);
|
|
|
|
const promise = api.get("/health");
|
|
await expect(promise).rejects.toBeInstanceOf(ApiError);
|
|
await expect(promise).rejects.toMatchObject({
|
|
message: "暂不可用",
|
|
status: 503,
|
|
code: "unavailable",
|
|
requestId: "abc",
|
|
});
|
|
});
|
|
|
|
it("adds the readable CSRF cookie to write requests", async () => {
|
|
vi.stubGlobal("document", { cookie: "xiaobai_csrf=csrf-token-123" });
|
|
const fetchMock = vi.fn().mockResolvedValue(
|
|
new Response(JSON.stringify({ message: "ok" }), {
|
|
status: 200,
|
|
headers: { "Content-Type": "application/json" },
|
|
}),
|
|
);
|
|
vi.stubGlobal("fetch", fetchMock);
|
|
|
|
await api.patch("/account/password", { value: "changed" });
|
|
|
|
const request = fetchMock.mock.calls[0]?.[1] as RequestInit;
|
|
const headers = request.headers as Headers;
|
|
expect(request.method).toBe("PATCH");
|
|
expect(headers.get("X-CSRF-Token")).toBe("csrf-token-123");
|
|
expect(headers.get("Content-Type")).toBe("application/json");
|
|
});
|
|
});
|