import assert from 'node:assert/strict'; import { readFile } from 'node:fs/promises'; import { after, test } from 'node:test'; import { fileURLToPath } from 'node:url'; import { createServer } from 'vite'; const vite = await createServer({ root: fileURLToPath(new URL('..', import.meta.url)), configFile: false, optimizeDeps: { noDiscovery: true }, server: { middlewareMode: true, hmr: false }, appType: 'custom' }); const originalUni = globalThis.uni; const read = (path) => readFile(new URL(path, import.meta.url), 'utf8'); after(async () => { await vite.close(); if (originalUni === undefined) delete globalThis.uni; else globalThis.uni = originalUni; }); const [ fileSelection, speech, caseService, candidate, knowledge, personalAssistant ] = await Promise.all([ vite.ssrLoadModule('/src/utils/file-selection.ts'), vite.ssrLoadModule('/src/services/speech.ts'), vite.ssrLoadModule('/src/services/case.ts'), vite.ssrLoadModule('/src/services/candidate.ts'), vite.ssrLoadModule('/src/services/knowledge.ts'), vite.ssrLoadModule('/src/services/personal-assistant.ts') ]); const pickers = [ ['音频', speech.chooseSpeechAudio], ['音频', caseService.chooseCaseAudio], ['文件', candidate.chooseCandidateFile], ['附件', knowledge.chooseKnowledgeMedia], ['文件', personalAssistant.choosePersonalFile] ]; test('所有文件选择器把用户取消识别为同一可静默处理的信号', async () => { globalThis.uni = { chooseFile: ({ fail }) => fail({ errMsg: 'chooseFile:fail cancel' }) }; for (const [label, picker] of pickers) { await assert.rejects(picker(), (error) => { assert.equal(fileSelection.isFileSelectionCancelled(error), true); assert.equal(error.code, fileSelection.FILE_SELECTION_CANCELLED); assert.equal(error.message, `未选择${label}`); return true; }); } }); test('系统选择失败不是用户取消,并只展示稳定中文提示', async () => { globalThis.uni = { chooseFile: ({ fail }) => fail({ errMsg: 'chooseFile:fail permission denied' }) }; for (const [label, picker] of pickers) { await assert.rejects(picker(), (error) => { assert.equal(fileSelection.isFileSelectionCancelled(error), false); assert.equal(error.message, `无法选择${label},请重试`); assert.doesNotMatch(error.message, /permission|denied|chooseFile/i); return true; }); } }); test('无结构异常也不会被误判为取消', () => { const error = fileSelection.fileSelectionFailure(undefined, '附件'); assert.equal(fileSelection.isFileSelectionCancelled(error), false); assert.equal(error.message, '无法选择附件,请重试'); }); test('所有使用文件选择器的页面都按取消信号恢复空闲态而不展示错误', async () => { const pages = await Promise.all([ '../src/pages/candidate/interview/index.vue', '../src/pages/candidate/materials/index.vue', '../src/pages/user/web-ai/index.vue', '../src/pages/user/today/index.vue', '../src/pages/user/cases/index.vue', '../src/pages/user/sop/index.vue', '../src/pages/user/practice/index.vue', '../src/pages/user/report/index.vue', '../src/pages/user/assistant/capture.vue' ].map(read)); const combined = pages.join('\n'); for (const page of pages) assert.match(page, /isFileSelectionCancelled/); assert.doesNotMatch(combined, /(?:!==|===)\s*['"]未选择(?:音频|附件|文件)['"]/); assert.match(pages[0], /isFileSelectionCancelled\(error\)[\s\S]*?message\.value = ''[\s\S]*?return/); assert.match(pages[6], /isFileSelectionCancelled\(error\)[\s\S]*?message\.value = ''[\s\S]*?return/); });