openreader/tests/unit/server-error-contract.vitest.spec.ts

85 lines
2.7 KiB
TypeScript

import { describe, expect, test } from 'vitest';
import {
ServerAppError,
createServerAppError,
isServerAppError,
normalizeServerError,
toApiErrorBody,
toHttpStatus,
} from '../../src/lib/server/errors/contract';
import { makeServerAppErrorInput } from './support/factories';
describe('server error contract', () => {
test('normalizes unknown throwable to fallback shape', () => {
const normalized = normalizeServerError('boom');
expect(normalized.code).toBe('UNKNOWN_SERVER_ERROR');
expect(normalized.errorClass).toBe('unknown');
expect(normalized.httpStatus).toBe(500);
expect(normalized.retryable).toBe(false);
expect(normalized.message).toBe('boom');
});
test('preserves ServerAppError metadata', () => {
const err = createServerAppError(makeServerAppErrorInput({
code: 'USER_PROGRESS_UPDATE_FAILED',
message: 'Failed to update progress',
errorClass: 'db',
retryable: true,
httpStatus: 500,
details: { operation: 'update_progress' },
}));
const normalized = normalizeServerError(err);
expect(isServerAppError(err)).toBe(true);
expect(normalized.code).toBe('USER_PROGRESS_UPDATE_FAILED');
expect(normalized.errorClass).toBe('db');
expect(normalized.httpStatus).toBe(500);
expect(normalized.retryable).toBe(true);
expect(normalized.details?.operation).toBe('update_progress');
});
test('normalizes partially-shaped thrown errors with code sanitization', () => {
const thrown = Object.assign(new Error('Timed out waiting for storage read'), {
code: 'not_valid_code',
errorClass: 'timeout',
httpStatus: 604,
retryable: true,
});
const normalized = normalizeServerError(thrown);
expect(normalized.code).toBe('UNKNOWN_SERVER_ERROR');
expect(normalized.errorClass).toBe('timeout');
expect(normalized.httpStatus).toBe(599);
expect(normalized.retryable).toBe(true);
});
test('maps normalized errors to API body + status', () => {
const normalized = normalizeServerError(
new ServerAppError({
code: 'UPSTREAM_TTS_ERROR',
message: 'Upstream failure',
errorClass: 'upstream',
}),
);
const body = toApiErrorBody(normalized, { includeDetails: false });
expect(body).toEqual({
error: 'Upstream failure',
errorCode: 'UPSTREAM_TTS_ERROR',
retryable: true,
});
expect(toHttpStatus(normalized)).toBe(502);
});
test('rejects invalid server error code at creation boundary', () => {
expect(() => createServerAppError(makeServerAppErrorInput({
code: 'bad-code',
message: 'Invalid',
errorClass: 'validation',
}))).toThrow(/Invalid ServerAppError code/i);
});
});