import { afterEach, describe, expect, it, vi } from 'vitest'; import { ApiProblemError, requestJSON } from '../../src/apiClient'; afterEach(() => vi.unstubAllGlobals()); describe('requestJSON', () => { it('preserves safe problem and correlation context', async () => { vi.stubGlobal('fetch', vi.fn().mockResolvedValue(new Response(JSON.stringify({ title: 'Begrensd', detail: 'Probeer een kortere periode.' }), { status: 422, headers: { 'content-type': 'application/problem+json', 'x-correlation-id': 'corr-123' } }))); await expect(requestJSON('/api/v1/example')).rejects.toMatchObject({ status: 422, correlationId: 'corr-123', message: 'Probeer een kortere periode.' } satisfies Partial); }); it('retries safe GET requests only within the configured bound', async () => { const fetcher = vi.fn().mockResolvedValueOnce(new Response('{}', { status: 503 })).mockResolvedValueOnce(new Response(JSON.stringify({ ok: true }), { status: 200, headers: { 'content-type': 'application/json' } })); vi.stubGlobal('fetch', fetcher); await expect(requestJSON<{ ok: boolean }>('/api/v1/example', { retries: 1 })).resolves.toEqual({ ok: true }); expect(fetcher).toHaveBeenCalledTimes(2); }); it('never retries mutations', async () => { const fetcher = vi.fn().mockResolvedValue(new Response('{}', { status: 503, headers: { 'content-type': 'application/problem+json' } })); vi.stubGlobal('fetch', fetcher); await expect(requestJSON('/api/v1/example', { method: 'POST', retries: 2 })).rejects.toBeInstanceOf(ApiProblemError); expect(fetcher).toHaveBeenCalledTimes(1); }); it.each([401, 403])('preserves authorization status %s without retry', async (status) => { const fetcher = vi.fn().mockResolvedValue(new Response(JSON.stringify({ title: 'Geen toegang', correlationId: 'corr-auth' }), { status, headers: { 'content-type': 'application/problem+json' } })); vi.stubGlobal('fetch', fetcher); await expect(requestJSON('/api/v1/protected', { retries: 2 })).rejects.toMatchObject({ status, correlationId: 'corr-auth' }); expect(fetcher).toHaveBeenCalledTimes(1); }); it('never retries an aborted request', async () => { const fetcher = vi.fn().mockRejectedValue(new DOMException('aborted', 'AbortError')); vi.stubGlobal('fetch', fetcher); await expect(requestJSON('/api/v1/example', { retries: 2 })).rejects.toMatchObject({ name: 'AbortError' }); expect(fetcher).toHaveBeenCalledTimes(1); }); });