112 lines
3.3 KiB
TypeScript
112 lines
3.3 KiB
TypeScript
import { http, HttpResponse } from 'msw'
|
|
import { describe, expect, it } from 'vitest'
|
|
import { server } from '../test/server'
|
|
import { ApiError, api } from './api'
|
|
|
|
describe('api.postJson', () => {
|
|
it('sends application/json and returns the parsed body', async () => {
|
|
let sentContentType: string | null = null
|
|
|
|
server.use(
|
|
http.post('http://localhost/api/login', async ({ request }) => {
|
|
sentContentType = request.headers.get('Content-Type')
|
|
return HttpResponse.json({ id: 'u1', email: 'a@b.com' })
|
|
}),
|
|
)
|
|
|
|
const result = await api.postJson<{ id: string; email: string }>('/login', {
|
|
username: 'a@b.com',
|
|
password: 'secret',
|
|
})
|
|
|
|
expect(sentContentType).toBe('application/json')
|
|
expect(result).toEqual({ id: 'u1', email: 'a@b.com' })
|
|
})
|
|
|
|
it('throws ApiError on a non-2xx response', async () => {
|
|
server.use(
|
|
http.post('http://localhost/api/login', () =>
|
|
HttpResponse.json({ message: 'bad creds' }, { status: 401 }),
|
|
),
|
|
)
|
|
|
|
const error = await api.postJson('/login', {}).catch((e: unknown) => e)
|
|
|
|
expect(error).toBeInstanceOf(ApiError)
|
|
expect((error as ApiError).status).toBe(401)
|
|
})
|
|
})
|
|
|
|
describe('api path guard', () => {
|
|
it('throws if a path already includes the /api prefix', async () => {
|
|
// Callers pass `/login`, not `/api/login` — the client prepends BASE.
|
|
await expect(api.get('/api/login')).rejects.toThrow(/must not include/i)
|
|
})
|
|
})
|
|
|
|
describe('api.get', () => {
|
|
it('sends Accept: application/ld+json and returns the parsed body', async () => {
|
|
let accept: string | null = null
|
|
|
|
server.use(
|
|
http.get('http://localhost/api/scenarios', ({ request }) => {
|
|
accept = request.headers.get('Accept')
|
|
return HttpResponse.json({ member: [] })
|
|
}),
|
|
)
|
|
|
|
const result = await api.get<{ member: unknown[] }>('/scenarios')
|
|
|
|
expect(accept).toBe('application/ld+json')
|
|
expect(result).toEqual({ member: [] })
|
|
})
|
|
})
|
|
|
|
describe('api.post', () => {
|
|
it('sends Content-Type: application/ld+json (API Platform write format)', async () => {
|
|
let contentType: string | null = null
|
|
|
|
server.use(
|
|
http.post('http://localhost/api/buckets', async ({ request }) => {
|
|
contentType = request.headers.get('Content-Type')
|
|
return HttpResponse.json({ '@id': '/api/buckets/1' }, { status: 201 })
|
|
}),
|
|
)
|
|
|
|
await api.post('/buckets', { name: 'Rent' })
|
|
|
|
expect(contentType).toBe('application/ld+json')
|
|
})
|
|
})
|
|
|
|
describe('api.patch', () => {
|
|
it('sends Content-Type: application/merge-patch+json', async () => {
|
|
let contentType: string | null = null
|
|
|
|
server.use(
|
|
http.patch('http://localhost/api/buckets/1', async ({ request }) => {
|
|
contentType = request.headers.get('Content-Type')
|
|
return HttpResponse.json({ '@id': '/api/buckets/1' })
|
|
}),
|
|
)
|
|
|
|
await api.patch('/buckets/1', { name: 'Rent' })
|
|
|
|
expect(contentType).toBe('application/merge-patch+json')
|
|
})
|
|
})
|
|
|
|
describe('api.delete', () => {
|
|
it('resolves to undefined on a 204 No Content', async () => {
|
|
server.use(
|
|
http.delete(
|
|
'http://localhost/api/buckets/1',
|
|
() => new HttpResponse(null, { status: 204 }),
|
|
),
|
|
)
|
|
|
|
const result = await api.delete('/buckets/1')
|
|
|
|
expect(result).toBeUndefined()
|
|
})
|
|
})
|