Files
border-red-post-nalati/frontend/tests/session.test.mjs

71 lines
3.6 KiB
JavaScript

import assert from 'node:assert/strict'
import { readFile } from 'node:fs/promises'
import test from 'node:test'
import ts from 'typescript'
async function session(t, fetch_) {
const previous = globalThis.fetch
globalThis.fetch = fetch_
t.after(() => { globalThis.fetch = previous })
const source = await readFile(new URL('../src/services/session.ts', import.meta.url), 'utf8')
const { outputText } = ts.transpileModule(source, { compilerOptions: { target: ts.ScriptTarget.ES2022, module: ts.ModuleKind.ESNext } })
return import(`data:text/javascript;base64,${Buffer.from(outputText).toString('base64')}#${t.name}`)
}
test('JSON login and binary export share Cookie/CSRF transport without parsing JSONL as JSON', async t => {
const content = '{"record_type":"manifest"}\n{"query":"合成测试"}\n'
const calls = []
const api = await session(t, async (path, init) => {
calls.push([path, init])
if (path === '/api/auth/login') return Response.json({ csrf_token: 'fixture-csrf' })
return new Response(content, { headers: { 'Content-Disposition': 'attachment; filename="fixture.jsonl"', 'X-Records-SHA256': 'a'.repeat(64) } })
})
await api.apiRequest('/api/auth/login', { method: 'POST', body: '{}' })
const file = await api.apiDownload('/api/retrieval/exports', { method: 'POST', body: '{"run_ids":[]}' }, true)
assert.equal(await file.blob.text(), content)
assert.equal(file.filename, 'fixture.jsonl')
assert.equal(file.recordsSha256, 'a'.repeat(64))
assert.equal(calls[1][1].credentials, 'include')
assert.equal(calls[1][1].headers.get('X-CSRF-Token'), 'fixture-csrf')
assert.equal(calls[1][1].headers.get('Content-Type'), 'application/json')
assert.equal(calls[1][1].headers.get('Accept'), 'application/x-ndjson')
assert.equal(calls[0][1].headers.get('Accept'), 'application/json')
})
test('download refreshes missing session token and preserves server authorization errors', async t => {
const calls = []
const api = await session(t, async (path, init) => {
calls.push([path, init])
if (path === '/api/auth/me') return Response.json({ csrf_token: 'refreshed-csrf' })
return Response.json({ detail: '需要管理员权限' }, { status: 403 })
})
await assert.rejects(api.apiDownload('/api/retrieval/exports', { method: 'POST', body: '{}' }, true), error => {
assert.ok(error instanceof api.ApiError)
assert.equal(error.status, 403)
assert.equal(error.message, '需要管理员权限')
return true
})
assert.equal(calls.length, 2)
assert.equal(calls[0][0], '/api/auth/me')
assert.equal(calls[1][1].headers.get('X-CSRF-Token'), 'refreshed-csrf')
})
test('401 download clears stale token and unsafe filename is not propagated', async t => {
let current = 'old-csrf'
let failed = false
const api = await session(t, async (path, init) => {
if (path === '/api/auth/login' || path === '/api/auth/me') return Response.json({ csrf_token: current })
assert.equal(init.headers.get('X-CSRF-Token'), current)
if (!failed) {
failed = true; current = 'new-csrf'
return Response.json({ detail: '请先登录' }, { status: 401 })
}
return new Response('fixture', { headers: { 'Content-Disposition': 'attachment; filename="../../fixture.jsonl"' } })
})
await api.apiRequest('/api/auth/login', { method: 'POST', body: '{}' })
await assert.rejects(api.apiDownload('/api/retrieval/exports', { method: 'POST' }, true), error => error.status === 401)
const file = await api.apiDownload('/api/retrieval/exports', { method: 'POST' }, true)
assert.equal(file.filename, 'download.jsonl')
assert.equal(file.recordsSha256, null)
})