admin/services/errorHandler.test.ts
alisaza e1eaf5eff5 feat: initial ghabilee-admin backoffice app
Extract admin dashboard from ghabilee-frontend2 into a dedicated Next.js
app for backoffice.ghabilee.ir (no SEO indexing / Clarity).
2026-09-05 13:12:59 +03:30

81 lines
3.2 KiB
TypeScript

import { AxiosError, AxiosHeaders } from 'axios'
import { describe, expect, it } from 'vitest'
import {
extractServerErrorDetail,
NETWORK_ERROR_MESSAGE_KEY,
normalizeServiceError,
resolveServiceErrorDisplayMessage,
} from '@/services/errorHandler'
describe('service error normalization', () => {
it('extracts nested validation messages', () => {
expect(extractServerErrorDetail({ body: { message: ['شماره نامعتبر است', 'کد منقضی شده است'] } })).toBe(
'شماره نامعتبر است\nکد منقضی شده است'
)
})
it('preserves API code, status and useful server detail', () => {
const error = new AxiosError('Request failed with status code 409', 'ERR_BAD_REQUEST', undefined, undefined, {
data: { message: 'رزرو فعال وجود دارد', code: 'ACTIVE_BOOKING_EXISTS' },
status: 409,
statusText: 'Conflict',
headers: {},
config: { headers: new AxiosHeaders() },
})
const normalized = normalizeServiceError(error)
expect(normalized.apiCode).toBe('ACTIVE_BOOKING_EXISTS')
expect(normalized.statusCode).toBe(409)
expect(normalized.detailMessage).toBe('رزرو فعال وجود دارد')
})
it('maps transport failures to localized network errors', () => {
const normalized = normalizeServiceError(new AxiosError('Network Error', 'ERR_NETWORK'))
expect(normalized.messageKey).toBe(NETWORK_ERROR_MESSAGE_KEY)
expect(
resolveServiceErrorDisplayMessage(normalized, {
apiError: 'خطای API',
networkError: 'خطای شبکه',
})
).toBe('خطای شبکه')
})
it('replaces an English API message with Persian copy and preserves its code', () => {
const error = new AxiosError('Request failed with status code 409', 'ERR_BAD_REQUEST', undefined, undefined, {
data: { message: 'An active booking already exists', code: 'ACTIVE_BOOKING_EXISTS' },
status: 409,
statusText: 'Conflict',
headers: {},
config: { headers: new AxiosHeaders() },
})
const normalized = normalizeServiceError(error)
expect(normalized.message).toBe('برای این رویداد رزرو فعال دارید.')
expect(normalized.detailMessage).toBe('برای این رویداد رزرو فعال دارید.')
expect(normalized.apiCode).toBe('ACTIVE_BOOKING_EXISTS')
})
it('uses a Persian status fallback for unknown English server errors', () => {
const error = new AxiosError('Request failed with status code 503', 'ERR_BAD_RESPONSE', undefined, undefined, {
data: { message: 'Service unavailable' },
status: 503,
statusText: 'Service Unavailable',
headers: {},
config: { headers: new AxiosHeaders() },
})
expect(normalizeServiceError(error).message).toBe('سرویس موقتاً در دسترس نیست. لطفاً کمی بعد دوباره تلاش کنید.')
})
it('never returns an English-only display message', () => {
expect(
resolveServiceErrorDisplayMessage(
{ message: 'Internal Server Error', detailMessage: 'Database connection failed' },
{ apiError: 'خطای API', networkError: 'خطای شبکه' }
)
).toBe('خطایی در انجام درخواست پیش آمد.')
})
})