import { describe, it, expect } from 'vitest';
import { agentAvatar, designTokensCss, escapeHtml, liveTimerJs, statusPill, appHeader, appHeaderCss, appHeaderOnlyCss } 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('')).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');
});
});
describe('appHeader (v2 shared header)', () => {
it('renders logo, project cell, nav links and status mounts', () => {
const h = appHeader('demo', 'team');
expect(h).toContain('/logo.svg');
expect(h).toContain('id="projectName"');
expect(h).toContain('b2-proj');
expect(h).toContain('id="newTaskBtn"');
expect(h).toContain('id="sseStatus"');
for (const path of ['/board', '/team', '/activity', '/messages', '/decisions']) {
expect(h).toContain(`href="${path}"`);
}
});
it('marks the current page active with aria-current', () => {
const team = appHeader('demo', 'team');
expect(team).toContain('active" href="/team" aria-current="page"');
const board = appHeader('demo', 'board');
expect(board).toContain('active" href="/board" aria-current="page"');
expect(board).not.toContain('active" href="/team"');
});
it('escapes the project name', () => {
expect(appHeader('x', 'board')).not.toContain('x');
});
it('appHeaderOnlyCss is a prefix of appHeaderCss', () => {
expect(appHeaderCss().startsWith(appHeaderOnlyCss())).toBe(true);
expect(appHeaderOnlyCss()).toContain('.app-header');
expect(appHeaderCss()).toContain('.modal-backdrop');
});
});