| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122 |
- 'use strict';
- const assert = require('assert/strict');
- const fs = require('fs');
- const path = require('path');
- const packageRoot = path.resolve(__dirname, '..');
- const dashboardRoot = path.join(packageRoot, 'mcp', 'src', 'dashboard');
- const html = fs.readFileSync(path.join(dashboardRoot, 'index.html'), 'utf8');
- const app = fs.readFileSync(path.join(dashboardRoot, 'app.js'), 'utf8');
- const css = fs.readFileSync(path.join(dashboardRoot, 'styles.css'), 'utf8');
- const server = fs.readFileSync(path.join(dashboardRoot, 'server.js'), 'utf8');
- const agentService = fs.readFileSync(path.join(dashboardRoot, 'agent-service.js'), 'utf8');
- const checks = [];
- function check(name, fn) {
- fn();
- checks.push(name);
- }
- check('工作台资源带缓存版本', () => {
- assert.match(html, /styles\.css\?v=/);
- assert.match(html, /app\.js\?v=/);
- });
- check('客服工作台可直接进入,不先被登录页挡住', () => {
- assert.match(app, /if \(!acc && !\[\'overview\', \'agent\', \'skills\', \'knowledge\', \'customer-ops\'\]\.includes\(page\)\)/);
- });
- check('监听按钮跟 listener.running,不再跟 AI 模式绑死', () => {
- assert.match(app, /const listenerRunning = Boolean\(listener\.running\);/);
- assert.match(app, /data-agent-action="\$\{allowlistReady \? \(listenerRunning \? 'stop-listener' : 'start-listener'\) : 'manage-allowlist'\}"/);
- assert.doesNotMatch(app, /aiListenerActive/);
- });
- check('离线账号和监听失败会直接显示在工作台', () => {
- assert.match(app, /账号离线,请先扫码登录/);
- assert.match(app, /登录后可启动监听/);
- assert.match(app, /listener\.lastError && !listenerRunning/);
- assert.match(app, /<strong>监听未运行<\/strong>/);
- });
- check('启动监听前在点击处理里检查白名单,避免 allowlistReady 作用域错误', () => {
- assert.match(app, /if \(action === 'start-listener'\) \{\s*const allowlistReady = Number\(state\.agent\.status\?\.config\?\.allowedSenderCount \|\| 0\) > 0;/);
- });
- check('删除账号会请求服务端清理本地凭据', () => {
- assert.match(app, /async function removeAccount\(id\)/);
- assert.match(app, /\/api\/accounts\/remove/);
- assert.match(server, /pathname === '\/api\/accounts\/remove'/);
- assert.match(agentService, /function removeActiveAccount/);
- });
- check('席位占满时提供强制切换登录', () => {
- assert.match(app, /async function forceSwitchLogin/);
- assert.match(app, /已有登录流程进行中\|设备登录数量已达上限\|停用旧设备/);
- assert.match(app, /startLoginFlow\(\{ forceSwitch: true \}\)/);
- assert.match(app, /\/api\/logout/);
- assert.match(server, /pathname === '\/api\/logout'/);
- });
- check('免扫码失败不再自动拉起二维码,避免占死登录通道', () => {
- assert.match(app, /不再自动发起登录流程/);
- assert.match(app, /toast\('免扫码恢复失败,请在登录页手动开始登录'/);
- assert.doesNotMatch(app, /setTimeout\(\(\) => startLoginFlow\(\), 100\)/);
- });
- check('媒体不可用有独立气泡和重试按钮', () => {
- assert.match(app, /function agentMediaUnavailableHtml/);
- assert.match(app, /agent-message-media unavailable agent-media-unavailable/);
- assert.match(css, /\.agent-message-media \{/);
- assert.match(css, /\.agent-media-retry/);
- assert.match(css, /\.agent-drawer-backdrop \{/);
- assert.match(css, /\.content > \.agent-page > \* \{ animation: none; \}/);
- });
- check('全自动接管和工作台会话入口仍在', () => {
- assert.match(app, /全自动接管/);
- assert.match(app, /AGENT_SNAPSHOT_KEY/);
- assert.match(app, /\/api\/accounts\/switch/);
- assert.match(app, /voicePreview/);
- assert.match(app, /openSessionConversation/);
- });
- check('全局、会话和群聊模式切换不再弹二次确认', () => {
- assert.match(app, /const modeButton = event\.target\.closest\('\[data-agent-mode\]'\)/);
- assert.match(app, /const conversationModeButton = event\.target\.closest\('\[data-agent-conversation-mode\]'\)/);
- assert.match(app, /const groupModeButton = event\.target\.closest\('\[data-agent-group-mode\]'\)/);
- const modeHandler = app.slice(app.indexOf("const modeButton = event.target.closest('[data-agent-mode]')"), app.indexOf("const actionButton = event.target.closest('[data-agent-action]')"));
- assert.doesNotMatch(modeHandler, /confirmModal\(/);
- assert.match(app, /if \(action === 'group-approve'\)[\s\S]*confirmModal\(/);
- assert.match(app, /if \(action === 'approve'\)[\s\S]*confirmModal\(/);
- });
- check('工作台语音可合成试听并真实发送', () => {
- assert.match(app, /data-agent-action="voice-preview"/);
- assert.match(app, /data-agent-action="voice-send"/);
- assert.match(app, /\/api\/agent\/voice\/preview/);
- assert.match(app, /\/api\/agent\/conversations\/\$\{id\}\/voice-send/);
- assert.match(app, /\/api\/agent\/messages\/\$\{encodeURIComponent\(message\.id\)\}\/voice-audio/);
- assert.match(server, /pathname === '\/api\/agent\/voice\/preview'/);
- assert.match(server, /voice-send/);
- assert.match(server, /serveVoicePreviewAudio/);
- assert.match(server, /serveSentVoiceAudio/);
- assert.match(agentService, /async function previewVoice/);
- assert.match(agentService, /async function sendClonedVoice/);
- assert.match(agentService, /confirmed: input.confirmed/);
- assert.match(css, /\.agent-voice-audio/);
- });
- check('通用仓保留 token 表单,不迁入房产业务字段', () => {
- assert.match(app, /function ensureAuthTokenReady/);
- assert.match(app, /function renderAuthTokenForm/);
- assert.match(app, /match\.community \|\| match\.title/);
- assert.doesNotMatch(app, /match\.estateName/);
- assert.doesNotMatch(app, /match\.layoutName/);
- assert.doesNotMatch(app, /match\.buildingArea/);
- assert.doesNotMatch(app, /match\.featureTags/);
- });
- console.log(JSON.stringify({ status: 'ok', checks: checks.length, coverage: checks }, null, 2));
|