Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apps/mcp-server/src/tui/components/HeaderBar.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { describe, it, expect } from 'vitest';
import { render } from 'ink-testing-library';
import { HeaderBar } from './HeaderBar';

const FIXED_NOW = new Date('2026-03-18T14:30:45Z').getTime();
const FIXED_NOW = new Date(2026, 2, 18, 14, 30, 45).getTime(); // local 14:30:45

describe('tui/components/HeaderBar', () => {
it('should render title with neon branding', () => {
Expand Down
30 changes: 19 additions & 11 deletions apps/mcp-server/src/tui/components/live.pure.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ describe('tui/components/live.pure', () => {
const now = start + 725_000; // 12분 5초
expect(formatElapsed(start, now)).toBe('12m 5s');
});

it('startedAt > now (clock drift) → "0s"로 클램프', () => {
const now = 1000000;
expect(formatElapsed(now + 5000, now)).toBe('0s');
});
});

describe('formatRelativeTime', () => {
Expand Down Expand Up @@ -68,6 +73,11 @@ describe('tui/components/live.pure', () => {
expect(formatRelativeTime(now - 3600000, now)).toBe('1h ago');
expect(formatRelativeTime(now - 7200000, now)).toBe('2h ago');
});

it('timestamp > now (clock drift) → "just now"로 클램프', () => {
const now = 1000000;
expect(formatRelativeTime(now + 5000, now)).toBe('just now');
});
});

describe('spinnerFrame', () => {
Expand Down Expand Up @@ -177,21 +187,19 @@ describe('tui/components/live.pure', () => {
});

describe('formatTimeWithSeconds', () => {
it('자정 → "00:00:00"', () => {
// 2026-01-01T00:00:00Z = 1767225600000
const midnight = new Date('2026-01-01T00:00:00Z').getTime();
// UTC 기준
expect(formatTimeWithSeconds(midnight)).toBe('00:00:00');
it('로컬 시간 기준으로 HH:MM:SS 형식 반환', () => {
const d = new Date(2026, 0, 1, 14, 23, 45); // local 14:23:45
expect(formatTimeWithSeconds(d.getTime())).toBe('14:23:45');
});

it('오후 시간 → "14:23:45"', () => {
const t = new Date('2026-01-01T14:23:45Z').getTime();
expect(formatTimeWithSeconds(t)).toBe('14:23:45');
it('한 자리 시/분/초 → 0으로 패딩', () => {
const d = new Date(2026, 0, 1, 3, 5, 9); // local 03:05:09
expect(formatTimeWithSeconds(d.getTime())).toBe('03:05:09');
});

it('한 자리 시/분/초 → 0으로 패딩', () => {
const t = new Date('2026-01-01T03:05:09Z').getTime();
expect(formatTimeWithSeconds(t)).toBe('03:05:09');
it('자정 → "00:00:00"', () => {
const d = new Date(2026, 0, 1, 0, 0, 0); // local midnight
expect(formatTimeWithSeconds(d.getTime())).toBe('00:00:00');
});
});
});
12 changes: 6 additions & 6 deletions apps/mcp-server/src/tui/components/live.pure.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ export interface ActivitySample {

/** Format elapsed time as "Xm Ys" or "Ys". */
export function formatElapsed(startedAt: number, now: number): string {
const totalSec = Math.floor((now - startedAt) / 1000);
const totalSec = Math.max(0, Math.floor((now - startedAt) / 1000));
const min = Math.floor(totalSec / 60);
const sec = totalSec % 60;
return min > 0 ? `${min}m ${sec}s` : `${sec}s`;
}

/** Format relative time as "just now", "Ns ago", "Nm ago", "Nh ago". */
export function formatRelativeTime(timestamp: number, now: number): string {
const diffSec = Math.floor((now - timestamp) / 1000);
const diffSec = Math.max(0, Math.floor((now - timestamp) / 1000));
if (diffSec <= 2) return 'just now';
if (diffSec < 60) return `${diffSec}s ago`;
const diffMin = Math.floor(diffSec / 60);
Expand Down Expand Up @@ -63,11 +63,11 @@ export function computeThroughput(samples: ActivitySample[]): string {
return `${(totalCalls / durationMin).toFixed(1)}/min`;
}

/** Format a UTC timestamp as "HH:MM:SS". */
/** Format a timestamp as local "HH:MM:SS". */
export function formatTimeWithSeconds(now: number): string {
const d = new Date(now);
const h = String(d.getUTCHours()).padStart(2, '0');
const m = String(d.getUTCMinutes()).padStart(2, '0');
const s = String(d.getUTCSeconds()).padStart(2, '0');
const h = String(d.getHours()).padStart(2, '0');
const m = String(d.getMinutes()).padStart(2, '0');
const s = String(d.getSeconds()).padStart(2, '0');
return `${h}:${m}:${s}`;
}
Loading