51 lines
2.9 KiB
JavaScript
51 lines
2.9 KiB
JavaScript
import test from 'node:test'
|
|||
|
|
import assert from 'node:assert/strict'
|
||
|
|
import { createFlowContext, requireSuccess } from './prod-release-http.mjs'
|
||
|
|
const settings = { apiBase: 'https://fixture.invalid/api', credentials: { ADMIN: { loginId: 'fixture', password: 'private' } } }
|
||
|
|
function harness(fetcher, saveError = false) {
|
||
|
|
const state = { requests: [] }, saves = []
|
||
|
|
const save = async patch => { if (saveError) throw Error('disk failed'); Object.assign(state,patch); saves.push(structuredClone(state)) }
|
||
|
|
return { state, saves, ctx: createFlowContext({ settings, state, save, fetcher }) }
|
||
|
|
}
|
||
|
|
test('persists intent before writes and never saves credentials or tokens', async () => {
|
||
|
|
let h
|
||
|
|
h = harness(async (_url, options) => {
|
||
|
|
assert.equal(h.state.requests.at(-1).status, 'INTENT')
|
||
|
|
return new Response(JSON.stringify({ code: '200', data: { accessToken: 'access-secret', refreshToken: 'refresh-secret' } }))
|
||
|
|
})
|
||
|
|
await h.ctx.login('ADMIN')
|
||
|
|
await h.ctx.close()
|
||
|
|
assert.doesNotMatch(JSON.stringify(h.state), /private|access-secret|refresh-secret/)
|
||
|
|
assert.ok(h.state.requests.every(row=>row.status==='DONE'))
|
||
|
|
})
|
||
|
|
test('disk failure prevents HTTP and unknown network result is never retried', async () => {
|
||
|
|
let calls=0
|
||
|
|
const broken=harness(async()=>{calls++;throw Error('network')},true)
|
||
|
|
await assert.rejects(broken.ctx.request('POST','/api/platform/v1/example',{}),/disk/)
|
||
|
|
assert.equal(calls,0)
|
||
|
|
const h=harness(async()=>{calls++;throw Error('network')})
|
||
|
|
await assert.rejects(h.ctx.request('POST','/api/platform/v1/example',{}),/结果不确定/)
|
||
|
|
assert.equal(calls,1)
|
||
|
|
assert.equal(h.state.requests[0].status,'UNKNOWN')
|
||
|
|
})
|
||
|
|
test('business errors retain diagnostic IDs and binary responses preserve bytes',async()=>{
|
||
|
|
const h=harness(async()=>new Response(JSON.stringify({code:'A0403',requestId:'req-1',traceId:'trace-1',message:'private'})))
|
||
|
|
const response=await h.ctx.request('GET','/api/platform/v1/example')
|
||
|
|
assert.throws(()=>requireSuccess(response),/A0403.*req-1.*trace-1/)
|
||
|
|
assert.doesNotMatch(JSON.stringify(h.state),/private/)
|
||
|
|
const binary=harness(async()=>new Response('%PDF-fixture',{headers:{'content-type':'application/pdf'}}))
|
||
|
|
const pdf=await binary.ctx.requestBinary('POST','/api/platform/inbounds/1/carton-label-pdf')
|
||
|
|
assert.equal(Buffer.from(pdf.bytes).toString(),'%PDF-fixture')
|
||
|
|
assert.equal(pdf.contentType,'application/pdf')
|
||
|
|
})
|
||
|
|
|
||
|
|
test('request limit blocks business calls but permits session logout', async () => {
|
||
|
|
const h = harness(async () => new Response(JSON.stringify({ code: '200', data: {} })))
|
||
|
|
h.ctx.registerSession({ accessToken: 'secret', refreshToken: 'refresh' })
|
||
|
|
h.state.requests = Array.from({ length: 2500 }, (_, index) => ({ sequence: index + 1, status: 'DONE' }))
|
||
|
|
await assert.rejects(h.ctx.request('GET', '/api/platform/v1/example'), /安全上限/)
|
||
|
|
assert.deepEqual(await h.ctx.close(), [])
|
||
|
|
assert.equal(h.state.requests.at(-1).path, '/api/auth/logout')
|
||
|
|
assert.equal(h.state.requests.at(-1).status, 'DONE')
|
||
|
|
})
|