import { describe, expect, it } from 'vitest'; import { createErrorResolver } from '../../src/errors/createErrorResolver'; const CATALOG = { AUTH_UNAUTHORIZED: 'Unauthorized access. Please sign in again.', FORBIDDEN: 'You do not have permission to perform this action.', USER_NOT_FOUND: 'User not found.', INTERNAL_ERROR: 'Unexpected request error.', REQUEST_FAILED: 'Request failed. Please try again.', }; const resolver = createErrorResolver({ catalog: CATALOG, fallbackCode: 'REQUEST_FAILED', defaultContext: 'default', contextOverrides: { session: { AUTH_UNAUTHORIZED: 'Session expired. Please sign in again.', }, }, inferCodeFromStatus: (status?: number | null) => { switch (status) { case 401: return 'AUTH_UNAUTHORIZED'; case 403: return 'FORBIDDEN'; case 404: return 'USER_NOT_FOUND'; default: if (status != null && status >= 500) { return 'INTERNAL_ERROR'; } return undefined; } }, inferCodeFromLegacyMessage: (message?: string | null) => { if (message?.toLowerCase() === 'unauthorized') { return 'AUTH_UNAUTHORIZED'; } return undefined; }, }); describe('createErrorResolver', () => { it('recognizes known error codes', () => { expect(resolver.isKnownErrorCode('AUTH_UNAUTHORIZED')).toBe(true); expect(resolver.isKnownErrorCode('NOPE')).toBe(false); }); it('returns context override for known code', () => { expect( resolver.resolveErrorMessage({ code: 'AUTH_UNAUTHORIZED', context: 'session', }), ).toBe('Session expired. Please sign in again.'); }); it('falls back from unknown code to legacy message inference', () => { expect( resolver.resolveErrorMessage({ code: 'UNKNOWN_CODE', fallbackMessage: 'unauthorized', }), ).toBe('Unauthorized access. Please sign in again.'); }); it('falls back to status mapping when code is missing', () => { expect(resolver.resolveErrorMessage({ status: 404 })).toBe('User not found.'); }); it('falls back to status mapping when legacy inference returns an unmapped code', () => { const resolverWithUnmappedLegacyCode = createErrorResolver({ catalog: CATALOG, inferCodeFromStatus: resolver.inferErrorCodeFromStatus, inferCodeFromLegacyMessage: () => 'LEGACY_ONLY_CODE', }); expect( resolverWithUnmappedLegacyCode.resolveErrorMessage({ status: 403, fallbackMessage: 'legacy message', }), ).toBe('You do not have permission to perform this action.'); }); it('uses fallbackCode when no code/status resolve and fallback message is missing', () => { expect(resolver.resolveErrorMessage({ status: 418 })).toBe('Request failed. Please try again.'); }); it('uses fallback message when no mapping exists and fallback code is unavailable', () => { const noFallbackCodeResolver = createErrorResolver({ catalog: CATALOG, inferCodeFromStatus: () => undefined, }); expect( noFallbackCodeResolver.resolveErrorMessage({ code: 'UNKNOWN', fallbackMessage: 'raw backend message', }), ).toBe('raw backend message'); }); it('returns default request failure message when no signal is available', () => { const emptyResolver = createErrorResolver({ catalog: {}, }); expect(emptyResolver.resolveErrorMessage({})).toBe('Request failed. Please try again.'); }); it('resolveOptionalErrorMessage returns undefined for empty inputs', () => { expect(resolver.resolveOptionalErrorMessage(undefined)).toBeUndefined(); expect(resolver.resolveOptionalErrorMessage(null)).toBeUndefined(); }); it('resolveOptionalErrorMessage resolves known codes', () => { expect(resolver.resolveOptionalErrorMessage('FORBIDDEN')).toBe( 'You do not have permission to perform this action.', ); }); it('toErrorMessage prefers rawMessage over message and handles unknown values', () => { expect( resolver.toErrorMessage({ status: 403, rawMessage: 'unauthorized', message: 'ignored message', }), ).toBe('Unauthorized access. Please sign in again.'); expect(resolver.toErrorMessage('boom')).toBe('Request failed. Please try again.'); expect(resolver.toErrorMessage(null)).toBe('Request failed. Please try again.'); }); it('exposes inferErrorCodeFromStatus', () => { expect(resolver.inferErrorCodeFromStatus(401)).toBe('AUTH_UNAUTHORIZED'); expect(resolver.inferErrorCodeFromStatus(500)).toBe('INTERNAL_ERROR'); expect(resolver.inferErrorCodeFromStatus(418)).toBeUndefined(); expect(resolver.inferErrorCodeFromStatus(null)).toBeUndefined(); }); });