import { afterEach, describe, expect, it, vi } from 'vitest'; import { api, ApiError, errorMessage } from '../apiClient.ts'; const jsonResponse = (body: unknown, status = 200, headers: Record = {}) => new Response(JSON.stringify(body), { status, headers: { 'Content-Type': 'application/json', ...headers }, }); describe('apiClient', () => { afterEach(() => { vi.unstubAllGlobals(); document.cookie = 'csrftoken=; Max-Age=0; path=/'; }); it('unwraps paginated list results', async () => { vi.stubGlobal( 'fetch', vi.fn().mockResolvedValue( jsonResponse({ count: 1, next: null, previous: null, results: [{ id: 7, site_name: 'Sukawarna', user: 1 }], }) ) ); const sites = await api.sites.list(); expect(sites).toEqual([{ id: 7, site_name: 'Sukawarna', user: 1 }]); }); it('unwraps a bare array list', async () => { vi.stubGlobal( 'fetch', vi.fn().mockResolvedValue(jsonResponse([{ id: 2, site_name: 'Cilayang', user: 1 }])) ); const sites = await api.sites.list(); expect(sites[0]?.site_name).toBe('Cilayang'); }); it('sends CSRF token on POST', async () => { document.cookie = 'csrftoken=abc123; path=/'; const fetchMock = vi.fn().mockResolvedValue(jsonResponse({ id: 1, user_name: 'admin' })); vi.stubGlobal('fetch', fetchMock); await api.auth.login('admin', 'admin123'); const init = fetchMock.mock.calls[0]?.[1] as RequestInit; const headers = new Headers(init.headers); expect(headers.get('X-CSRFToken')).toBe('abc123'); expect(init.credentials).toBe('include'); }); it('throws ApiError with detail and status', async () => { document.cookie = 'csrftoken=abc123; path=/'; vi.stubGlobal( 'fetch', vi.fn().mockResolvedValue(jsonResponse({ detail: 'Bad credentials' }, 400)) ); await expect(api.auth.login('x', 'y')).rejects.toMatchObject({ name: 'ApiError', status: 400, message: 'Bad credentials', }); }); it('maps unknown errors through errorMessage', () => { expect(errorMessage(new ApiError('Gagal', 502, null))).toBe('Gagal'); expect(errorMessage(new Error('boom'))).toBe('boom'); expect(errorMessage('nope')).toBe('Terjadi kesalahan'); }); });