Files
admin-web/src/shared/api/http.test.ts
T

91 lines
2.9 KiB
TypeScript
Raw Normal View History

2026-07-30 17:59:43 +08:00
import axios, { AxiosHeaders } from 'axios'
2026-07-31 13:43:16 +08:00
import { afterEach, describe, expect, it, vi } from 'vitest'
import {
ApiResponseError,
getApiErrorDetails,
http,
registerAuthRefreshHandler,
registerAuthSessionExpiredHandler,
unwrapApiResponse,
} from './http'
const originalAdapter = http.defaults.adapter
afterEach(() => {
http.defaults.adapter = originalAdapter
registerAuthRefreshHandler(async () => { throw new Error('refresh handler is not configured') })
registerAuthSessionExpiredHandler(() => undefined)
})
2026-07-30 17:59:43 +08:00
describe('API error diagnostics', () => {
it('treats only body code 200 as success', () => {
expect(unwrapApiResponse({ code: '200', message: 'success', data: { id: '1' } }))
.toEqual({ id: '1' })
expect(() => unwrapApiResponse({ code: '0', message: 'legacy success code', data: null }))
.toThrow(ApiResponseError)
})
2026-07-30 17:59:43 +08:00
it('keeps business request and trace identifiers when unwrapping fails', () => {
expect(() => unwrapApiResponse({
code: 'A0403',
message: '无权限',
data: null,
requestId: 'request-1',
traceId: 'trace-1',
})).toThrow(ApiResponseError)
try {
unwrapApiResponse({ code: 'A0403', message: '无权限', data: null, requestId: 'request-1', traceId: 'trace-1' })
} catch (error) {
expect(getApiErrorDetails(error)).toEqual({
message: '无权限',
code: 'A0403',
requestId: 'request-1',
traceId: 'trace-1',
})
}
})
it('extracts identifiers from an HTTP error envelope', () => {
const error = new axios.AxiosError('Request failed', 'ERR_BAD_RESPONSE', undefined, undefined, {
status: 503,
statusText: 'Service Unavailable',
headers: {},
config: { headers: new AxiosHeaders() },
data: { code: 'S0503', message: '服务不可用', requestId: 'request-2', traceId: 'trace-2' },
})
expect(getApiErrorDetails(error)).toEqual({
message: '服务不可用',
code: 'S0503',
requestId: 'request-2',
traceId: 'trace-2',
})
})
2026-07-31 13:43:16 +08:00
it('notifies session expiry once when concurrent 401 requests share a failed refresh', async () => {
const refresh = vi.fn(async () => { throw new Error('refresh token expired') })
const expired = vi.fn()
registerAuthRefreshHandler(refresh)
registerAuthSessionExpiredHandler(expired)
http.defaults.adapter = async (config) => {
throw new axios.AxiosError('Unauthorized', 'ERR_BAD_REQUEST', config, undefined, {
status: 401,
statusText: 'Unauthorized',
headers: {},
config,
data: { code: 'A0401', message: '登录状态已过期' },
})
}
const results = await Promise.allSettled([
http.get('/platform/v1/orders'),
http.get('/platform/v1/warehouses'),
])
expect(results.every((result) => result.status === 'rejected')).toBe(true)
expect(refresh).toHaveBeenCalledTimes(1)
expect(expired).toHaveBeenCalledTimes(1)
})
2026-07-30 17:59:43 +08:00
})