diff --git a/apps/mcp-server/src/tui/components/FlowMap.spec.tsx b/apps/mcp-server/src/tui/components/FlowMap.spec.tsx index 8cab01c2..4b5ed870 100644 --- a/apps/mcp-server/src/tui/components/FlowMap.spec.tsx +++ b/apps/mcp-server/src/tui/components/FlowMap.spec.tsx @@ -143,6 +143,28 @@ describe('tui/components/FlowMap', () => { expect(frame).toContain(formatElapsed(now - 90_000, now)); }); + it('should show pulse icon and elapsed label for running agents in medium mode', () => { + const now = 1710700000000; + const agents = new Map(); + agents.set( + 'a1', + createDefaultDashboardNode({ + id: 'a1', + name: 'Architect', + stage: 'PLAN', + status: 'running', + isPrimary: true, + startedAt: now - 120_000, // 2 minutes ago + }), + ); + const { lastFrame } = render( + , + ); + const frame = lastFrame() ?? ''; + expect(frame).toContain(pulseIcon(1)); + expect(frame).toContain(formatElapsed(now - 120_000, now)); + }); + it('should NOT show pulse icon when no agents are running', () => { const now = 1710700000000; const agents = new Map(); diff --git a/apps/mcp-server/src/tui/components/FocusedAgentPanel.spec.tsx b/apps/mcp-server/src/tui/components/FocusedAgentPanel.spec.tsx index 2ef5e694..2142c2ee 100644 --- a/apps/mcp-server/src/tui/components/FocusedAgentPanel.spec.tsx +++ b/apps/mcp-server/src/tui/components/FocusedAgentPanel.spec.tsx @@ -210,6 +210,30 @@ describe('tui/components/FocusedAgentPanel', () => { expect(frame).not.toContain('1m 23s'); }); + it('should show spinner but hide elapsed when tick is provided without now', () => { + const runningAgent = createDefaultDashboardNode({ + id: 'agent-1', + name: 'BackendDev', + stage: 'ACT', + status: 'running', + isPrimary: true, + progress: 50, + startedAt: 1710000000000, + }); + const { lastFrame } = render( + , + ); + const frame = lastFrame() ?? ''; + expect(frame).toContain('⠋'); // spinner shown + expect(frame).not.toMatch(/\d+m \d+s/); // no elapsed time + }); + it('should not show elapsed when startedAt is missing', () => { const now = 1710000090000; const { lastFrame } = render( diff --git a/apps/mcp-server/src/tui/hooks/use-tick.spec.tsx b/apps/mcp-server/src/tui/hooks/use-tick.spec.tsx index 85ef9cd3..56134191 100644 --- a/apps/mcp-server/src/tui/hooks/use-tick.spec.tsx +++ b/apps/mcp-server/src/tui/hooks/use-tick.spec.tsx @@ -54,6 +54,24 @@ describe('tui/hooks/useTick', () => { expect(lastFrame()).toBe('2'); }); + it('should reset interval when intervalMs prop changes', () => { + const clearIntervalSpy = vi.spyOn(global, 'clearInterval'); + const { lastFrame, rerender } = render(); + act(() => { + vi.advanceTimersByTime(1000); + }); + expect(lastFrame()).toBe('1'); + + rerender(); + expect(clearIntervalSpy).toHaveBeenCalled(); + + act(() => { + vi.advanceTimersByTime(500); + }); + expect(lastFrame()).toBe('2'); + clearIntervalSpy.mockRestore(); + }); + it('should cleanup interval on unmount', () => { const clearIntervalSpy = vi.spyOn(global, 'clearInterval'); const { unmount } = render();