openreader/tests/unit/server-route-error-mappings.vitest.spec.ts

80 lines
2.8 KiB
TypeScript

import { describe, expect, test } from 'vitest';
import { AdminProviderError } from '../../src/lib/server/admin/providers';
import { errorResponse } from '../../src/lib/server/errors/next-response';
import { makeServerErrorContext } from './support/factories';
describe('route error mapping contract', () => {
test('admin provider validation errors map to 4xx via route normalize policy', async () => {
const adminError = new AdminProviderError('slug is required', 400);
const response = errorResponse(adminError, {
apiErrorMessage: adminError.message,
normalize: makeServerErrorContext({
code: 'ADMIN_PROVIDERS_CREATE_REQUEST_FAILED',
errorClass: 'validation',
httpStatus: adminError.status,
retryable: false,
}),
});
expect(response.status).toBe(400);
await expect(response.json()).resolves.toEqual({
error: 'slug is required',
errorCode: 'ADMIN_PROVIDERS_CREATE_REQUEST_FAILED',
retryable: false,
});
});
test.each([
{
name: 'documents storage failures map to retryable 503',
thrown: new Error('blobstore timeout'),
apiErrorMessage: 'Failed to fetch document blob',
normalize: makeServerErrorContext({
code: 'DOCUMENT_BLOB_FETCH_FAILED',
errorClass: 'storage',
}),
expectedStatus: 503,
expectedBody: {
error: 'Failed to fetch document blob',
errorCode: 'DOCUMENT_BLOB_FETCH_FAILED',
retryable: true,
},
},
{
name: 'audiobook upstream failures map to retryable 502',
thrown: new Error('provider overloaded'),
apiErrorMessage: 'Failed to process audio chapter',
normalize: makeServerErrorContext({
code: 'AUDIOBOOK_CHAPTER_PROCESS_FAILED',
errorClass: 'upstream',
}),
expectedStatus: 502,
expectedBody: {
error: 'Failed to process audio chapter',
errorCode: 'AUDIOBOOK_CHAPTER_PROCESS_FAILED',
retryable: true,
},
},
{
name: 'user export auth initialization failure maps to 500 auth classification',
thrown: new Error('Auth not initialized'),
apiErrorMessage: 'Auth not initialized',
normalize: makeServerErrorContext({
code: 'USER_EXPORT_AUTH_NOT_INITIALIZED',
errorClass: 'auth',
httpStatus: 500,
retryable: false,
}),
expectedStatus: 500,
expectedBody: {
error: 'Auth not initialized',
errorCode: 'USER_EXPORT_AUTH_NOT_INITIALIZED',
retryable: false,
},
},
])('$name', async ({ thrown, apiErrorMessage, normalize, expectedStatus, expectedBody }) => {
const response = errorResponse(thrown, { apiErrorMessage, normalize });
expect(response.status).toBe(expectedStatus);
await expect(response.json()).resolves.toEqual(expectedBody);
});
});