- Add src/server/ui-shared.ts: design tokens, agentAvatar(), statusPill(), escapeHtml(), liveTimerJs(), pageHeader(). No emojis, no deps. - Add src/server/team.ts: role hierarchy renderer (architect -> implementer/ reviewer/tester) with per-agent free/busy state derived from in-progress tasks. - Wire GET /team route in src/server/routes.ts. - Add tests/team.test.ts and tests/ui-shared.test.ts. Build: npm run build clean. Tests: 132 passed (was 122).
51 lines
1.7 KiB
TypeScript
51 lines
1.7 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
import { agentAvatar, designTokensCss, escapeHtml, liveTimerJs, statusPill } from '../src/server/ui-shared.js';
|
|
|
|
describe('ui-shared helpers', () => {
|
|
it('designTokensCss returns the dark palette variables', () => {
|
|
const css = designTokensCss();
|
|
expect(css).toContain('--bg: #0F172A');
|
|
expect(css).toContain('--status-in_progress: #58A6FF');
|
|
expect(css).toContain('prefers-reduced-motion');
|
|
});
|
|
|
|
it('agentAvatar renders initials without emojis', () => {
|
|
const html = agentAvatar('kimi');
|
|
expect(html).toContain('K');
|
|
expect(html).toContain('#7C3AED');
|
|
expect(html).not.toContain('emoji');
|
|
});
|
|
|
|
it('agentAvatar renders deterministic fallback for unknown agents', () => {
|
|
const html = agentAvatar('robo-agent-42');
|
|
expect(html).toContain('R');
|
|
expect(html).toContain('agent-avatar');
|
|
});
|
|
|
|
it('agentAvatar adds architect ring when requested', () => {
|
|
const html = agentAvatar('claude', { architectRing: true });
|
|
expect(html).toContain('box-shadow');
|
|
});
|
|
|
|
it('statusPill renders each known status', () => {
|
|
for (const status of ['open', 'in_progress', 'review', 'done', 'cancelled'] as const) {
|
|
const html = statusPill(status);
|
|
expect(html).toContain(`data-status="${status}"`);
|
|
expect(html).toContain('status-pill');
|
|
}
|
|
});
|
|
|
|
it('escapeHtml escapes dangerous characters', () => {
|
|
expect(escapeHtml('<script>alert("x")</script>')).toBe(
|
|
'<script>alert("x")</script>',
|
|
);
|
|
});
|
|
|
|
it('liveTimerJs contains the setInterval updater', () => {
|
|
const js = liveTimerJs();
|
|
expect(js).toContain('setInterval');
|
|
expect(js).toContain('data-live-timer');
|
|
expect(js).toContain('claimed');
|
|
});
|
|
});
|