Files
glchat/web/tests/client.test.ts
T

66 lines
2.0 KiB
TypeScript
Raw Permalink Normal View History

import { describe, expect, it, vi } from 'vitest';
import { ApiError, request } from '@/api/client';
function jsonResponse(body: unknown, status = 200): Response {
return new Response(JSON.stringify(body), {
status,
headers: { 'Content-Type': 'application/json' },
});
}
describe('api client', () => {
it('returns the parsed payload on success', async () => {
const fetchMock = vi.fn().mockResolvedValue(jsonResponse({ api_version: 'v1' }));
vi.stubGlobal('fetch', fetchMock);
await expect(request<{ api_version: string }>('/meta')).resolves.toEqual({
api_version: 'v1',
});
expect(fetchMock).toHaveBeenCalledWith(
'/api/v1/meta',
expect.objectContaining({ method: 'GET', credentials: 'same-origin' }),
);
});
it('maps the server error envelope to ApiError', async () => {
vi.stubGlobal(
'fetch',
vi
.fn()
.mockResolvedValue(
jsonResponse({ error: { code: 'perm.denied', message: 'no access' } }, 403),
),
);
await expect(request('/guilds/1')).rejects.toMatchObject({
name: 'ApiError',
code: 'perm.denied',
status: 403,
});
});
it('falls back to internal.error when the body is not an envelope', async () => {
vi.stubGlobal(
'fetch',
vi.fn().mockResolvedValue(new Response('gateway timeout', { status: 504 })),
);
const error = await request('/meta').catch((reason: unknown) => reason);
expect(error).toBeInstanceOf(ApiError);
expect((error as ApiError).code).toBe('internal.error');
expect((error as ApiError).status).toBe(504);
});
it('sends a json body for write requests', async () => {
const fetchMock = vi.fn().mockResolvedValue(jsonResponse({ ok: true }));
vi.stubGlobal('fetch', fetchMock);
await request('/guilds', { method: 'POST', body: { name: 'test' } });
const init = fetchMock.mock.calls[0]?.[1] as RequestInit;
expect(init.body).toBe('{"name":"test"}');
expect((init.headers as Record<string, string>)['Content-Type']).toBe('application/json');
});
});