Files
certctl/web/src/api/utils.test.ts
T
shankar0123 73c6bd1416 feat: add frontend action buttons, fix notification auth bug, add 53 Vitest tests
Bug fix:
- markNotificationRead was using raw fetch() without auth headers,
  bypassing the shared client's Authorization header. Moved to
  api/client.ts to use fetchJSON with proper auth.

New action buttons:
- CertificatesPage: "New Certificate" modal with form fields
- CertificateDetailPage: "Deploy" button with target selector modal,
  "Archive" button with confirmation
- IssuersPage: "Test Connection" and "Delete" per-row actions
- TargetsPage: "Delete" per-row action
- PoliciesPage: "Enable/Disable" toggle and "Delete" per-row actions

New API client functions:
- updateCertificate, archiveCertificate, registerAgent,
  createPolicy, updatePolicy, deletePolicy, getPolicyViolations,
  createIssuer, testIssuerConnection, deleteIssuer,
  createTarget, deleteTarget, markNotificationRead

Frontend tests (53 tests, 2 files):
- client.test.ts: 35 tests covering all API endpoints, auth headers,
  401 handling, error parsing, HTTP methods, request bodies
- utils.test.ts: 18 tests covering formatDate, formatDateTime,
  timeAgo, daysUntil, expiryColor

CI: Added "Run Frontend Tests" step to frontend-build job

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 00:05:21 -04:00

111 lines
2.9 KiB
TypeScript

import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import { formatDate, formatDateTime, timeAgo, daysUntil, expiryColor } from './utils';
describe('Utility functions', () => {
describe('formatDate', () => {
it('returns dash for empty string', () => {
expect(formatDate('')).toBe('—');
});
it('formats ISO date string', () => {
const result = formatDate('2026-06-15T12:00:00Z');
expect(result).toContain('Jun');
expect(result).toContain('15');
expect(result).toContain('2026');
});
});
describe('formatDateTime', () => {
it('returns dash for empty string', () => {
expect(formatDateTime('')).toBe('—');
});
it('formats ISO datetime string with time', () => {
const result = formatDateTime('2026-06-15T14:30:00Z');
expect(result).toContain('Jun');
expect(result).toContain('15');
});
});
describe('timeAgo', () => {
beforeEach(() => {
vi.useFakeTimers();
vi.setSystemTime(new Date('2026-03-15T12:00:00Z'));
});
afterEach(() => {
vi.useRealTimers();
});
it('returns dash for empty string', () => {
expect(timeAgo('')).toBe('—');
});
it('returns "just now" for recent times', () => {
expect(timeAgo('2026-03-15T11:59:45Z')).toBe('just now');
});
it('returns minutes ago', () => {
expect(timeAgo('2026-03-15T11:45:00Z')).toBe('15m ago');
});
it('returns hours ago', () => {
expect(timeAgo('2026-03-15T09:00:00Z')).toBe('3h ago');
});
it('returns days ago', () => {
expect(timeAgo('2026-03-12T12:00:00Z')).toBe('3d ago');
});
it('returns formatted date for old dates', () => {
const result = timeAgo('2025-01-15T12:00:00Z');
expect(result).toContain('2025');
});
});
describe('daysUntil', () => {
beforeEach(() => {
vi.useFakeTimers();
vi.setSystemTime(new Date('2026-03-15T12:00:00Z'));
});
afterEach(() => {
vi.useRealTimers();
});
it('returns 0 for empty string', () => {
expect(daysUntil('')).toBe(0);
});
it('returns positive days for future date', () => {
expect(daysUntil('2026-03-25T12:00:00Z')).toBe(10);
});
it('returns negative days for past date', () => {
expect(daysUntil('2026-03-10T12:00:00Z')).toBeLessThan(0);
});
});
describe('expiryColor', () => {
it('returns red for expired (0 days)', () => {
expect(expiryColor(0)).toContain('red');
});
it('returns red for <= 7 days', () => {
expect(expiryColor(5)).toContain('red');
});
it('returns amber for <= 14 days', () => {
expect(expiryColor(12)).toContain('amber');
});
it('returns amber for <= 30 days', () => {
expect(expiryColor(25)).toContain('amber');
});
it('returns green for > 30 days', () => {
expect(expiryColor(60)).toContain('emerald');
});
});
});