import assert from 'node:assert/strict' import { readFileSync } from 'node:fs' import test from 'node:test' import { fileURLToPath } from 'node:url' import { SESSION_TYPE_APPLICATION, SESSION_TYPE_EXPENSE, SESSION_TYPE_KNOWLEDGE, buildWelcomeInsight, buildWelcomeMessage } from '../src/views/scripts/travelReimbursementConversationModel.js' const appShellRouteView = readFileSync( fileURLToPath(new URL('../src/views/AppShellRouteView.vue', import.meta.url)), 'utf8' ) const appShellComposable = readFileSync( fileURLToPath(new URL('../src/composables/useAppShell.js', import.meta.url)), 'utf8' ) const assistantScript = readFileSync( fileURLToPath(new URL('../src/views/scripts/TravelReimbursementCreateView.js', import.meta.url)), 'utf8' ) const assistantTemplate = readFileSync( fileURLToPath(new URL('../src/views/TravelReimbursementCreateView.vue', import.meta.url)), 'utf8' ) test('application and reimbursement entries open the same financial assistant modal', () => { assert.match(appShellRouteView, / { assert.match(appShellComposable, /const SMART_ENTRY_SOURCE_APPLICATION = 'application'/) assert.match(appShellComposable, /function openExpenseApplicationCreate\(\) \{[\s\S]*openFinancialAssistantCreate\(SMART_ENTRY_SOURCE_APPLICATION\)/) assert.match(appShellComposable, /function openTravelCreate\(\) \{[\s\S]*openFinancialAssistantCreate\(SMART_ENTRY_SOURCE_REIMBURSEMENT\)/) assert.match(appShellComposable, /openExpenseApplicationCreate,/) assert.match(assistantScript, /activeSessionType\.value === SESSION_TYPE_APPLICATION[\s\S]*我想先申请一笔差旅费用/) }) test('financial assistant toolbar renders four isolated assistant sessions', () => { assert.match(assistantScript, /ASSISTANT_SESSION_MODE_OPTIONS\.map/) assert.match(assistantScript, /targetSessionType:\s*mode\.key/) assert.match(assistantScript, /active:\s*mode\.key === activeSessionType\.value/) assert.match(assistantTemplate, /:class="\{ active: shortcut\.active \}"/) assert.match(assistantTemplate, /:aria-pressed="shortcut\.active \? 'true' : 'false'"/) assert.match(assistantTemplate, /:disabled="shortcut\.active \|\| submitting/) }) test('closing a busy assistant keeps the running instance recoverable', () => { assert.match(appShellRouteView, /:reopen-token="smartEntryRevealToken"/) assert.match(appShellComposable, /const smartEntryRevealToken = ref\(0\)/) assert.match(appShellComposable, /if \(smartEntryOpen\.value\) \{\s*smartEntryRevealToken\.value \+= 1\s*return\s*\}/) assert.match(appShellComposable, /smartEntryRevealToken,/) assert.match(assistantScript, /reopenToken:\s*\{\s*type:\s*Number/) assert.match(assistantScript, /closeAfterBusy\.value = false[\s\S]*workbenchVisible\.value = true/) assert.match(assistantScript, /function emitCloseAfterLeave\(\) \{\s*if \(workbenchVisible\.value\)/) }) test('financial assistant welcome copy differentiates application intent from reimbursement entry', () => { const user = { name: '李文静', username: 'wenjing.li', grade: 'P5' } const applicationWelcome = buildWelcomeMessage('application', null, SESSION_TYPE_APPLICATION, user) const reimbursementWelcome = buildWelcomeMessage('topbar', null, SESSION_TYPE_EXPENSE, user) const knowledgeWelcome = buildWelcomeMessage('topbar', null, SESSION_TYPE_KNOWLEDGE, user) const applicationInsight = buildWelcomeInsight('application', null, SESSION_TYPE_APPLICATION, user) assert.match(applicationWelcome, /申请助手/) assert.match(applicationWelcome, /费用申请、报销申请还是其他财务事项/) assert.match(reimbursementWelcome, /报销助手/) assert.match(reimbursementWelcome, /报销发起、票据识别、草稿归集、报销信息核对/) assert.match(knowledgeWelcome, /财务知识助手/) assert.notEqual(applicationWelcome, reimbursementWelcome) assert.equal(applicationInsight.metricValue, '申请助手') assert.equal(applicationInsight.title, '申请助手') })