Files
gstack/test/lib-sync-show.test.ts
T
Garry Tan 87cb769c35 feat: sync heartbeats, eval:trend --team, setup guide, 10 new tests
- 005_sync_heartbeats.sql migration for connectivity testing
- eval:trend --team flag pulls team eval data (graceful fallback)
- docs/TEAM_SYNC_SETUP.md step-by-step setup guide
- Design doc status updated to Phase 2 complete
- 10 new tests for sync show formatting functions

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 19:43:03 -05:00

109 lines
3.5 KiB
TypeScript

/**
* Tests for sync show formatting functions (pure, no network).
*/
import { describe, test, expect } from 'bun:test';
import { formatTeamSummary, formatEvalTable, formatShipTable, formatRelativeTime } from '../lib/cli-sync';
describe('formatRelativeTime', () => {
test('returns "just now" for recent timestamps', () => {
expect(formatRelativeTime(new Date().toISOString())).toBe('just now');
});
test('returns minutes for recent past', () => {
const fiveMinAgo = new Date(Date.now() - 5 * 60_000).toISOString();
expect(formatRelativeTime(fiveMinAgo)).toBe('5m ago');
});
test('returns hours for older past', () => {
const threeHoursAgo = new Date(Date.now() - 3 * 3_600_000).toISOString();
expect(formatRelativeTime(threeHoursAgo)).toBe('3h ago');
});
test('returns days for old past', () => {
const twoDaysAgo = new Date(Date.now() - 2 * 86_400_000).toISOString();
expect(formatRelativeTime(twoDaysAgo)).toBe('2d ago');
});
});
describe('formatTeamSummary', () => {
test('formats summary with data', () => {
const output = formatTeamSummary({
teamSlug: 'test-team',
evalRuns: [
{ timestamp: new Date().toISOString(), user_id: 'u1', tests: [{ detection_rate: 4 }] },
{ timestamp: new Date().toISOString(), user_id: 'u2', tests: [{ detection_rate: 5 }] },
],
shipLogs: [
{ created_at: new Date().toISOString() },
],
retroSnapshots: [
{ date: '2026-03-15', streak_days: 47 },
],
queueSize: 0,
cacheLastPull: new Date().toISOString(),
});
expect(output).toContain('test-team');
expect(output).toContain('2 runs');
expect(output).toContain('2 contributors');
expect(output).toContain('1 PRs');
expect(output).toContain('4.5'); // avg detection
expect(output).toContain('streak: 47d');
expect(output).toContain('0 items');
});
test('handles empty data gracefully', () => {
const output = formatTeamSummary({
teamSlug: 'empty-team',
evalRuns: [],
shipLogs: [],
retroSnapshots: [],
queueSize: 3,
cacheLastPull: null,
});
expect(output).toContain('empty-team');
expect(output).toContain('0 runs');
expect(output).toContain('0 PRs');
expect(output).toContain('3 items');
expect(output).toContain('never');
});
});
describe('formatEvalTable', () => {
test('formats eval runs as table', () => {
const output = formatEvalTable([
{ timestamp: '2026-03-15T12:00:00Z', branch: 'main', passed: 10, total_tests: 10, total_cost_usd: 2.50, tier: 'e2e' },
]);
expect(output).toContain('Recent Eval Runs');
expect(output).toContain('2026-03-15');
expect(output).toContain('main');
expect(output).toContain('10/10');
expect(output).toContain('$2.50');
expect(output).toContain('e2e');
});
test('returns message for empty data', () => {
expect(formatEvalTable([])).toContain('No eval runs yet');
});
});
describe('formatShipTable', () => {
test('formats ship logs as table', () => {
const output = formatShipTable([
{ created_at: '2026-03-15T12:00:00Z', version: '0.3.10', branch: 'feature/sync', pr_url: 'https://github.com/org/repo/pull/1' },
]);
expect(output).toContain('Recent Ship Logs');
expect(output).toContain('0.3.10');
expect(output).toContain('feature/sync');
expect(output).toContain('github.com');
});
test('returns message for empty data', () => {
expect(formatShipTable([])).toContain('No ship logs yet');
});
});