diff --git a/frontend-vue/tests/download-url.test.ts b/frontend-vue/tests/download-url.test.ts new file mode 100644 index 00000000..6ec2cf1d --- /dev/null +++ b/frontend-vue/tests/download-url.test.ts @@ -0,0 +1,78 @@ +import { test } from 'node:test' +import assert from 'node:assert/strict' +import { getJavaDownloadUrl } from '../src/shared/api/download-url.ts' + +/** task-215:下载 URL 格式契约(公开直链、绝对 schema、origin 补齐、user_id 附加、query 拼接)。 */ + +function setup(uid = '42', origin = 'http://localhost:5173') { + ;(globalThis as Record).window = { + localStorage: { getItem: (k: string) => (k === 'uid' ? uid : null) }, + location: { origin }, + } +} + +test('绝对 https 直链被保留并追加 user_id', () => { + setup() + const url = getJavaDownloadUrl('https://api.example.com/result/a.xlsx') + assert.ok(url.startsWith('https://api.example.com/result/a.xlsx'), url) + assert.ok(url.includes('?user_id=42'), url) +}) + +test('相对路径在 window 环境补齐 origin(schema 完整)', () => { + setup() + const url = getJavaDownloadUrl('/newApi/download/x') + assert.ok(url.startsWith('http://localhost:5173'), url) + assert.ok(url.includes('user_id=42'), url) +}) + +test('绝对 http 直链不被 origin 包裹', () => { + setup() + const url = getJavaDownloadUrl('http://cdn.example.com/result/b.xlsx') + assert.ok(url.startsWith('http://cdn.example.com/result/b.xlsx'), url) + assert.ok(!url.startsWith('http://localhost:5173'), url) +}) + +test('已带 query 的 URL 用 & 拼接 user_id', () => { + setup() + const url = getJavaDownloadUrl('https://api.example.com/result/c.xlsx?k=1') + assert.ok(url.includes('k=1&user_id=42'), url) + assert.ok(!/\?user_id=42/.test(url), '不应出现第二个 ?') +}) + +test('user_id 为当前 uid 且 URL 编码可解析', () => { + setup('42') + const url = getJavaDownloadUrl('https://api.example.com/result/d.xlsx') + const params = new URL(url).searchParams + assert.equal(params.get('user_id'), '42') +}) + +test('相对产物 query 仅含 user_id(无签名/多余参数)', () => { + setup('42') + const url = getJavaDownloadUrl('/api/result/e.xlsx') + const params = new URL(url).searchParams + const keys = [...params.keys()] + assert.deepEqual(keys, ['user_id'], url) + assert.ok(!url.includes('X-Amz-Signature'), '不应出现签名参数') +}) + +test('不含重复问号', () => { + setup() + const url = getJavaDownloadUrl('https://api.example.com/result/e.xlsx') + const questionMarks = (url.match(/\?/g) ?? []).length + assert.equal(questionMarks, 1, url) +}) + +test('返回 URL 始终带 schema(save_file 兼容)', () => { + setup() + for (const p of ['/a', 'relative', '/newApi/result/f.xlsx']) { + const url = getJavaDownloadUrl(p) + assert.ok(url.startsWith('http://') || url.startsWith('https://'), `${p} -> ${url}`) + } +}) + +test('结果稳定可复现', () => { + setup() + const a = getJavaDownloadUrl('https://api.example.com/result/g.xlsx') + const b = getJavaDownloadUrl('https://api.example.com/result/g.xlsx') + assert.equal(a, b) +})