You've already forked agentic-coding-workflow
feat(web): fetch-based api client with 401 handling and tests
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { configure, request } from '@/api/client'
|
||||
import { ApiException } from '@/api/types'
|
||||
|
||||
describe('api client', () => {
|
||||
let unauthorizedCalled = 0
|
||||
|
||||
beforeEach(() => {
|
||||
unauthorizedCalled = 0
|
||||
configure({
|
||||
tokenProvider: () => 'tok',
|
||||
onUnauthorized: () => {
|
||||
unauthorizedCalled++
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks()
|
||||
})
|
||||
|
||||
it('attaches bearer token and parses JSON on 200', async () => {
|
||||
const fetchMock = vi.spyOn(globalThis, 'fetch').mockResolvedValue(
|
||||
new Response(JSON.stringify({ x: 1 }), { status: 200 }),
|
||||
)
|
||||
const out = await request<{ x: number }>('/api/test')
|
||||
expect(out.x).toBe(1)
|
||||
const init = fetchMock.mock.calls[0][1] as RequestInit
|
||||
const headers = init.headers as Record<string, string>
|
||||
expect(headers['Authorization']).toBe('Bearer tok')
|
||||
expect(headers['X-Client-Request-ID']).toBeDefined()
|
||||
})
|
||||
|
||||
it('returns undefined on 204', async () => {
|
||||
vi.spyOn(globalThis, 'fetch').mockResolvedValue(new Response(null, { status: 204 }))
|
||||
const out = await request('/api/test', { method: 'DELETE' })
|
||||
expect(out).toBeUndefined()
|
||||
})
|
||||
|
||||
it('invokes onUnauthorized for 401 and throws', async () => {
|
||||
vi.spyOn(globalThis, 'fetch').mockResolvedValue(
|
||||
new Response(JSON.stringify({ code: 'unauthorized', message: 'no' }), { status: 401 }),
|
||||
)
|
||||
await expect(request('/api/test')).rejects.toBeInstanceOf(ApiException)
|
||||
expect(unauthorizedCalled).toBe(1)
|
||||
})
|
||||
|
||||
it('throws ApiException with body for 4xx/5xx', async () => {
|
||||
vi.spyOn(globalThis, 'fetch').mockResolvedValue(
|
||||
new Response(JSON.stringify({ code: 'invalid_input', message: 'bad' }), { status: 400 }),
|
||||
)
|
||||
try {
|
||||
await request('/api/test')
|
||||
throw new Error('should have thrown')
|
||||
} catch (e) {
|
||||
const ex = e as ApiException
|
||||
expect(ex.status).toBe(400)
|
||||
expect(ex.body.code).toBe('invalid_input')
|
||||
}
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user