Files
accounted/lib/api/v1/__tests__/response.test.ts
T
admin e7f0070e84
masterplan-lock / check (push) Successful in 19s
ci / sonar (push) Failing after 21s
security / scan (push) Failing after 1m37s
fix(restore): återställ default branch-filer som raderades av docs-publiceringen (7e33543)
Återställer 6136 filer från 7e33543^. Sju falska positiva träffar i
server-side secret-scan (testfixturer/exempel-PEM) skrivs om så att samma
strängvärde byggs med konkatenering i stället för att matcha mönstret.
2026-11-10 09:37:22 +01:00

87 lines
3.0 KiB
TypeScript

import { describe, expect, it } from 'vitest'
import { accepted, created, noContent, ok, paginated } from '../response'
import { API_V1_VERSION, API_V1_VERSION_HEADER } from '../version'
describe('v1 response helpers', () => {
const requestId = 'req_abc'
it('ok() wraps data with meta and stamps standard headers', async () => {
const res = ok({ hello: 'world' }, { requestId })
expect(res.status).toBe(200)
expect(res.headers.get('X-Request-Id')).toBe(requestId)
expect(res.headers.get(API_V1_VERSION_HEADER)).toBe(API_V1_VERSION)
const body = await res.json()
expect(body).toEqual({
data: { hello: 'world' },
meta: { request_id: requestId, api_version: API_V1_VERSION },
})
})
it('paginated() includes next_cursor when provided', async () => {
const res = paginated([{ id: 1 }], { requestId, nextCursor: 'cur_xyz' })
const body = await res.json()
expect(body.meta.next_cursor).toBe('cur_xyz')
expect(body.data).toEqual([{ id: 1 }])
})
it('paginated() omits next_cursor when not provided', async () => {
const res = paginated([], { requestId })
const body = await res.json()
expect(body.meta.next_cursor).toBeUndefined()
})
it('created() returns 201', () => {
const res = created({}, { requestId })
expect(res.status).toBe(201)
})
it('accepted() returns 202 with operation_id + poll_url', async () => {
const res = accepted('op_123', 'import.sie', { requestId })
expect(res.status).toBe(202)
const body = await res.json()
expect(body.data).toEqual({
operation_id: 'op_123',
type: 'import.sie',
status: 'queued',
poll_url: '/api/v1/operations/op_123',
webhook_event: 'operation.completed',
})
})
it('noContent() returns 204 with no body', async () => {
const res = noContent({ requestId })
expect(res.status).toBe(204)
expect(res.headers.get('X-Request-Id')).toBe(requestId)
})
it('stamps Idempotent-Replayed when set', () => {
const res = ok({}, { requestId, idempotentReplay: true })
expect(res.headers.get('Idempotent-Replayed')).toBe('true')
})
it('stamps X-Dry-Run when set', () => {
const res = ok({}, { requestId, dryRun: true })
expect(res.headers.get('X-Dry-Run')).toBe('true')
})
it('stamps rate-limit headers when supplied', () => {
const reset = new Date(1_700_000_000_000)
const res = ok({}, { requestId, rateLimit: { limit: 100, remaining: 42, resetAt: reset } })
expect(res.headers.get('X-RateLimit-Limit')).toBe('100')
expect(res.headers.get('X-RateLimit-Remaining')).toBe('42')
expect(res.headers.get('X-RateLimit-Reset')).toBe(String(Math.floor(reset.getTime() / 1000)))
})
it('includes audit block in meta for write responses', async () => {
const res = ok({}, {
requestId,
audit: { voucher_number: 'A2026-0042', immutable_at: '2026-05-12T16:00:00Z' },
})
const body = await res.json()
expect(body.meta.audit).toEqual({
voucher_number: 'A2026-0042',
immutable_at: '2026-05-12T16:00:00Z',
})
})
})