soulsync/webui/src/app/api-client.test.ts
Antti Kettunen 9cde9442b7
Improve API JSON error handling
- Keep ky HTTPError instances intact instead of flattening them
- Use the parsed error payload when the server sends a useful message
- Fix the Issues default search type so issueId stays optional
- Add regression tests for the JSON helper behavior
2026-05-13 22:26:24 +03:00

54 lines
1.7 KiB
TypeScript

import { describe, expect, it, vi } from 'vite-plus/test';
import { HTTPError } from 'ky';
import type { ResponsePromise } from 'ky';
import { readJson } from './api-client';
function createHttpError(body: unknown, status = 400) {
const response = new Response(JSON.stringify(body), {
status,
statusText: 'Bad Request',
headers: {
'Content-Type': 'application/json',
},
});
const request = new Request('https://example.com/api/test');
const error = new HTTPError(response, request, {} as any);
error.data = body;
return error;
}
describe('readJson', () => {
it('returns parsed JSON', async () => {
const json = vi.fn().mockResolvedValue({ ok: true });
const promise = { json } as unknown as ResponsePromise<{ ok: boolean }>;
await expect(readJson(promise)).resolves.toEqual({ ok: true });
expect(json).toHaveBeenCalledTimes(1);
});
it('keeps HTTPError instances intact and uses the payload message', async () => {
const error = createHttpError({ error: 'Nope' }, 403);
const json = vi.fn().mockRejectedValue(error);
const promise = { json } as unknown as ResponsePromise<unknown>;
const result = readJson(promise);
await expect(result).rejects.toBe(error);
await expect(result).rejects.toHaveProperty('message', 'Nope');
});
it('falls back to the HTTPError message when the payload is unhelpful', async () => {
const error = createHttpError({ detail: 'missing error field' }, 404);
const json = vi.fn().mockRejectedValue(error);
const promise = { json } as unknown as ResponsePromise<unknown>;
const result = readJson(promise);
await expect(result).rejects.toBe(error);
await expect(result).rejects.toHaveProperty(
'message',
error.message,
);
});
});