init
This commit is contained in:
175
tests/request.test.js
Normal file
175
tests/request.test.js
Normal file
@@ -0,0 +1,175 @@
|
||||
const { createRequester, RequestError } = require('../services/request')
|
||||
|
||||
describe('createRequester', () => {
|
||||
test('normalizes successful responses', async () => {
|
||||
const requester = createRequester({
|
||||
requestAdapter: jest.fn().mockResolvedValue({
|
||||
statusCode: 200,
|
||||
data: {
|
||||
code: 0,
|
||||
data: { id: 1, name: 'Xuanzhi' },
|
||||
message: 'ok'
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
await expect(
|
||||
requester({
|
||||
url: '/users/me',
|
||||
method: 'GET'
|
||||
})
|
||||
).resolves.toEqual({
|
||||
code: 0,
|
||||
data: { id: 1, name: 'Xuanzhi' },
|
||||
message: 'ok'
|
||||
})
|
||||
})
|
||||
|
||||
test('retries retryable transport failures once', async () => {
|
||||
const requestAdapter = jest
|
||||
.fn()
|
||||
.mockRejectedValueOnce(new Error('timeout'))
|
||||
.mockResolvedValueOnce({
|
||||
statusCode: 200,
|
||||
data: {
|
||||
code: 0,
|
||||
data: { ok: true },
|
||||
message: 'ok'
|
||||
}
|
||||
})
|
||||
|
||||
const requester = createRequester({
|
||||
requestAdapter,
|
||||
shouldRetry: error => error.message === 'timeout'
|
||||
})
|
||||
|
||||
await expect(
|
||||
requester({
|
||||
url: '/reports/slow-task',
|
||||
retry: 1
|
||||
})
|
||||
).resolves.toEqual({
|
||||
code: 0,
|
||||
data: { ok: true },
|
||||
message: 'ok'
|
||||
})
|
||||
|
||||
expect(requestAdapter).toHaveBeenCalledTimes(2)
|
||||
})
|
||||
|
||||
test('rejects business errors with a normalized error instance', async () => {
|
||||
const requester = createRequester({
|
||||
requestAdapter: jest.fn().mockResolvedValue({
|
||||
statusCode: 200,
|
||||
data: {
|
||||
code: 50001,
|
||||
data: null,
|
||||
message: 'invalid payload'
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
await expect(
|
||||
requester({
|
||||
url: '/orders',
|
||||
method: 'POST',
|
||||
data: { name: '' }
|
||||
})
|
||||
).rejects.toEqual(
|
||||
expect.objectContaining({
|
||||
name: 'RequestError',
|
||||
code: 50001,
|
||||
message: 'invalid payload'
|
||||
})
|
||||
)
|
||||
|
||||
expect(RequestError).toBeDefined()
|
||||
})
|
||||
|
||||
test('clears auth state and notifies unauthorized handler when token expires', async () => {
|
||||
const onUnauthorized = jest.fn()
|
||||
const sessionStore = {
|
||||
clearSession: jest.fn()
|
||||
}
|
||||
|
||||
const requester = createRequester({
|
||||
requestAdapter: jest.fn().mockResolvedValue({
|
||||
statusCode: 200,
|
||||
data: {
|
||||
code: 401,
|
||||
data: null,
|
||||
message: 'token expired'
|
||||
}
|
||||
}),
|
||||
authExpiredCodes: [401],
|
||||
onUnauthorized,
|
||||
sessionStore
|
||||
})
|
||||
|
||||
await expect(requester({ url: '/users/me' })).rejects.toEqual(
|
||||
expect.objectContaining({
|
||||
code: 401,
|
||||
message: 'token expired'
|
||||
})
|
||||
)
|
||||
|
||||
expect(sessionStore.clearSession).toHaveBeenCalledTimes(1)
|
||||
expect(onUnauthorized).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
code: 401,
|
||||
message: 'token expired'
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
test('deduplicates in-flight requests when dedupe is enabled', async () => {
|
||||
let resolveRequest
|
||||
const requestAdapter = jest.fn(
|
||||
() =>
|
||||
new Promise(resolve => {
|
||||
resolveRequest = resolve
|
||||
})
|
||||
)
|
||||
|
||||
const requester = createRequester({
|
||||
requestAdapter
|
||||
})
|
||||
|
||||
const firstPromise = requester({
|
||||
url: '/orders/submit',
|
||||
method: 'POST',
|
||||
data: { skuId: 1 },
|
||||
dedupe: true
|
||||
})
|
||||
const secondPromise = requester({
|
||||
url: '/orders/submit',
|
||||
method: 'POST',
|
||||
data: { skuId: 1 },
|
||||
dedupe: true
|
||||
})
|
||||
|
||||
resolveRequest({
|
||||
statusCode: 200,
|
||||
data: {
|
||||
code: 0,
|
||||
data: { orderId: 'A1001' },
|
||||
message: 'ok'
|
||||
}
|
||||
})
|
||||
|
||||
await expect(Promise.all([firstPromise, secondPromise])).resolves.toEqual([
|
||||
{
|
||||
code: 0,
|
||||
data: { orderId: 'A1001' },
|
||||
message: 'ok'
|
||||
},
|
||||
{
|
||||
code: 0,
|
||||
data: { orderId: 'A1001' },
|
||||
message: 'ok'
|
||||
}
|
||||
])
|
||||
|
||||
expect(requestAdapter).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user