| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091 |
- const assert = require('assert/strict');
- const fs = require('fs');
- const path = require('path');
- const root = path.resolve(__dirname, '..');
- const app = fs.readFileSync(path.join(root, 'mcp', 'src', 'dashboard', 'app.js'), 'utf8');
- const styles = fs.readFileSync(path.join(root, 'mcp', 'src', 'dashboard', 'styles.css'), 'utf8');
- const results = [];
- function check(name, fn) {
- fn();
- results.push({ name, status: 'passed' });
- }
- function functionSource(name, nextName) {
- const start = app.indexOf(`function ${name}`);
- const end = app.indexOf(`function ${nextName}`, start + 1);
- assert.ok(start >= 0 && end > start, `missing function source: ${name}`);
- return app.slice(start, end);
- }
- check('active Agent view uses a compact command bar and drawers', () => {
- const source = functionSource('renderAgentWorkspaceV2', 'responseMonitorRenderSignature');
- assert.match(source, /agent-commandbar/);
- assert.match(source, /agent-drawer settings/);
- assert.match(source, /agent-drawer reminders/);
- assert.doesNotMatch(source, /agent-hero|agent-modebar/);
- });
- check('skills workspace does not receive Agent-only drawers', () => {
- const source = functionSource('renderSkillsWorkspace', 'renderSkillsPage');
- assert.doesNotMatch(source, /agent-drawer|renderAgentIntakeSettings|renderResponseMonitor/);
- });
- check('workspace reserves viewport height and internal scrolling', () => {
- assert.match(styles, /\.agent-page\s*\{[\s\S]*?height:\s*calc\(100dvh\s*-\s*144px\)/);
- assert.match(styles, /\.agent-workspace\s*\{[\s\S]*?min-height:\s*0;[\s\S]*?overflow:\s*hidden;/);
- assert.match(styles, /\.agent-list-scroll\s*\{[^}]*overflow-y:\s*auto;/);
- assert.match(styles, /\.agent-message-stream\s*\{[\s\S]*?overflow-y:\s*auto;/);
- assert.match(styles, /\.agent-insight-panel\s*\{[\s\S]*?overflow-y:\s*auto;/);
- });
- check('short desktop viewports keep the chat column bounded and usable', () => {
- assert.match(styles, /\.agent-chat-panel\s*>\s*\*\s*\{\s*min-width:\s*0;/);
- assert.match(styles, /@media\s*\(min-width:\s*761px\)\s*and\s*\(max-height:\s*760px\)/);
- assert.match(styles, /\.agent-composer-actions\s*\{\s*align-items:\s*stretch;\s*flex-direction:\s*column;/);
- assert.match(styles, /\.agent-review-actions\s*\{\s*flex-wrap:\s*nowrap;/);
- });
- check('mobile layout is bounded and keeps controls reachable', () => {
- const mobile = styles.slice(styles.indexOf('@media (max-width: 760px)'));
- assert.match(mobile, /\.agent-workspace\s*\{[^}]*grid-template-columns:\s*1fr;/);
- assert.match(mobile, /\.agent-command-actions\s*\{[^}]*overflow-x:\s*auto;/);
- assert.match(mobile, /\.agent-drawer\s*\{[^}]*width:\s*100vw;/);
- assert.match(mobile, /\.agent-chat-panel\s*\{[^}]*min-height:\s*720px;[^}]*minmax\(160px,\s*1fr\)/);
- assert.match(styles, /\.page\.agent-page\s*\{\s*animation:\s*none;\s*transform:\s*none;/);
- });
- check('conversation ordering has explicit invalid-time and stable-tie behavior', () => {
- assert.match(app, /Number\.NEGATIVE_INFINITY/);
- assert.match(app, /b\.timestamp\s*-\s*a\.timestamp\s*\|\|\s*a\.index\s*-\s*b\.index/);
- assert.match(app, /sortAgentItemsByLatest\(conversations\.filter/);
- });
- check('activity timeline uses existing trace and audit without raw JSON rendering', () => {
- const source = functionSource('renderAgentActivityTimeline', 'scrollAgentMessagesToLatest');
- assert.match(source, /Plan/);
- assert.match(source, /Act/);
- assert.match(source, /Observe/);
- assert.match(source, /Evaluate/);
- assert.doesNotMatch(source, /JSON\.stringify/);
- assert.doesNotMatch(app, /JSON\.stringify\(viewModel\.toolTrace\[0\]/);
- });
- check('Agent theme is semantic and tenant-overridable', () => {
- for (const token of ['brand', 'page-bg', 'panel', 'ink', 'line', 'focus', 'success', 'warning', 'error']) {
- assert.match(styles, new RegExp(`--agent-${token}:`));
- }
- assert.match(styles, /\.agent-page\[data-theme="xiaoniu"\]/);
- assert.match(app, /page\.dataset\.theme/);
- });
- check('intake settings use the fixed API contract and explicit confirmation', () => {
- assert.match(app, /\/api\/agent\/intake-policy/);
- assert.match(app, /welcomeEnabled/);
- assert.match(app, /welcomeText/);
- assert.match(app, /welcomeSendMode/);
- assert.match(app, /ENABLE_AUTO_ENROLL_AUTOPILOT/);
- });
- console.log(JSON.stringify({ status: 'ok', passed: results.length, results }, null, 2));
|