import assert from 'node:assert/strict'; import { readFile } from 'node:fs/promises'; import test from 'node:test'; const pageSource = async (path) => readFile(new URL(path, import.meta.url), 'utf8'); test('全局基础样式不对输入控件设置 border-box', async () => { const source = await pageSource('../src/styles/base.css'); assert.doesNotMatch(source, /view,\s*\ntext,\s*\ninput,/); assert.doesNotMatch(source, /view,\s*\ntext,\s*\ntextarea,/); assert.doesNotMatch(source, /(^|\n)input\b[\s\S]*?box-sizing:\s*border-box/m); assert.doesNotMatch(source, /(^|\n)textarea\b[\s\S]*?box-sizing:\s*border-box/m); }); test('SOP 查询框不再覆盖 textarea 的 box-sizing', async () => { const source = await pageSource('../src/pages/user/sop/index.vue'); const queryPanelStyle = source.match(/\.query-panel \.textarea \{[\s\S]*?\n\}/)?.[0] || ''; assert.equal(queryPanelStyle.includes('box-sizing'), false); }); test('员工首页地图主标题保留真实工具名称', async () => { const source = await pageSource('../src/pages/user/today/index.vue'); assert.match(source, /class="map-symbol"/); assert.match(source, /\{\{ tile\.title \}\}<\/text>/); assert.match(source, /title:\s*'问老师傅'/); assert.match(source, /title:\s*'刻意练习'/); assert.match(source, /shortTitle:\s*'问'/); }); test('训练页提交失败会回滚本次乐观追加的对话', async () => { const source = await pageSource('../src/pages/user/practice/index.vue'); assert.match(source, /const previousTurns = turns\.value\.slice\(\)/); assert.match(source, /turns\.value = previousTurns/); }); test('manifest 明确声明为 uni-app Vue3 CLI 工程', async () => { const source = await pageSource('../src/manifest.json'); assert.match(source, /"vueVersion"\s*:\s*"3"/); }); test('员工端 tabBar 继续保留四个固定入口', async () => { const source = await pageSource('../src/pages.json'); assert.match(source, /"selectedColor"\s*:\s*"#e60012"/); assert.match(source, /pages\/user\/today\/index/); assert.match(source, /pages\/user\/practice\/index/); assert.match(source, /pages\/user\/sop\/index/); assert.match(source, /pages\/user\/profile\/index/); }); test('登录页按高保真原型保留品牌结构和紧凑验证码行', async () => { const source = await pageSource('../src/pages/auth/login/index.vue'); assert.match(source, /高效协同 · 贴心服务 · 让工作更简单/); assert.match(source, /]+type="phone"/); assert.match(source, /]+type="locked"/); assert.doesNotMatch(source, /class="logo-badge"/); assert.doesNotMatch(source, /grid-template-columns:\s*1fr;[\s\S]*?\.code-button/); }); test('共享视觉基座包含员工端主色和卡片圆角 token', async () => { const source = await pageSource('../src/styles/base.css'); assert.match(source, /--employee-primary:\s*#2f6bff/); assert.match(source, /--employee-card-radius:\s*24px/); assert.match(source, /\.employee-card\s*\{/); }); test('员工端三页接入共享页面和卡片基座', async () => { const [todaySource, sopSource, practiceSource] = await Promise.all([ pageSource('../src/pages/user/today/index.vue'), pageSource('../src/pages/user/sop/index.vue'), pageSource('../src/pages/user/practice/index.vue') ]); assert.match(todaySource, /employee-page-shell/); assert.match(todaySource, /section-card employee-card/); assert.match(sopSource, /query-panel employee-card/); assert.match(practiceSource, /scenario-card employee-card/); }); test('登录后按组织身份切换主管首页', async () => { const source = await pageSource('../src/services/position.ts'); assert.match(source, /\/api\/aihr\/mobile\/me/); assert.match(source, /role === 'supervisor'/); assert.match(source, /pages\/supervisor\/index\/index/); }); test('员工首页保留师傅区、语音条、今日安排、我的地图四段结构', async () => { const source = await pageSource('../src/pages/user/today/index.vue'); assert.match(source, /mentor-hero/); assert.match(source, /voice-panel/); assert.match(source, /今日安排/); assert.match(source, /我的地图/); assert.match(source, /brand-bar/); assert.match(source, /ask-card/); assert.match(source, /小贴士/); }); test('员工首页高保真入口继续使用真实图标和业务跳转', async () => { const source = await pageSource('../src/pages/user/today/index.vue'); assert.match(source, /type="notification"/); assert.match(source, /type="chatboxes"/); assert.match(source, /type="compose"/); assert.match(source, /type="location"/); assert.match(source, /const goSop = \(\) =>/); assert.match(source, /const openPrimarySchedule = \(\) =>/); assert.match(source, /getMobileHome\('user'\)/); assert.match(source, /getPracticeAssignments\(true\)/); assert.match(source, /src="\/static\/mentor-hifi\.png"/); }); test('问师傅页保留搜索框、答案区和总结卡入口', async () => { const source = await pageSource('../src/pages/user/sop/index.vue'); assert.match(source, /query-panel/); assert.match(source, /answer-panel/); assert.match(source, /summary-panel/); }); test('训练页保留任务卡、对话区、回复区和结果区', async () => { const source = await pageSource('../src/pages/user/practice/index.vue'); assert.match(source, /scenario-card/); assert.match(source, /assignment-panel/); assert.match(source, /dialogue-card/); assert.match(source, /reply-card/); assert.match(source, /result-card/); });