mirror of
https://github.com/Sea-Haven-Industries/shoc-frontend-new.git
synced 2026-09-30 12:43:13 +00:00
80 lines
2.7 KiB
TypeScript
80 lines
2.7 KiB
TypeScript
import ky from "ky";
|
|
import { describe, expect, it, vi } from "vitest";
|
|
import { normalizeApiRequestError, REQUEST_UPLIFTS_ROLE_DENIAL_MESSAGE } from "@/api/api-error";
|
|
|
|
const RESOURCE_URL = "https://example.test/api/resource";
|
|
|
|
function createClient(fetchImpl: typeof fetch) {
|
|
return ky.create({
|
|
fetch: fetchImpl,
|
|
retry: 0,
|
|
timeout: 50,
|
|
hooks: { beforeError: [({ error }) => normalizeApiRequestError(error)] },
|
|
});
|
|
}
|
|
|
|
describe("normalizeApiRequestError", () => {
|
|
it("surfaces Ky's pre-parsed JSON body for HTTP errors via the hook", async () => {
|
|
const fetchImpl = vi.fn(() =>
|
|
Promise.resolve(
|
|
new Response(JSON.stringify({ message: "Validation failed" }), {
|
|
status: 422,
|
|
headers: { "Content-Type": "application/json" },
|
|
}),
|
|
),
|
|
) as unknown as typeof fetch;
|
|
|
|
await expect(createClient(fetchImpl).get(RESOURCE_URL).json()).rejects.toThrow(
|
|
"Validation failed",
|
|
);
|
|
});
|
|
|
|
it("preserves only the allowlisted public denial for 403 responses", async () => {
|
|
const allowedFetch = vi.fn(() =>
|
|
Promise.resolve(
|
|
new Response(JSON.stringify({ message: REQUEST_UPLIFTS_ROLE_DENIAL_MESSAGE }), {
|
|
status: 403,
|
|
headers: { "Content-Type": "application/json" },
|
|
}),
|
|
),
|
|
) as unknown as typeof fetch;
|
|
const unrelatedFetch = vi.fn(() =>
|
|
Promise.resolve(
|
|
new Response(JSON.stringify({ message: "accountId 42 is forbidden" }), {
|
|
status: 403,
|
|
headers: { "Content-Type": "application/json" },
|
|
}),
|
|
),
|
|
) as unknown as typeof fetch;
|
|
|
|
await expect(createClient(allowedFetch).get(RESOURCE_URL).json()).rejects.toThrow(
|
|
REQUEST_UPLIFTS_ROLE_DENIAL_MESSAGE,
|
|
);
|
|
await expect(createClient(unrelatedFetch).get(RESOURCE_URL).json()).rejects.toThrow(
|
|
"You do not have permission to perform this action.",
|
|
);
|
|
});
|
|
|
|
it("reports a connection failure for network errors", async () => {
|
|
const fetchImpl = vi.fn(() =>
|
|
Promise.reject(new TypeError("fetch failed")),
|
|
) as unknown as typeof fetch;
|
|
|
|
await expect(createClient(fetchImpl).get(RESOURCE_URL).json()).rejects.toThrow(
|
|
"No response from server. Please check your connection.",
|
|
);
|
|
});
|
|
|
|
it("returns a friendly timeout message", async () => {
|
|
const fetchImpl = vi.fn((_input: RequestInfo | URL, init?: RequestInit) => {
|
|
const signal = init?.signal;
|
|
return new Promise<Response>((_resolve, reject) => {
|
|
signal?.addEventListener("abort", () => reject(signal?.reason));
|
|
});
|
|
}) as unknown as typeof fetch;
|
|
|
|
await expect(createClient(fetchImpl).get(RESOURCE_URL).json()).rejects.toThrow(
|
|
"The request timed out. Please try again.",
|
|
);
|
|
});
|
|
});
|