// Copyright (c) 2026 Gordon Bolton. MIT License. /** * @vitest-environment jsdom * Tests for client/src/utils/format.js * * Verifies formatting utilities for sizes, speeds, dates, and HTML escaping. * These are pure functions that handle edge cases like null, zero, and large numbers. */ import { formatSize, formatSpeed, formatDate, formatTimeAgo, escapeHtml } from '../../../client/src/utils/format.js'; describe('formatSize', () => { it('returns N/A for null/undefined', () => { expect(formatSize(null)).toBe('N/A'); expect(formatSize(undefined)).toBe('N/A'); }); it('returns string as-is when already formatted', () => { expect(formatSize('21.5 GB')).toBe('21.5 GB'); }); it('formats bytes correctly', () => { expect(formatSize(512)).toBe('512 B'); }); it('formats kilobytes correctly', () => { expect(formatSize(1024)).toBe('1 KB'); }); it('formats megabytes correctly', () => { expect(formatSize(1024 * 1024)).toBe('1 MB'); }); it('formats gigabytes correctly', () => { expect(formatSize(1024 * 1024 * 1024)).toBe('1 GB'); }); it('handles zero', () => { expect(formatSize(0)).toBe('N/A'); }); }); describe('formatSpeed', () => { it('returns 0 B/s for zero', () => { expect(formatSpeed(0)).toBe('0 B/s'); }); it('returns 0 B/s for null/undefined', () => { expect(formatSpeed(null)).toBe('0 B/s'); expect(formatSpeed(undefined)).toBe('0 B/s'); }); it('formats bytes per second correctly', () => { expect(formatSpeed(512)).toBe('512.00 B/s'); }); it('formats kilobytes per second correctly', () => { expect(formatSpeed(1024)).toBe('1.00 KB/s'); }); it('formats megabytes per second correctly', () => { expect(formatSpeed(1024 * 1024)).toBe('1.00 MB/s'); }); it('handles large numbers', () => { expect(formatSpeed(1024 * 1024 * 1024)).toBe('1.00 GB/s'); }); }); describe('formatDate', () => { it('returns N/A for null/undefined', () => { expect(formatDate(null)).toBe('N/A'); expect(formatDate(undefined)).toBe('N/A'); }); it('formats valid date string', () => { const dateStr = '2024-01-15T10:30:00Z'; const result = formatDate(dateStr); expect(result).toBeTruthy(); expect(result).not.toBe('N/A'); }); }); describe('formatTimeAgo', () => { it('returns Never for null/undefined', () => { expect(formatTimeAgo(null)).toBe('Never'); expect(formatTimeAgo(undefined)).toBe('Never'); }); it('returns seconds ago for recent timestamps', () => { const now = Date.now(); expect(formatTimeAgo(now - 30000)).toBe('30s ago'); }); it('returns minutes ago for older timestamps', () => { const now = Date.now(); expect(formatTimeAgo(now - 60000 * 5)).toBe('5m ago'); }); it('returns hours ago for hours-old timestamps', () => { const now = Date.now(); expect(formatTimeAgo(now - 60000 * 60 * 3)).toBe('3h ago'); }); it('returns days ago for day-old timestamps', () => { const now = Date.now(); expect(formatTimeAgo(now - 60000 * 60 * 24 * 2)).toBe('2d ago'); }); }); describe('escapeHtml', () => { it('escapes HTML special characters', () => { expect(escapeHtml('')).toBe('<script>alert("xss")</script>'); }); it('escapes quotes', () => { expect(escapeHtml('"test"')).toBe('"test"'); }); it('handles empty string', () => { expect(escapeHtml('')).toBe(''); }); it('handles normal text without special chars', () => { expect(escapeHtml('normal text')).toBe('normal text'); }); });