优化构架
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
import axios, { AxiosHeaders } from 'axios'
|
||||
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)
|
||||
})
|
||||
|
||||
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)
|
||||
})
|
||||
|
||||
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',
|
||||
})
|
||||
})
|
||||
|
||||
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)
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user