124 lines
3.1 KiB
TypeScript
124 lines
3.1 KiB
TypeScript
// Mock de fetch() pour les tests — supporte méthodes HTTP et status codes
|
|
|
|
type HttpMethod = "GET" | "POST" | "PUT" | "DELETE";
|
|
|
|
export interface MockRoute {
|
|
method?: HttpMethod;
|
|
status?: number;
|
|
body?: unknown;
|
|
headers?: Record<string, string>;
|
|
}
|
|
|
|
// deno-lint-ignore no-explicit-any
|
|
let _originalFetch: ((input: any, init?: any) => Promise<Response>) | null =
|
|
null;
|
|
let _calls: { url: string; method: string; body?: unknown }[] = [];
|
|
|
|
/**
|
|
* Remplace globalThis.fetch par un mock configurable.
|
|
*
|
|
* Usage simple (GET 200 par défaut) :
|
|
* mockFetch({ "/students": studentsData })
|
|
*
|
|
* Usage avancé (méthode + status) :
|
|
* mockFetch({ "/students": { method: "POST", status: 201, body: newStudent } })
|
|
*/
|
|
export function mockFetch(
|
|
routes: Record<string, unknown | MockRoute>,
|
|
): void {
|
|
_originalFetch = globalThis.fetch;
|
|
_calls = [];
|
|
|
|
globalThis.fetch = async (
|
|
input: string | URL | Request,
|
|
init?: RequestInit,
|
|
): Promise<Response> => {
|
|
const url = typeof input === "string"
|
|
? input
|
|
: input instanceof URL
|
|
? input.toString()
|
|
: input.url;
|
|
const method = (init?.method ?? "GET").toUpperCase();
|
|
|
|
// Parse le body si présent
|
|
let reqBody: unknown = undefined;
|
|
if (init?.body) {
|
|
try {
|
|
reqBody = JSON.parse(init.body as string);
|
|
} catch {
|
|
reqBody = init.body;
|
|
}
|
|
}
|
|
|
|
_calls.push({ url, method, body: reqBody });
|
|
|
|
for (const [pattern, config] of Object.entries(routes)) {
|
|
if (!url.includes(pattern)) continue;
|
|
|
|
// Config simple : la valeur est directement le body de réponse (GET 200)
|
|
if (!isRouteConfig(config)) {
|
|
return new Response(JSON.stringify(config), {
|
|
status: 200,
|
|
headers: { "Content-Type": "application/json" },
|
|
});
|
|
}
|
|
|
|
// Config avancée : vérifier la méthode si spécifiée
|
|
if (config.method && config.method !== method) continue;
|
|
|
|
const status = config.status ?? 200;
|
|
|
|
// 204 : pas de body
|
|
if (status === 204) {
|
|
return new Response(null, { status: 204 });
|
|
}
|
|
|
|
return new Response(
|
|
config.body !== undefined ? JSON.stringify(config.body) : null,
|
|
{
|
|
status,
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
...config.headers,
|
|
},
|
|
},
|
|
);
|
|
}
|
|
|
|
return new Response(JSON.stringify({ error: "Not Found" }), {
|
|
status: 404,
|
|
headers: { "Content-Type": "application/json" },
|
|
});
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Restaure le fetch original.
|
|
*/
|
|
export function restoreFetch(): void {
|
|
if (_originalFetch) {
|
|
globalThis.fetch = _originalFetch;
|
|
_originalFetch = null;
|
|
}
|
|
_calls = [];
|
|
}
|
|
|
|
/**
|
|
* Retourne la liste des appels fetch interceptés.
|
|
*/
|
|
export function getFetchCalls(): {
|
|
url: string;
|
|
method: string;
|
|
body?: unknown;
|
|
}[] {
|
|
return [..._calls];
|
|
}
|
|
|
|
function isRouteConfig(value: unknown): value is MockRoute {
|
|
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
return false;
|
|
}
|
|
const v = value as Record<string, unknown>;
|
|
return "status" in v || "method" in v || "body" in v;
|
|
}
|