formatter tests
Some checks failed
CI / lint-typecheck (push) Failing after 4m52s
CI / tests (push) Has been skipped
CI / contract-tests (push) Has been skipped
CI / e2e-tests (push) Has been skipped
CI / comment-pr (push) Has been skipped
CI / commit-types (push) Has been skipped

This commit is contained in:
2026-01-25 11:17:47 +01:00
parent ecd22432c7
commit 3db2209d2a
42 changed files with 2743 additions and 0 deletions

View File

@@ -0,0 +1,80 @@
import { describe, it, expect } from 'vitest';
import { AchievementFormatter } from './AchievementFormatter';
describe('AchievementFormatter', () => {
describe('getRarityVariant', () => {
it('should format common rarity correctly', () => {
const result = AchievementFormatter.getRarityVariant('common');
expect(result).toEqual({
text: 'low',
surface: 'rarity-common',
iconIntent: 'low',
});
});
it('should format rare rarity correctly', () => {
const result = AchievementFormatter.getRarityVariant('rare');
expect(result).toEqual({
text: 'primary',
surface: 'rarity-rare',
iconIntent: 'primary',
});
});
it('should format epic rarity correctly', () => {
const result = AchievementFormatter.getRarityVariant('epic');
expect(result).toEqual({
text: 'primary',
surface: 'rarity-epic',
iconIntent: 'primary',
});
});
it('should format legendary rarity correctly', () => {
const result = AchievementFormatter.getRarityVariant('legendary');
expect(result).toEqual({
text: 'warning',
surface: 'rarity-legendary',
iconIntent: 'warning',
});
});
it('should handle case-insensitive rarity', () => {
const result = AchievementFormatter.getRarityVariant('COMMON');
expect(result).toEqual({
text: 'low',
surface: 'rarity-common',
iconIntent: 'low',
});
});
it('should default to common for unknown rarity', () => {
const result = AchievementFormatter.getRarityVariant('unknown');
expect(result).toEqual({
text: 'low',
surface: 'rarity-common',
iconIntent: 'low',
});
});
});
describe('formatDate', () => {
it('should format date correctly', () => {
const date = new Date('2026-01-15');
const result = AchievementFormatter.formatDate(date);
expect(result).toBe('Jan 15, 2026');
});
it('should format date with different months', () => {
const date = new Date('2026-12-25');
const result = AchievementFormatter.formatDate(date);
expect(result).toBe('Dec 25, 2026');
});
it('should handle single digit days', () => {
const date = new Date('2026-01-05');
const result = AchievementFormatter.formatDate(date);
expect(result).toBe('Jan 5, 2026');
});
});
});

View File

@@ -0,0 +1,44 @@
import { describe, it, expect } from 'vitest';
import { ActivityLevelFormatter } from './ActivityLevelFormatter';
describe('ActivityLevelFormatter', () => {
describe('levelLabel', () => {
it('should return "Low" for engagement rate below 20', () => {
expect(ActivityLevelFormatter.levelLabel(0)).toBe('Low');
expect(ActivityLevelFormatter.levelLabel(10)).toBe('Low');
expect(ActivityLevelFormatter.levelLabel(19.9)).toBe('Low');
});
it('should return "Medium" for engagement rate between 20 and 50', () => {
expect(ActivityLevelFormatter.levelLabel(20)).toBe('Medium');
expect(ActivityLevelFormatter.levelLabel(35)).toBe('Medium');
expect(ActivityLevelFormatter.levelLabel(49.9)).toBe('Medium');
});
it('should return "High" for engagement rate 50 or above', () => {
expect(ActivityLevelFormatter.levelLabel(50)).toBe('High');
expect(ActivityLevelFormatter.levelLabel(75)).toBe('High');
expect(ActivityLevelFormatter.levelLabel(100)).toBe('High');
});
});
describe('levelValue', () => {
it('should return "low" for engagement rate below 20', () => {
expect(ActivityLevelFormatter.levelValue(0)).toBe('low');
expect(ActivityLevelFormatter.levelValue(10)).toBe('low');
expect(ActivityLevelFormatter.levelValue(19.9)).toBe('low');
});
it('should return "medium" for engagement rate between 20 and 50', () => {
expect(ActivityLevelFormatter.levelValue(20)).toBe('medium');
expect(ActivityLevelFormatter.levelValue(35)).toBe('medium');
expect(ActivityLevelFormatter.levelValue(49.9)).toBe('medium');
});
it('should return "high" for engagement rate 50 or above', () => {
expect(ActivityLevelFormatter.levelValue(50)).toBe('high');
expect(ActivityLevelFormatter.levelValue(75)).toBe('high');
expect(ActivityLevelFormatter.levelValue(100)).toBe('high');
});
});
});

View File

@@ -0,0 +1,75 @@
import { describe, it, expect } from 'vitest';
import { AvatarFormatter } from './AvatarFormatter';
describe('AvatarFormatter', () => {
describe('bufferToBase64', () => {
it('should convert ArrayBuffer to base64 string', () => {
const buffer = new ArrayBuffer(3);
const view = new Uint8Array(buffer);
view[0] = 72; // 'H'
view[1] = 101; // 'e'
view[2] = 108; // 'l'
const result = AvatarFormatter.bufferToBase64(buffer);
expect(result).toBe('SGVs');
});
it('should handle empty buffer', () => {
const buffer = new ArrayBuffer(0);
const result = AvatarFormatter.bufferToBase64(buffer);
expect(result).toBe('');
});
it('should handle buffer with special characters', () => {
const buffer = new ArrayBuffer(4);
const view = new Uint8Array(buffer);
view[0] = 255; // ÿ
view[1] = 254; // Þ
view[2] = 253; // Ý
view[3] = 252; // Ü
const result = AvatarFormatter.bufferToBase64(buffer);
expect(result).toBe('/v7+/v4=');
});
});
describe('hasValidData', () => {
it('should return true for valid buffer and content type', () => {
expect(AvatarFormatter.hasValidData('base64data', 'image/png')).toBe(true);
});
it('should return false for empty buffer', () => {
expect(AvatarFormatter.hasValidData('', 'image/png')).toBe(false);
});
it('should return false for empty content type', () => {
expect(AvatarFormatter.hasValidData('base64data', '')).toBe(false);
});
it('should return false for both empty', () => {
expect(AvatarFormatter.hasValidData('', '')).toBe(false);
});
});
describe('formatContentType', () => {
it('should format image/png to PNG', () => {
expect(AvatarFormatter.formatContentType('image/png')).toBe('PNG');
});
it('should format image/jpeg to JPEG', () => {
expect(AvatarFormatter.formatContentType('image/jpeg')).toBe('JPEG');
});
it('should format image/gif to GIF', () => {
expect(AvatarFormatter.formatContentType('image/gif')).toBe('GIF');
});
it('should handle content type without slash', () => {
expect(AvatarFormatter.formatContentType('png')).toBe('png');
});
it('should handle content type with multiple slashes', () => {
expect(AvatarFormatter.formatContentType('image/png/test')).toBe('PNG');
});
});
});

View File

@@ -0,0 +1,65 @@
import { describe, it, expect } from 'vitest';
import { CountryFlagFormatter } from './CountryFlagFormatter';
describe('CountryFlagFormatter', () => {
describe('fromCountryCode', () => {
it('should return flag emoji for valid 2-letter country code', () => {
const formatter = CountryFlagFormatter.fromCountryCode('US');
expect(formatter.toString()).toBe('🇺🇸');
});
it('should handle lowercase country codes', () => {
const formatter = CountryFlagFormatter.fromCountryCode('us');
expect(formatter.toString()).toBe('🇺🇸');
});
it('should return default flag for null', () => {
const formatter = CountryFlagFormatter.fromCountryCode(null);
expect(formatter.toString()).toBe('🏁');
});
it('should return default flag for undefined', () => {
const formatter = CountryFlagFormatter.fromCountryCode(undefined);
expect(formatter.toString()).toBe('🏁');
});
it('should return default flag for empty string', () => {
const formatter = CountryFlagFormatter.fromCountryCode('');
expect(formatter.toString()).toBe('🏁');
});
it('should return default flag for invalid length code', () => {
const formatter = CountryFlagFormatter.fromCountryCode('USA');
expect(formatter.toString()).toBe('🏁');
});
it('should return default flag for single character code', () => {
const formatter = CountryFlagFormatter.fromCountryCode('U');
expect(formatter.toString()).toBe('🏁');
});
it('should handle various country codes', () => {
expect(CountryFlagFormatter.fromCountryCode('GB').toString()).toBe('🇬🇧');
expect(CountryFlagFormatter.fromCountryCode('DE').toString()).toBe('🇩🇪');
expect(CountryFlagFormatter.fromCountryCode('FR').toString()).toBe('🇫🇷');
expect(CountryFlagFormatter.fromCountryCode('IT').toString()).toBe('🇮🇹');
expect(CountryFlagFormatter.fromCountryCode('ES').toString()).toBe('🇪🇸');
expect(CountryFlagFormatter.fromCountryCode('JP').toString()).toBe('🇯🇵');
expect(CountryFlagFormatter.fromCountryCode('AU').toString()).toBe('🇦🇺');
expect(CountryFlagFormatter.fromCountryCode('CA').toString()).toBe('🇨🇦');
expect(CountryFlagFormatter.fromCountryCode('BR').toString()).toBe('🇧🇷');
});
});
describe('toString', () => {
it('should return the flag emoji', () => {
const formatter = CountryFlagFormatter.fromCountryCode('US');
expect(formatter.toString()).toBe('🇺🇸');
});
it('should return the default flag for invalid codes', () => {
const formatter = CountryFlagFormatter.fromCountryCode('XX');
expect(formatter.toString()).toBe('🏁');
});
});
});

View File

@@ -0,0 +1,76 @@
import { describe, it, expect } from 'vitest';
import { CurrencyFormatter } from './CurrencyFormatter';
describe('CurrencyFormatter', () => {
describe('format', () => {
it('should format USD with dollar sign and commas', () => {
expect(CurrencyFormatter.format(1234.56, 'USD')).toBe('$1,234.56');
expect(CurrencyFormatter.format(1000000, 'USD')).toBe('$1,000,000.00');
});
it('should format EUR with euro sign and dots as thousands separator', () => {
expect(CurrencyFormatter.format(1234.56, 'EUR')).toBe('€1.234,56');
expect(CurrencyFormatter.format(1000000, 'EUR')).toBe('€1.000.000,00');
});
it('should format with custom currency symbol', () => {
expect(CurrencyFormatter.format(1234.56, 'GBP')).toBe('GBP 1,234.56');
expect(CurrencyFormatter.format(1234.56, 'JPY')).toBe('JPY 1,234.56');
});
it('should use USD as default currency', () => {
expect(CurrencyFormatter.format(1234.56)).toBe('$1,234.56');
});
it('should handle zero amount', () => {
expect(CurrencyFormatter.format(0, 'USD')).toBe('$0.00');
expect(CurrencyFormatter.format(0, 'EUR')).toBe('€0,00');
});
it('should handle negative amounts', () => {
expect(CurrencyFormatter.format(-1234.56, 'USD')).toBe('$-1,234.56');
expect(CurrencyFormatter.format(-1234.56, 'EUR')).toBe('€-1.234,56');
});
it('should handle amounts with many decimal places', () => {
expect(CurrencyFormatter.format(1234.5678, 'USD')).toBe('$1,234.57');
expect(CurrencyFormatter.format(1234.5678, 'EUR')).toBe('€1.234,57');
});
});
describe('formatCompact', () => {
it('should format USD with dollar sign and no decimals', () => {
expect(CurrencyFormatter.formatCompact(1234.56, 'USD')).toBe('$1,235');
expect(CurrencyFormatter.formatCompact(1000000, 'USD')).toBe('$1,000,000');
});
it('should format EUR with euro sign and dots as thousands separator', () => {
expect(CurrencyFormatter.formatCompact(1234.56, 'EUR')).toBe('€1.235');
expect(CurrencyFormatter.formatCompact(1000000, 'EUR')).toBe('€1.000.000');
});
it('should format with custom currency symbol', () => {
expect(CurrencyFormatter.formatCompact(1234.56, 'GBP')).toBe('GBP 1,235');
expect(CurrencyFormatter.formatCompact(1234.56, 'JPY')).toBe('JPY 1,235');
});
it('should use USD as default currency', () => {
expect(CurrencyFormatter.formatCompact(1234.56)).toBe('$1,235');
});
it('should handle zero amount', () => {
expect(CurrencyFormatter.formatCompact(0, 'USD')).toBe('$0');
expect(CurrencyFormatter.formatCompact(0, 'EUR')).toBe('€0');
});
it('should handle negative amounts', () => {
expect(CurrencyFormatter.formatCompact(-1234.56, 'USD')).toBe('$-1,235');
expect(CurrencyFormatter.formatCompact(-1234.56, 'EUR')).toBe('€-1.235');
});
it('should round amounts correctly', () => {
expect(CurrencyFormatter.formatCompact(1234.4, 'USD')).toBe('$1,234');
expect(CurrencyFormatter.formatCompact(1234.6, 'USD')).toBe('$1,235');
});
});
});

View File

@@ -0,0 +1,98 @@
import { describe, it, expect } from 'vitest';
import { DateFormatter } from './DateFormatter';
describe('DateFormatter', () => {
describe('formatShort', () => {
it('should format date as "Jan 18, 2026"', () => {
const date = new Date('2026-01-18T12:00:00Z');
expect(DateFormatter.formatShort(date)).toBe('Jan 18, 2026');
});
it('should handle string input', () => {
expect(DateFormatter.formatShort('2026-01-18T12:00:00Z')).toBe('Jan 18, 2026');
});
it('should format different months correctly', () => {
expect(DateFormatter.formatShort(new Date('2026-02-15T12:00:00Z'))).toBe('Feb 15, 2026');
expect(DateFormatter.formatShort(new Date('2026-12-25T12:00:00Z'))).toBe('Dec 25, 2026');
});
it('should handle single digit days', () => {
expect(DateFormatter.formatShort(new Date('2026-01-05T12:00:00Z'))).toBe('Jan 5, 2026');
});
});
describe('formatMonthYear', () => {
it('should format date as "Jan 2026"', () => {
const date = new Date('2026-01-18T12:00:00Z');
expect(DateFormatter.formatMonthYear(date)).toBe('Jan 2026');
});
it('should handle string input', () => {
expect(DateFormatter.formatMonthYear('2026-01-18T12:00:00Z')).toBe('Jan 2026');
});
it('should format different months correctly', () => {
expect(DateFormatter.formatMonthYear(new Date('2026-02-15T12:00:00Z'))).toBe('Feb 2026');
expect(DateFormatter.formatMonthYear(new Date('2026-12-25T12:00:00Z'))).toBe('Dec 2026');
});
});
describe('formatTime', () => {
it('should format time as "15:00"', () => {
const date = new Date('2026-01-18T15:00:00Z');
expect(DateFormatter.formatTime(date)).toBe('15:00');
});
it('should handle string input', () => {
expect(DateFormatter.formatTime('2026-01-18T15:00:00Z')).toBe('15:00');
});
it('should pad single digit hours and minutes', () => {
expect(DateFormatter.formatTime(new Date('2026-01-18T05:09:00Z'))).toBe('05:09');
});
it('should handle midnight', () => {
expect(DateFormatter.formatTime(new Date('2026-01-18T00:00:00Z'))).toBe('00:00');
});
});
describe('formatMonthDay', () => {
it('should format date as "Jan 18"', () => {
const date = new Date('2026-01-18T12:00:00Z');
expect(DateFormatter.formatMonthDay(date)).toBe('Jan 18');
});
it('should handle string input', () => {
expect(DateFormatter.formatMonthDay('2026-01-18T12:00:00Z')).toBe('Jan 18');
});
it('should format different months correctly', () => {
expect(DateFormatter.formatMonthDay(new Date('2026-02-15T12:00:00Z'))).toBe('Feb 15');
expect(DateFormatter.formatMonthDay(new Date('2026-12-25T12:00:00Z'))).toBe('Dec 25');
});
it('should handle single digit days', () => {
expect(DateFormatter.formatMonthDay(new Date('2026-01-05T12:00:00Z'))).toBe('Jan 5');
});
});
describe('formatDateTime', () => {
it('should format date and time as "Jan 18, 15:00"', () => {
const date = new Date('2026-01-18T15:00:00Z');
expect(DateFormatter.formatDateTime(date)).toBe('Jan 18, 15:00');
});
it('should handle string input', () => {
expect(DateFormatter.formatDateTime('2026-01-18T15:00:00Z')).toBe('Jan 18, 15:00');
});
it('should pad single digit hours and minutes', () => {
expect(DateFormatter.formatDateTime(new Date('2026-01-18T05:09:00Z'))).toBe('Jan 18, 05:09');
});
it('should handle midnight', () => {
expect(DateFormatter.formatDateTime(new Date('2026-01-18T00:00:00Z'))).toBe('Jan 18, 00:00');
});
});
});

View File

@@ -0,0 +1,34 @@
import { describe, it, expect } from 'vitest';
import { DriverRegistrationStatusFormatter } from './DriverRegistrationStatusFormatter';
describe('DriverRegistrationStatusFormatter', () => {
describe('statusMessage', () => {
it('should return "Registered for this race" when registered', () => {
expect(DriverRegistrationStatusFormatter.statusMessage(true)).toBe('Registered for this race');
});
it('should return "Not registered" when not registered', () => {
expect(DriverRegistrationStatusFormatter.statusMessage(false)).toBe('Not registered');
});
});
describe('statusBadgeVariant', () => {
it('should return "success" when registered', () => {
expect(DriverRegistrationStatusFormatter.statusBadgeVariant(true)).toBe('success');
});
it('should return "warning" when not registered', () => {
expect(DriverRegistrationStatusFormatter.statusBadgeVariant(false)).toBe('warning');
});
});
describe('registrationButtonText', () => {
it('should return "Withdraw" when registered', () => {
expect(DriverRegistrationStatusFormatter.registrationButtonText(true)).toBe('Withdraw');
});
it('should return "Register" when not registered', () => {
expect(DriverRegistrationStatusFormatter.registrationButtonText(false)).toBe('Register');
});
});
});

View File

@@ -0,0 +1,57 @@
import { describe, it, expect } from 'vitest';
import { DurationFormatter } from './DurationFormatter';
describe('DurationFormatter', () => {
describe('formatMs', () => {
it('should format milliseconds with 2 decimal places', () => {
expect(DurationFormatter.formatMs(123.456)).toBe('123.46ms');
expect(DurationFormatter.formatMs(123.454)).toBe('123.45ms');
});
it('should handle zero milliseconds', () => {
expect(DurationFormatter.formatMs(0)).toBe('0.00ms');
});
it('should handle large milliseconds', () => {
expect(DurationFormatter.formatMs(123456.789)).toBe('123456.79ms');
});
it('should handle negative milliseconds', () => {
expect(DurationFormatter.formatMs(-123.456)).toBe('-123.46ms');
});
});
describe('formatSeconds', () => {
it('should format seconds as "M:SS.mmm"', () => {
expect(DurationFormatter.formatSeconds(65.123)).toBe('1:05.123');
expect(DurationFormatter.formatSeconds(125.456)).toBe('2:05.456');
});
it('should handle zero seconds', () => {
expect(DurationFormatter.formatSeconds(0)).toBe('0:00.000');
});
it('should handle less than 60 seconds', () => {
expect(DurationFormatter.formatSeconds(5.123)).toBe('0:05.123');
expect(DurationFormatter.formatSeconds(59.999)).toBe('0:59.999');
});
it('should handle exactly 60 seconds', () => {
expect(DurationFormatter.formatSeconds(60)).toBe('1:00.000');
});
it('should handle multiple minutes', () => {
expect(DurationFormatter.formatSeconds(125.123)).toBe('2:05.123');
expect(DurationFormatter.formatSeconds(365.456)).toBe('6:05.456');
});
it('should pad seconds with leading zeros', () => {
expect(DurationFormatter.formatSeconds(5.123)).toBe('0:05.123');
expect(DurationFormatter.formatSeconds(0.123)).toBe('0:00.123');
});
it('should handle negative seconds', () => {
expect(DurationFormatter.formatSeconds(-65.123)).toBe('-1:05.123');
});
});
});

View File

@@ -0,0 +1,60 @@
import { describe, it, expect } from 'vitest';
import { FinishFormatter } from './FinishFormatter';
describe('FinishFormatter', () => {
describe('format', () => {
it('should format position as "P1"', () => {
expect(FinishFormatter.format(1)).toBe('P1');
});
it('should format position as "P2"', () => {
expect(FinishFormatter.format(2)).toBe('P2');
});
it('should format position as "P10"', () => {
expect(FinishFormatter.format(10)).toBe('P10');
});
it('should handle null value', () => {
expect(FinishFormatter.format(null)).toBe('—');
});
it('should handle undefined value', () => {
expect(FinishFormatter.format(undefined)).toBe('—');
});
it('should handle decimal positions', () => {
expect(FinishFormatter.format(5.5)).toBe('P5');
});
it('should handle large positions', () => {
expect(FinishFormatter.format(100)).toBe('P100');
});
});
describe('formatAverage', () => {
it('should format average as "P5.4"', () => {
expect(FinishFormatter.formatAverage(5.4)).toBe('P5.4');
});
it('should format average as "P10.0"', () => {
expect(FinishFormatter.formatAverage(10.0)).toBe('P10.0');
});
it('should handle null value', () => {
expect(FinishFormatter.formatAverage(null)).toBe('—');
});
it('should handle undefined value', () => {
expect(FinishFormatter.formatAverage(undefined)).toBe('—');
});
it('should handle decimal averages', () => {
expect(FinishFormatter.formatAverage(5.123)).toBe('P5.1');
});
it('should handle large averages', () => {
expect(FinishFormatter.formatAverage(100.5)).toBe('P100.5');
});
});
});

View File

@@ -0,0 +1,91 @@
import { describe, it, expect } from 'vitest';
import { HealthAlertFormatter } from './HealthAlertFormatter';
describe('HealthAlertFormatter', () => {
describe('formatSeverity', () => {
it('should format critical severity correctly', () => {
expect(HealthAlertFormatter.formatSeverity('critical')).toBe('Critical');
});
it('should format warning severity correctly', () => {
expect(HealthAlertFormatter.formatSeverity('warning')).toBe('Warning');
});
it('should format info severity correctly', () => {
expect(HealthAlertFormatter.formatSeverity('info')).toBe('Info');
});
it('should default to Info for unknown severity', () => {
expect(HealthAlertFormatter.formatSeverity('unknown')).toBe('Info');
});
});
describe('formatSeverityColor', () => {
it('should return red for critical', () => {
expect(HealthAlertFormatter.formatSeverityColor('critical')).toBe('#ef4444');
});
it('should return amber for warning', () => {
expect(HealthAlertFormatter.formatSeverityColor('warning')).toBe('#f59e0b');
});
it('should return blue for info', () => {
expect(HealthAlertFormatter.formatSeverityColor('info')).toBe('#3b82f6');
});
it('should default to blue for unknown severity', () => {
expect(HealthAlertFormatter.formatSeverityColor('unknown')).toBe('#3b82f6');
});
});
describe('formatTimestamp', () => {
it('should format timestamp correctly', () => {
const timestamp = '2026-01-15T14:30:45Z';
const result = HealthAlertFormatter.formatTimestamp(timestamp);
expect(result).toBe('Jan 15, 2026, 14:30:45');
});
it('should handle different timestamps', () => {
const timestamp = '2026-12-25T09:15:30Z';
const result = HealthAlertFormatter.formatTimestamp(timestamp);
expect(result).toBe('Dec 25, 2026, 09:15:30');
});
});
describe('formatRelativeTime', () => {
it('should return "Just now" for less than 1 minute ago', () => {
const now = new Date();
const oneSecondAgo = new Date(now.getTime() - 1000);
const result = HealthAlertFormatter.formatRelativeTime(oneSecondAgo.toISOString());
expect(result).toBe('Just now');
});
it('should return minutes ago for less than 1 hour', () => {
const now = new Date();
const thirtyMinutesAgo = new Date(now.getTime() - 30 * 60 * 1000);
const result = HealthAlertFormatter.formatRelativeTime(thirtyMinutesAgo.toISOString());
expect(result).toBe('30m ago');
});
it('should return hours ago for less than 24 hours', () => {
const now = new Date();
const fiveHoursAgo = new Date(now.getTime() - 5 * 60 * 60 * 1000);
const result = HealthAlertFormatter.formatRelativeTime(fiveHoursAgo.toISOString());
expect(result).toBe('5h ago');
});
it('should return days ago for less than 7 days', () => {
const now = new Date();
const threeDaysAgo = new Date(now.getTime() - 3 * 24 * 60 * 60 * 1000);
const result = HealthAlertFormatter.formatRelativeTime(threeDaysAgo.toISOString());
expect(result).toBe('3d ago');
});
it('should return weeks ago for more than 7 days', () => {
const now = new Date();
const tenDaysAgo = new Date(now.getTime() - 10 * 24 * 60 * 60 * 1000);
const result = HealthAlertFormatter.formatRelativeTime(tenDaysAgo.toISOString());
expect(result).toBe('1w ago');
});
});
});

View File

@@ -0,0 +1,84 @@
import { describe, it, expect } from 'vitest';
import { HealthComponentFormatter } from './HealthComponentFormatter';
describe('HealthComponentFormatter', () => {
describe('formatStatusLabel', () => {
it('should format ok status correctly', () => {
expect(HealthComponentFormatter.formatStatusLabel('ok')).toBe('Healthy');
});
it('should format degraded status correctly', () => {
expect(HealthComponentFormatter.formatStatusLabel('degraded')).toBe('Degraded');
});
it('should format error status correctly', () => {
expect(HealthComponentFormatter.formatStatusLabel('error')).toBe('Error');
});
it('should format unknown status correctly', () => {
expect(HealthComponentFormatter.formatStatusLabel('unknown')).toBe('Unknown');
});
it('should default to Unknown for unknown status', () => {
expect(HealthComponentFormatter.formatStatusLabel('invalid')).toBe('Unknown');
});
});
describe('formatStatusColor', () => {
it('should return green for ok', () => {
expect(HealthComponentFormatter.formatStatusColor('ok')).toBe('#10b981');
});
it('should return amber for degraded', () => {
expect(HealthComponentFormatter.formatStatusColor('degraded')).toBe('#f59e0b');
});
it('should return red for error', () => {
expect(HealthComponentFormatter.formatStatusColor('error')).toBe('#ef4444');
});
it('should return gray for unknown', () => {
expect(HealthComponentFormatter.formatStatusColor('unknown')).toBe('#6b7280');
});
it('should default to gray for invalid status', () => {
expect(HealthComponentFormatter.formatStatusColor('invalid')).toBe('#6b7280');
});
});
describe('formatStatusIcon', () => {
it('should return checkmark for ok', () => {
expect(HealthComponentFormatter.formatStatusIcon('ok')).toBe('✓');
});
it('should return warning for degraded', () => {
expect(HealthComponentFormatter.formatStatusIcon('degraded')).toBe('⚠');
});
it('should return X for error', () => {
expect(HealthComponentFormatter.formatStatusIcon('error')).toBe('✕');
});
it('should return question mark for unknown', () => {
expect(HealthComponentFormatter.formatStatusIcon('unknown')).toBe('?');
});
it('should default to question mark for invalid status', () => {
expect(HealthComponentFormatter.formatStatusIcon('invalid')).toBe('?');
});
});
describe('formatTimestamp', () => {
it('should format timestamp correctly', () => {
const timestamp = '2026-01-15T14:30:45Z';
const result = HealthComponentFormatter.formatTimestamp(timestamp);
expect(result).toBe('Jan 15, 2026, 14:30:45');
});
it('should handle different timestamps', () => {
const timestamp = '2026-12-25T09:15:30Z';
const result = HealthComponentFormatter.formatTimestamp(timestamp);
expect(result).toBe('Dec 25, 2026, 09:15:30');
});
});
});

View File

@@ -0,0 +1,125 @@
import { describe, it, expect } from 'vitest';
import { HealthMetricFormatter } from './HealthMetricFormatter';
describe('HealthMetricFormatter', () => {
describe('formatUptime', () => {
it('should format uptime as percentage with 2 decimal places', () => {
expect(HealthMetricFormatter.formatUptime(99.99)).toBe('99.99%');
expect(HealthMetricFormatter.formatUptime(95.5)).toBe('95.50%');
});
it('should handle undefined uptime', () => {
expect(HealthMetricFormatter.formatUptime(undefined)).toBe('N/A');
});
it('should handle null uptime', () => {
expect(HealthMetricFormatter.formatUptime(null)).toBe('N/A');
});
it('should handle negative uptime', () => {
expect(HealthMetricFormatter.formatUptime(-1)).toBe('N/A');
});
it('should handle zero uptime', () => {
expect(HealthMetricFormatter.formatUptime(0)).toBe('0.00%');
});
});
describe('formatResponseTime', () => {
it('should format response time in milliseconds for values under 1000', () => {
expect(HealthMetricFormatter.formatResponseTime(123)).toBe('123ms');
expect(HealthMetricFormatter.formatResponseTime(999)).toBe('999ms');
});
it('should format response time in seconds for values between 1000 and 60000', () => {
expect(HealthMetricFormatter.formatResponseTime(1000)).toBe('1.00s');
expect(HealthMetricFormatter.formatResponseTime(12345)).toBe('12.35s');
expect(HealthMetricFormatter.formatResponseTime(59999)).toBe('60.00s');
});
it('should format response time in minutes for values 60000 or above', () => {
expect(HealthMetricFormatter.formatResponseTime(60000)).toBe('1.00m');
expect(HealthMetricFormatter.formatResponseTime(123456)).toBe('2.06m');
});
it('should handle undefined response time', () => {
expect(HealthMetricFormatter.formatResponseTime(undefined)).toBe('N/A');
});
it('should handle null response time', () => {
expect(HealthMetricFormatter.formatResponseTime(null)).toBe('N/A');
});
it('should handle negative response time', () => {
expect(HealthMetricFormatter.formatResponseTime(-1)).toBe('N/A');
});
it('should handle zero response time', () => {
expect(HealthMetricFormatter.formatResponseTime(0)).toBe('0ms');
});
});
describe('formatErrorRate', () => {
it('should format error rate as percentage with 2 decimal places', () => {
expect(HealthMetricFormatter.formatErrorRate(0.5)).toBe('0.50%');
expect(HealthMetricFormatter.formatErrorRate(12.34)).toBe('12.34%');
});
it('should handle undefined error rate', () => {
expect(HealthMetricFormatter.formatErrorRate(undefined)).toBe('N/A');
});
it('should handle null error rate', () => {
expect(HealthMetricFormatter.formatErrorRate(null)).toBe('N/A');
});
it('should handle negative error rate', () => {
expect(HealthMetricFormatter.formatErrorRate(-1)).toBe('N/A');
});
it('should handle zero error rate', () => {
expect(HealthMetricFormatter.formatErrorRate(0)).toBe('0.00%');
});
});
describe('formatTimestamp', () => {
it('should format timestamp correctly', () => {
const timestamp = '2026-01-15T14:30:45Z';
const result = HealthMetricFormatter.formatTimestamp(timestamp);
expect(result).toBe('Jan 15, 2026, 14:30:45');
});
it('should handle different timestamps', () => {
const timestamp = '2026-12-25T09:15:30Z';
const result = HealthMetricFormatter.formatTimestamp(timestamp);
expect(result).toBe('Dec 25, 2026, 09:15:30');
});
});
describe('formatSuccessRate', () => {
it('should format success rate correctly', () => {
expect(HealthMetricFormatter.formatSuccessRate(95, 5)).toBe('95.0%');
expect(HealthMetricFormatter.formatSuccessRate(99, 1)).toBe('99.0%');
});
it('should handle zero total checks', () => {
expect(HealthMetricFormatter.formatSuccessRate(0, 0)).toBe('N/A');
});
it('should handle only passed checks', () => {
expect(HealthMetricFormatter.formatSuccessRate(100, 0)).toBe('100.0%');
});
it('should handle only failed checks', () => {
expect(HealthMetricFormatter.formatSuccessRate(0, 100)).toBe('0.0%');
});
it('should handle undefined checks', () => {
expect(HealthMetricFormatter.formatSuccessRate(undefined, undefined)).toBe('N/A');
});
it('should handle null checks', () => {
expect(HealthMetricFormatter.formatSuccessRate(null, null)).toBe('N/A');
});
});
});

View File

@@ -0,0 +1,121 @@
import { describe, it, expect } from 'vitest';
import { HealthStatusFormatter } from './HealthStatusFormatter';
describe('HealthStatusFormatter', () => {
describe('formatStatusLabel', () => {
it('should format ok status correctly', () => {
expect(HealthStatusFormatter.formatStatusLabel('ok')).toBe('Healthy');
});
it('should format degraded status correctly', () => {
expect(HealthStatusFormatter.formatStatusLabel('degraded')).toBe('Degraded');
});
it('should format error status correctly', () => {
expect(HealthStatusFormatter.formatStatusLabel('error')).toBe('Error');
});
it('should format unknown status correctly', () => {
expect(HealthStatusFormatter.formatStatusLabel('unknown')).toBe('Unknown');
});
it('should default to Unknown for unknown status', () => {
expect(HealthStatusFormatter.formatStatusLabel('invalid')).toBe('Unknown');
});
});
describe('formatStatusColor', () => {
it('should return green for ok', () => {
expect(HealthStatusFormatter.formatStatusColor('ok')).toBe('#10b981');
});
it('should return amber for degraded', () => {
expect(HealthStatusFormatter.formatStatusColor('degraded')).toBe('#f59e0b');
});
it('should return red for error', () => {
expect(HealthStatusFormatter.formatStatusColor('error')).toBe('#ef4444');
});
it('should return gray for unknown', () => {
expect(HealthStatusFormatter.formatStatusColor('unknown')).toBe('#6b7280');
});
it('should default to gray for invalid status', () => {
expect(HealthStatusFormatter.formatStatusColor('invalid')).toBe('#6b7280');
});
});
describe('formatStatusIcon', () => {
it('should return checkmark for ok', () => {
expect(HealthStatusFormatter.formatStatusIcon('ok')).toBe('✓');
});
it('should return warning for degraded', () => {
expect(HealthStatusFormatter.formatStatusIcon('degraded')).toBe('⚠');
});
it('should return X for error', () => {
expect(HealthStatusFormatter.formatStatusIcon('error')).toBe('✕');
});
it('should return question mark for unknown', () => {
expect(HealthStatusFormatter.formatStatusIcon('unknown')).toBe('?');
});
it('should default to question mark for invalid status', () => {
expect(HealthStatusFormatter.formatStatusIcon('invalid')).toBe('?');
});
});
describe('formatTimestamp', () => {
it('should format timestamp correctly', () => {
const timestamp = '2026-01-15T14:30:45Z';
const result = HealthStatusFormatter.formatTimestamp(timestamp);
expect(result).toBe('Jan 15, 2026, 14:30:45');
});
it('should handle different timestamps', () => {
const timestamp = '2026-12-25T09:15:30Z';
const result = HealthStatusFormatter.formatTimestamp(timestamp);
expect(result).toBe('Dec 25, 2026, 09:15:30');
});
});
describe('formatRelativeTime', () => {
it('should return "Just now" for less than 1 minute ago', () => {
const now = new Date();
const oneSecondAgo = new Date(now.getTime() - 1000);
const result = HealthStatusFormatter.formatRelativeTime(oneSecondAgo.toISOString());
expect(result).toBe('Just now');
});
it('should return minutes ago for less than 1 hour', () => {
const now = new Date();
const thirtyMinutesAgo = new Date(now.getTime() - 30 * 60 * 1000);
const result = HealthStatusFormatter.formatRelativeTime(thirtyMinutesAgo.toISOString());
expect(result).toBe('30m ago');
});
it('should return hours ago for less than 24 hours', () => {
const now = new Date();
const fiveHoursAgo = new Date(now.getTime() - 5 * 60 * 60 * 1000);
const result = HealthStatusFormatter.formatRelativeTime(fiveHoursAgo.toISOString());
expect(result).toBe('5h ago');
});
it('should return days ago for less than 7 days', () => {
const now = new Date();
const threeDaysAgo = new Date(now.getTime() - 3 * 24 * 60 * 60 * 1000);
const result = HealthStatusFormatter.formatRelativeTime(threeDaysAgo.toISOString());
expect(result).toBe('3d ago');
});
it('should return weeks ago for more than 7 days', () => {
const now = new Date();
const tenDaysAgo = new Date(now.getTime() - 10 * 24 * 60 * 60 * 1000);
const result = HealthStatusFormatter.formatRelativeTime(tenDaysAgo.toISOString());
expect(result).toBe('1w ago');
});
});
});

View File

@@ -0,0 +1,14 @@
import { describe, it, expect } from 'vitest';
import { LeagueCreationStatusFormatter } from './LeagueCreationStatusFormatter';
describe('LeagueCreationStatusFormatter', () => {
describe('statusMessage', () => {
it('should return success message when league created successfully', () => {
expect(LeagueCreationStatusFormatter.statusMessage(true)).toBe('League created successfully!');
});
it('should return failure message when league creation failed', () => {
expect(LeagueCreationStatusFormatter.statusMessage(false)).toBe('Failed to create league.');
});
});
});

View File

@@ -0,0 +1,26 @@
import { describe, it, expect } from 'vitest';
import { LeagueFormatter } from './LeagueFormatter';
describe('LeagueFormatter', () => {
describe('formatCount', () => {
it('should format 1 league correctly', () => {
expect(LeagueFormatter.formatCount(1)).toBe('1 league');
});
it('should format 2 leagues correctly', () => {
expect(LeagueFormatter.formatCount(2)).toBe('2 leagues');
});
it('should format 0 leagues correctly', () => {
expect(LeagueFormatter.formatCount(0)).toBe('0 leagues');
});
it('should format large numbers correctly', () => {
expect(LeagueFormatter.formatCount(100)).toBe('100 leagues');
});
it('should handle negative numbers', () => {
expect(LeagueFormatter.formatCount(-1)).toBe('-1 leagues');
});
});
});

View File

@@ -0,0 +1,60 @@
import { describe, it, expect } from 'vitest';
import { LeagueRoleFormatter, leagueRoleDisplay } from './LeagueRoleFormatter';
import type { LeagueRole } from './LeagueRoleFormatter';
describe('LeagueRoleFormatter', () => {
describe('getLeagueRoleDisplay', () => {
it('should return correct display data for owner role', () => {
const result = LeagueRoleFormatter.getLeagueRoleDisplay('owner');
expect(result).toEqual({
text: 'Owner',
badgeClasses: 'bg-yellow-500/10 text-yellow-500 border-yellow-500/30',
});
});
it('should return correct display data for admin role', () => {
const result = LeagueRoleFormatter.getLeagueRoleDisplay('admin');
expect(result).toEqual({
text: 'Admin',
badgeClasses: 'bg-purple-500/10 text-purple-400 border-purple-500/30',
});
});
it('should return correct display data for steward role', () => {
const result = LeagueRoleFormatter.getLeagueRoleDisplay('steward');
expect(result).toEqual({
text: 'Steward',
badgeClasses: 'bg-blue-500/10 text-blue-400 border-blue-500/30',
});
});
it('should return correct display data for member role', () => {
const result = LeagueRoleFormatter.getLeagueRoleDisplay('member');
expect(result).toEqual({
text: 'Member',
badgeClasses: 'bg-primary-blue/10 text-primary-blue border-primary-blue/30',
});
});
});
describe('leagueRoleDisplay constant', () => {
it('should contain all role definitions', () => {
expect(leagueRoleDisplay.owner).toBeDefined();
expect(leagueRoleDisplay.admin).toBeDefined();
expect(leagueRoleDisplay.steward).toBeDefined();
expect(leagueRoleDisplay.member).toBeDefined();
});
it('should have correct structure for each role', () => {
const roles: LeagueRole[] = ['owner', 'admin', 'steward', 'member'];
roles.forEach(role => {
const display = leagueRoleDisplay[role];
expect(display).toHaveProperty('text');
expect(display).toHaveProperty('badgeClasses');
expect(typeof display.text).toBe('string');
expect(typeof display.badgeClasses).toBe('string');
});
});
});
});

View File

@@ -0,0 +1,36 @@
import { describe, it, expect } from 'vitest';
import { LeagueTierFormatter } from './LeagueTierFormatter';
describe('LeagueTierFormatter', () => {
describe('getDisplay', () => {
it('should return correct display data for premium tier', () => {
const result = LeagueTierFormatter.getDisplay('premium');
expect(result).toEqual({
color: 'text-yellow-400',
bgColor: 'bg-yellow-500/10',
border: 'border-yellow-500/30',
icon: '⭐',
});
});
it('should return correct display data for standard tier', () => {
const result = LeagueTierFormatter.getDisplay('standard');
expect(result).toEqual({
color: 'text-primary-blue',
bgColor: 'bg-primary-blue/10',
border: 'border-primary-blue/30',
icon: '🏆',
});
});
it('should return correct display data for starter tier', () => {
const result = LeagueTierFormatter.getDisplay('starter');
expect(result).toEqual({
color: 'text-gray-400',
bgColor: 'bg-gray-500/10',
border: 'border-gray-500/30',
icon: '🚀',
});
});
});
});

View File

@@ -0,0 +1,52 @@
import { describe, it, expect } from 'vitest';
import { LeagueWizardValidationMessages } from './LeagueWizardValidationMessages';
describe('LeagueWizardValidationMessages', () => {
it('should have LEAGUE_NAME_REQUIRED message', () => {
expect(LeagueWizardValidationMessages.LEAGUE_NAME_REQUIRED).toBe('League name is required');
});
it('should have LEAGUE_NAME_TOO_SHORT message', () => {
expect(LeagueWizardValidationMessages.LEAGUE_NAME_TOO_SHORT).toBe('League name must be at least 3 characters');
});
it('should have LEAGUE_NAME_TOO_LONG message', () => {
expect(LeagueWizardValidationMessages.LEAGUE_NAME_TOO_LONG).toBe('League name must be less than 100 characters');
});
it('should have DESCRIPTION_TOO_LONG message', () => {
expect(LeagueWizardValidationMessages.DESCRIPTION_TOO_LONG).toBe('Description must be less than 500 characters');
});
it('should have VISIBILITY_REQUIRED message', () => {
expect(LeagueWizardValidationMessages.VISIBILITY_REQUIRED).toBe('Visibility is required');
});
it('should have MAX_DRIVERS_INVALID_SOLO message', () => {
expect(LeagueWizardValidationMessages.MAX_DRIVERS_INVALID_SOLO).toBe('Max drivers must be greater than 0 for solo leagues');
});
it('should have MAX_DRIVERS_TOO_HIGH message', () => {
expect(LeagueWizardValidationMessages.MAX_DRIVERS_TOO_HIGH).toBe('Max drivers cannot exceed 100');
});
it('should have MAX_TEAMS_INVALID_TEAM message', () => {
expect(LeagueWizardValidationMessages.MAX_TEAMS_INVALID_TEAM).toBe('Max teams must be greater than 0 for team leagues');
});
it('should have DRIVERS_PER_TEAM_INVALID message', () => {
expect(LeagueWizardValidationMessages.DRIVERS_PER_TEAM_INVALID).toBe('Drivers per team must be greater than 0');
});
it('should have QUALIFYING_DURATION_INVALID message', () => {
expect(LeagueWizardValidationMessages.QUALIFYING_DURATION_INVALID).toBe('Qualifying duration must be greater than 0 minutes');
});
it('should have MAIN_RACE_DURATION_INVALID message', () => {
expect(LeagueWizardValidationMessages.MAIN_RACE_DURATION_INVALID).toBe('Main race duration must be greater than 0 minutes');
});
it('should have SCORING_PRESET_OR_CUSTOM_REQUIRED message', () => {
expect(LeagueWizardValidationMessages.SCORING_PRESET_OR_CUSTOM_REQUIRED).toBe('Select a scoring preset or enable custom scoring');
});
});

View File

@@ -0,0 +1,100 @@
import { describe, it, expect } from 'vitest';
import { MedalFormatter } from './MedalFormatter';
describe('MedalFormatter', () => {
describe('getVariant', () => {
it('should return "warning" for 1st place', () => {
expect(MedalFormatter.getVariant(1)).toBe('warning');
});
it('should return "high" for 2nd place', () => {
expect(MedalFormatter.getVariant(2)).toBe('high');
});
it('should return "warning" for 3rd place', () => {
expect(MedalFormatter.getVariant(3)).toBe('warning');
});
it('should return "low" for 4th place', () => {
expect(MedalFormatter.getVariant(4)).toBe('low');
});
it('should return "low" for any position after 3rd', () => {
expect(MedalFormatter.getVariant(5)).toBe('low');
expect(MedalFormatter.getVariant(10)).toBe('low');
expect(MedalFormatter.getVariant(100)).toBe('low');
});
});
describe('getMedalIcon', () => {
it('should return trophy for 1st place', () => {
expect(MedalFormatter.getMedalIcon(1)).toBe('🏆');
});
it('should return trophy for 2nd place', () => {
expect(MedalFormatter.getMedalIcon(2)).toBe('🏆');
});
it('should return trophy for 3rd place', () => {
expect(MedalFormatter.getMedalIcon(3)).toBe('🏆');
});
it('should return null for 4th place', () => {
expect(MedalFormatter.getMedalIcon(4)).toBeNull();
});
it('should return null for any position after 3rd', () => {
expect(MedalFormatter.getMedalIcon(5)).toBeNull();
expect(MedalFormatter.getMedalIcon(10)).toBeNull();
expect(MedalFormatter.getMedalIcon(100)).toBeNull();
});
});
describe('getBg', () => {
it('should return bg-warning-amber for 1st place', () => {
expect(MedalFormatter.getBg(1)).toBe('bg-warning-amber');
});
it('should return bg-gray-300 for 2nd place', () => {
expect(MedalFormatter.getBg(2)).toBe('bg-gray-300');
});
it('should return bg-orange-700 for 3rd place', () => {
expect(MedalFormatter.getBg(3)).toBe('bg-orange-700');
});
it('should return bg-gray-800 for 4th place', () => {
expect(MedalFormatter.getBg(4)).toBe('bg-gray-800');
});
it('should return bg-gray-800 for any position after 3rd', () => {
expect(MedalFormatter.getBg(5)).toBe('bg-gray-800');
expect(MedalFormatter.getBg(10)).toBe('bg-gray-800');
expect(MedalFormatter.getBg(100)).toBe('bg-gray-800');
});
});
describe('getColor', () => {
it('should return text-warning-amber for 1st place', () => {
expect(MedalFormatter.getColor(1)).toBe('text-warning-amber');
});
it('should return text-gray-300 for 2nd place', () => {
expect(MedalFormatter.getColor(2)).toBe('text-gray-300');
});
it('should return text-orange-700 for 3rd place', () => {
expect(MedalFormatter.getColor(3)).toBe('text-orange-700');
});
it('should return text-gray-400 for 4th place', () => {
expect(MedalFormatter.getColor(4)).toBe('text-gray-400');
});
it('should return text-gray-400 for any position after 3rd', () => {
expect(MedalFormatter.getColor(5)).toBe('text-gray-400');
expect(MedalFormatter.getColor(10)).toBe('text-gray-400');
expect(MedalFormatter.getColor(100)).toBe('text-gray-400');
});
});
});

View File

@@ -0,0 +1,48 @@
import { describe, it, expect } from 'vitest';
import { MemberFormatter } from './MemberFormatter';
describe('MemberFormatter', () => {
describe('formatCount', () => {
it('should format 1 member correctly', () => {
expect(MemberFormatter.formatCount(1)).toBe('1 member');
});
it('should format 2 members correctly', () => {
expect(MemberFormatter.formatCount(2)).toBe('2 members');
});
it('should format 0 members correctly', () => {
expect(MemberFormatter.formatCount(0)).toBe('0 members');
});
it('should format large numbers correctly', () => {
expect(MemberFormatter.formatCount(100)).toBe('100 members');
});
it('should handle negative numbers', () => {
expect(MemberFormatter.formatCount(-1)).toBe('-1 members');
});
});
describe('formatUnits', () => {
it('should format 1 unit correctly', () => {
expect(MemberFormatter.formatUnits(1)).toBe('1 Unit');
});
it('should format 2 units correctly', () => {
expect(MemberFormatter.formatUnits(2)).toBe('2 Units');
});
it('should format 0 units correctly', () => {
expect(MemberFormatter.formatUnits(0)).toBe('0 Units');
});
it('should format large numbers correctly', () => {
expect(MemberFormatter.formatUnits(100)).toBe('100 Units');
});
it('should handle negative numbers', () => {
expect(MemberFormatter.formatUnits(-1)).toBe('-1 Units');
});
});
});

View File

@@ -0,0 +1,26 @@
import { describe, it, expect } from 'vitest';
import { MembershipFeeTypeFormatter } from './MembershipFeeTypeFormatter';
describe('MembershipFeeTypeFormatter', () => {
describe('format', () => {
it('should format "monthly" correctly', () => {
expect(MembershipFeeTypeFormatter.format('monthly')).toBe('Monthly');
});
it('should format "yearly" correctly', () => {
expect(MembershipFeeTypeFormatter.format('yearly')).toBe('Yearly');
});
it('should format "one_time" correctly', () => {
expect(MembershipFeeTypeFormatter.format('one_time')).toBe('One time');
});
it('should handle unknown types', () => {
expect(MembershipFeeTypeFormatter.format('unknown')).toBe('Unknown');
});
it('should handle empty string', () => {
expect(MembershipFeeTypeFormatter.format('')).toBe('');
});
});
});

View File

@@ -0,0 +1,46 @@
import { describe, it, expect } from 'vitest';
import { MemoryFormatter } from './MemoryFormatter';
describe('MemoryFormatter', () => {
describe('formatMB', () => {
it('should format bytes as MB with 1 decimal place', () => {
expect(MemoryFormatter.formatMB(1048576)).toBe('1.0MB');
expect(MemoryFormatter.formatMB(10485760)).toBe('10.0MB');
expect(MemoryFormatter.formatMB(104857600)).toBe('100.0MB');
});
it('should handle zero bytes', () => {
expect(MemoryFormatter.formatMB(0)).toBe('0.0MB');
});
it('should handle small values', () => {
expect(MemoryFormatter.formatMB(1024)).toBe('0.0MB');
expect(MemoryFormatter.formatMB(524288)).toBe('0.5MB');
});
it('should handle large values', () => {
expect(MemoryFormatter.formatMB(1073741824)).toBe('1024.0MB');
});
});
describe('formatKB', () => {
it('should format bytes as KB with 1 decimal place', () => {
expect(MemoryFormatter.formatKB(1024)).toBe('1.0KB');
expect(MemoryFormatter.formatKB(10240)).toBe('10.0KB');
expect(MemoryFormatter.formatKB(102400)).toBe('100.0KB');
});
it('should handle zero bytes', () => {
expect(MemoryFormatter.formatKB(0)).toBe('0.0KB');
});
it('should handle small values', () => {
expect(MemoryFormatter.formatKB(1)).toBe('0.0KB');
expect(MemoryFormatter.formatKB(512)).toBe('0.5KB');
});
it('should handle large values', () => {
expect(MemoryFormatter.formatKB(1048576)).toBe('1024.0KB');
});
});
});

View File

@@ -0,0 +1,82 @@
import { describe, it, expect } from 'vitest';
import { NumberFormatter } from './NumberFormatter';
describe('NumberFormatter', () => {
describe('format', () => {
it('should format number with thousands separators', () => {
expect(NumberFormatter.format(1234567)).toBe('1,234,567');
expect(NumberFormatter.format(1000000)).toBe('1,000,000');
});
it('should handle numbers without thousands separators', () => {
expect(NumberFormatter.format(123)).toBe('123');
expect(NumberFormatter.format(999)).toBe('999');
});
it('should handle decimal numbers', () => {
expect(NumberFormatter.format(1234.56)).toBe('1,234.56');
expect(NumberFormatter.format(1234567.89)).toBe('1,234,567.89');
});
it('should handle zero', () => {
expect(NumberFormatter.format(0)).toBe('0');
});
it('should handle negative numbers', () => {
expect(NumberFormatter.format(-1234567)).toBe('-1,234,567');
expect(NumberFormatter.format(-1234.56)).toBe('-1,234.56');
});
it('should handle large numbers', () => {
expect(NumberFormatter.format(1234567890)).toBe('1,234,567,890');
});
});
describe('formatCompact', () => {
it('should format numbers under 1000 as is', () => {
expect(NumberFormatter.formatCompact(123)).toBe('123');
expect(NumberFormatter.formatCompact(999)).toBe('999');
});
it('should format numbers 1000-999999 with k suffix', () => {
expect(NumberFormatter.formatCompact(1000)).toBe('1.0k');
expect(NumberFormatter.formatCompact(1234)).toBe('1.2k');
expect(NumberFormatter.formatCompact(999999)).toBe('1000.0k');
});
it('should format numbers 1000000 and above with M suffix', () => {
expect(NumberFormatter.formatCompact(1000000)).toBe('1.0M');
expect(NumberFormatter.formatCompact(1234567)).toBe('1.2M');
expect(NumberFormatter.formatCompact(999999999)).toBe('1000.0M');
});
it('should handle zero', () => {
expect(NumberFormatter.formatCompact(0)).toBe('0');
});
it('should handle negative numbers', () => {
expect(NumberFormatter.formatCompact(-1234)).toBe('-1.2k');
expect(NumberFormatter.formatCompact(-1234567)).toBe('-1.2M');
});
});
describe('formatCurrency', () => {
it('should format number with currency symbol', () => {
expect(NumberFormatter.formatCurrency(1234567, 'USD')).toBe('USD 1,234,567');
expect(NumberFormatter.formatCurrency(1234.56, 'EUR')).toBe('EUR 1,234.56');
});
it('should handle zero', () => {
expect(NumberFormatter.formatCurrency(0, 'USD')).toBe('USD 0');
});
it('should handle negative numbers', () => {
expect(NumberFormatter.formatCurrency(-1234567, 'USD')).toBe('USD -1,234,567');
});
it('should handle different currencies', () => {
expect(NumberFormatter.formatCurrency(1234567, 'GBP')).toBe('GBP 1,234,567');
expect(NumberFormatter.formatCurrency(1234567, 'JPY')).toBe('JPY 1,234,567');
});
});
});

View File

@@ -0,0 +1,48 @@
import { describe, it, expect } from 'vitest';
import { OnboardingStatusFormatter } from './OnboardingStatusFormatter';
describe('OnboardingStatusFormatter', () => {
describe('statusLabel', () => {
it('should return "Onboarding Complete" when success is true', () => {
expect(OnboardingStatusFormatter.statusLabel(true)).toBe('Onboarding Complete');
});
it('should return "Onboarding Failed" when success is false', () => {
expect(OnboardingStatusFormatter.statusLabel(false)).toBe('Onboarding Failed');
});
});
describe('statusVariant', () => {
it('should return "performance-green" when success is true', () => {
expect(OnboardingStatusFormatter.statusVariant(true)).toBe('performance-green');
});
it('should return "racing-red" when success is false', () => {
expect(OnboardingStatusFormatter.statusVariant(false)).toBe('racing-red');
});
});
describe('statusIcon', () => {
it('should return "✅" when success is true', () => {
expect(OnboardingStatusFormatter.statusIcon(true)).toBe('✅');
});
it('should return "❌" when success is false', () => {
expect(OnboardingStatusFormatter.statusIcon(false)).toBe('❌');
});
});
describe('statusMessage', () => {
it('should return success message when success is true', () => {
expect(OnboardingStatusFormatter.statusMessage(true)).toBe('Your onboarding has been completed successfully.');
});
it('should return default failure message when success is false and no error message', () => {
expect(OnboardingStatusFormatter.statusMessage(false)).toBe('Failed to complete onboarding. Please try again.');
});
it('should return custom error message when success is false and error message provided', () => {
expect(OnboardingStatusFormatter.statusMessage(false, 'Custom error')).toBe('Custom error');
});
});
});

View File

@@ -0,0 +1,28 @@
import { describe, it, expect } from 'vitest';
import { PayerTypeFormatter } from './PayerTypeFormatter';
describe('PayerTypeFormatter', () => {
describe('format', () => {
it('should capitalize the first letter and lowercase the rest', () => {
expect(PayerTypeFormatter.format('individual')).toBe('Individual');
expect(PayerTypeFormatter.format('organization')).toBe('Organization');
expect(PayerTypeFormatter.format('company')).toBe('Company');
});
it('should handle single character strings', () => {
expect(PayerTypeFormatter.format('a')).toBe('A');
});
it('should handle already capitalized strings', () => {
expect(PayerTypeFormatter.format('Individual')).toBe('Individual');
});
it('should handle all uppercase strings', () => {
expect(PayerTypeFormatter.format('INDIVIDUAL')).toBe('Individual');
});
it('should handle empty string', () => {
expect(PayerTypeFormatter.format('')).toBe('');
});
});
});

View File

@@ -0,0 +1,30 @@
import { describe, it, expect } from 'vitest';
import { PaymentTypeFormatter } from './PaymentTypeFormatter';
describe('PaymentTypeFormatter', () => {
describe('format', () => {
it('should replace underscores with spaces and capitalize words', () => {
expect(PaymentTypeFormatter.format('credit_card')).toBe('Credit Card');
expect(PaymentTypeFormatter.format('bank_transfer')).toBe('Bank Transfer');
expect(PaymentTypeFormatter.format('paypal')).toBe('Paypal');
});
it('should handle strings without underscores', () => {
expect(PaymentTypeFormatter.format('creditcard')).toBe('Creditcard');
expect(PaymentTypeFormatter.format('banktransfer')).toBe('Banktransfer');
});
it('should handle single word strings', () => {
expect(PaymentTypeFormatter.format('cash')).toBe('Cash');
expect(PaymentTypeFormatter.format('check')).toBe('Check');
});
it('should handle empty string', () => {
expect(PaymentTypeFormatter.format('')).toBe('');
});
it('should handle multiple underscores', () => {
expect(PaymentTypeFormatter.format('credit_card_payment')).toBe('Credit Card Payment');
});
});
});

View File

@@ -0,0 +1,62 @@
import { describe, it, expect } from 'vitest';
import { PercentFormatter } from './PercentFormatter';
describe('PercentFormatter', () => {
describe('format', () => {
it('should format decimal value as percentage with 1 decimal place', () => {
expect(PercentFormatter.format(0.1234)).toBe('12.3%');
expect(PercentFormatter.format(0.5)).toBe('50.0%');
expect(PercentFormatter.format(1.0)).toBe('100.0%');
});
it('should handle zero', () => {
expect(PercentFormatter.format(0)).toBe('0.0%');
});
it('should handle null', () => {
expect(PercentFormatter.format(null)).toBe('0.0%');
});
it('should handle undefined', () => {
expect(PercentFormatter.format(undefined)).toBe('0.0%');
});
it('should handle negative values', () => {
expect(PercentFormatter.format(-0.1234)).toBe('-12.3%');
});
it('should handle values greater than 1', () => {
expect(PercentFormatter.format(1.5)).toBe('150.0%');
expect(PercentFormatter.format(2.0)).toBe('200.0%');
});
});
describe('formatWhole', () => {
it('should format whole number as percentage', () => {
expect(PercentFormatter.formatWhole(12)).toBe('12%');
expect(PercentFormatter.formatWhole(50)).toBe('50%');
expect(PercentFormatter.formatWhole(100)).toBe('100%');
});
it('should handle zero', () => {
expect(PercentFormatter.formatWhole(0)).toBe('0%');
});
it('should handle null', () => {
expect(PercentFormatter.formatWhole(null)).toBe('0%');
});
it('should handle undefined', () => {
expect(PercentFormatter.formatWhole(undefined)).toBe('0%');
});
it('should round decimal values', () => {
expect(PercentFormatter.formatWhole(12.3)).toBe('12%');
expect(PercentFormatter.formatWhole(12.7)).toBe('13%');
});
it('should handle negative values', () => {
expect(PercentFormatter.formatWhole(-12)).toBe('-12%');
});
});
});

View File

@@ -0,0 +1,26 @@
import { describe, it, expect } from 'vitest';
import { PrizeTypeFormatter } from './PrizeTypeFormatter';
describe('PrizeTypeFormatter', () => {
describe('format', () => {
it('should format "cash" as "Cash Prize"', () => {
expect(PrizeTypeFormatter.format('cash')).toBe('Cash Prize');
});
it('should format "merchandise" as "Merchandise"', () => {
expect(PrizeTypeFormatter.format('merchandise')).toBe('Merchandise');
});
it('should format "other" as "Other"', () => {
expect(PrizeTypeFormatter.format('other')).toBe('Other');
});
it('should handle unknown types', () => {
expect(PrizeTypeFormatter.format('unknown')).toBe('unknown');
});
it('should handle empty string', () => {
expect(PrizeTypeFormatter.format('')).toBe('');
});
});
});

View File

@@ -0,0 +1,359 @@
import { describe, it, expect } from 'vitest';
import { ProfileFormatter } from './ProfileFormatter';
describe('ProfileFormatter', () => {
describe('getCountryFlag', () => {
it('should return correct flag for US', () => {
const result = ProfileFormatter.getCountryFlag('US');
expect(result).toEqual({
flag: '🇺🇸',
label: 'United States',
});
});
it('should return correct flag for GB', () => {
const result = ProfileFormatter.getCountryFlag('GB');
expect(result).toEqual({
flag: '🇬🇧',
label: 'United Kingdom',
});
});
it('should return correct flag for DE', () => {
const result = ProfileFormatter.getCountryFlag('DE');
expect(result).toEqual({
flag: '🇩🇪',
label: 'Germany',
});
});
it('should handle lowercase country codes', () => {
const result = ProfileFormatter.getCountryFlag('us');
expect(result).toEqual({
flag: '🇺🇸',
label: 'United States',
});
});
it('should return default flag for unknown country code', () => {
const result = ProfileFormatter.getCountryFlag('XX');
expect(result).toEqual({
flag: '🏁',
label: 'Unknown',
});
});
});
describe('getAchievementRarity', () => {
it('should return correct display data for common rarity', () => {
const result = ProfileFormatter.getAchievementRarity('common');
expect(result).toEqual({
text: 'Common',
badgeClasses: 'bg-gray-400/10 text-gray-400',
borderClasses: 'border-gray-400/30',
});
});
it('should return correct display data for rare rarity', () => {
const result = ProfileFormatter.getAchievementRarity('rare');
expect(result).toEqual({
text: 'Rare',
badgeClasses: 'bg-primary-blue/10 text-primary-blue',
borderClasses: 'border-primary-blue/30',
});
});
it('should return correct display data for epic rarity', () => {
const result = ProfileFormatter.getAchievementRarity('epic');
expect(result).toEqual({
text: 'Epic',
badgeClasses: 'bg-purple-400/10 text-purple-400',
borderClasses: 'border-purple-400/30',
});
});
it('should return correct display data for legendary rarity', () => {
const result = ProfileFormatter.getAchievementRarity('legendary');
expect(result).toEqual({
text: 'Legendary',
badgeClasses: 'bg-yellow-400/10 text-yellow-400',
borderClasses: 'border-yellow-400/30',
});
});
it('should default to common for unknown rarity', () => {
const result = ProfileFormatter.getAchievementRarity('unknown');
expect(result).toEqual({
text: 'Common',
badgeClasses: 'bg-gray-400/10 text-gray-400',
borderClasses: 'border-gray-400/30',
});
});
});
describe('getAchievementIcon', () => {
it('should return correct display data for trophy icon', () => {
const result = ProfileFormatter.getAchievementIcon('trophy');
expect(result).toEqual({
name: 'Trophy',
});
});
it('should return correct display data for medal icon', () => {
const result = ProfileFormatter.getAchievementIcon('medal');
expect(result).toEqual({
name: 'Medal',
});
});
it('should return correct display data for star icon', () => {
const result = ProfileFormatter.getAchievementIcon('star');
expect(result).toEqual({
name: 'Star',
});
});
it('should return correct display data for crown icon', () => {
const result = ProfileFormatter.getAchievementIcon('crown');
expect(result).toEqual({
name: 'Crown',
});
});
it('should return correct display data for target icon', () => {
const result = ProfileFormatter.getAchievementIcon('target');
expect(result).toEqual({
name: 'Target',
});
});
it('should return correct display data for zap icon', () => {
const result = ProfileFormatter.getAchievementIcon('zap');
expect(result).toEqual({
name: 'Zap',
});
});
it('should default to trophy for unknown icon', () => {
const result = ProfileFormatter.getAchievementIcon('unknown');
expect(result).toEqual({
name: 'Trophy',
});
});
});
describe('getSocialPlatform', () => {
it('should return correct display data for twitter', () => {
const result = ProfileFormatter.getSocialPlatform('twitter');
expect(result).toEqual({
name: 'Twitter',
hoverClasses: 'hover:text-sky-400 hover:bg-sky-400/10',
});
});
it('should return correct display data for youtube', () => {
const result = ProfileFormatter.getSocialPlatform('youtube');
expect(result).toEqual({
name: 'YouTube',
hoverClasses: 'hover:text-red-500 hover:bg-red-500/10',
});
});
it('should return correct display data for twitch', () => {
const result = ProfileFormatter.getSocialPlatform('twitch');
expect(result).toEqual({
name: 'Twitch',
hoverClasses: 'hover:text-purple-400 hover:bg-purple-400/10',
});
});
it('should return correct display data for discord', () => {
const result = ProfileFormatter.getSocialPlatform('discord');
expect(result).toEqual({
name: 'Discord',
hoverClasses: 'hover:text-indigo-400 hover:bg-indigo-400/10',
});
});
it('should default to discord for unknown platform', () => {
const result = ProfileFormatter.getSocialPlatform('unknown');
expect(result).toEqual({
name: 'Discord',
hoverClasses: 'hover:text-indigo-400 hover:bg-indigo-400/10',
});
});
});
describe('formatMonthYear', () => {
it('should format date as "Jan 2026"', () => {
expect(ProfileFormatter.formatMonthYear('2026-01-15')).toBe('Jan 2026');
});
it('should format different months correctly', () => {
expect(ProfileFormatter.formatMonthYear('2026-02-15')).toBe('Feb 2026');
expect(ProfileFormatter.formatMonthYear('2026-12-25')).toBe('Dec 2026');
});
});
describe('formatMonthDayYear', () => {
it('should format date as "Jan 15, 2026"', () => {
expect(ProfileFormatter.formatMonthDayYear('2026-01-15')).toBe('Jan 15, 2026');
});
it('should format different dates correctly', () => {
expect(ProfileFormatter.formatMonthDayYear('2026-02-15')).toBe('Feb 15, 2026');
expect(ProfileFormatter.formatMonthDayYear('2026-12-25')).toBe('Dec 25, 2026');
});
});
describe('formatPercentage', () => {
it('should format decimal value as percentage with 1 decimal place', () => {
expect(ProfileFormatter.formatPercentage(0.1234)).toBe('12.3%');
expect(ProfileFormatter.formatPercentage(0.5)).toBe('50.0%');
expect(ProfileFormatter.formatPercentage(1.0)).toBe('100.0%');
});
it('should handle zero', () => {
expect(ProfileFormatter.formatPercentage(0)).toBe('0.0%');
});
it('should handle null', () => {
expect(ProfileFormatter.formatPercentage(null)).toBe('0.0%');
});
it('should handle undefined', () => {
expect(ProfileFormatter.formatPercentage(undefined)).toBe('0.0%');
});
});
describe('formatFinishPosition', () => {
it('should format position as "P1"', () => {
expect(ProfileFormatter.formatFinishPosition(1)).toBe('P1');
});
it('should format position as "P10"', () => {
expect(ProfileFormatter.formatFinishPosition(10)).toBe('P10');
});
it('should handle null value', () => {
expect(ProfileFormatter.formatFinishPosition(null)).toBe('P-');
});
it('should handle undefined value', () => {
expect(ProfileFormatter.formatFinishPosition(undefined)).toBe('P-');
});
});
describe('formatAvgFinish', () => {
it('should format average as "P5.4"', () => {
expect(ProfileFormatter.formatAvgFinish(5.4)).toBe('P5.4');
});
it('should format average as "P10.0"', () => {
expect(ProfileFormatter.formatAvgFinish(10.0)).toBe('P10.0');
});
it('should handle null value', () => {
expect(ProfileFormatter.formatAvgFinish(null)).toBe('P-');
});
it('should handle undefined value', () => {
expect(ProfileFormatter.formatAvgFinish(undefined)).toBe('P-');
});
});
describe('formatRating', () => {
it('should format rating as rounded number', () => {
expect(ProfileFormatter.formatRating(1234.56)).toBe('1235');
expect(ProfileFormatter.formatRating(1234.4)).toBe('1234');
});
it('should handle null value', () => {
expect(ProfileFormatter.formatRating(null)).toBe('0');
});
it('should handle undefined value', () => {
expect(ProfileFormatter.formatRating(undefined)).toBe('0');
});
});
describe('formatConsistency', () => {
it('should format consistency as percentage', () => {
expect(ProfileFormatter.formatConsistency(85)).toBe('85%');
expect(ProfileFormatter.formatConsistency(99.5)).toBe('100%');
});
it('should handle null value', () => {
expect(ProfileFormatter.formatConsistency(null)).toBe('0%');
});
it('should handle undefined value', () => {
expect(ProfileFormatter.formatConsistency(undefined)).toBe('0%');
});
});
describe('formatPercentile', () => {
it('should format percentile as "Top X%"', () => {
expect(ProfileFormatter.formatPercentile(5)).toBe('Top 5%');
expect(ProfileFormatter.formatPercentile(10)).toBe('Top 10%');
});
it('should handle null value', () => {
expect(ProfileFormatter.formatPercentile(null)).toBe('Top -%');
});
it('should handle undefined value', () => {
expect(ProfileFormatter.formatPercentile(undefined)).toBe('Top -%');
});
});
describe('getTeamRole', () => {
it('should return correct display data for owner role', () => {
const result = ProfileFormatter.getTeamRole('owner');
expect(result).toEqual({
text: 'Owner',
badgeClasses: 'bg-yellow-500/10 text-yellow-500 border-yellow-500/30',
});
});
it('should return correct display data for manager role', () => {
const result = ProfileFormatter.getTeamRole('manager');
expect(result).toEqual({
text: 'Manager',
badgeClasses: 'bg-blue-500/10 text-blue-400 border-blue-500/30',
});
});
it('should return correct display data for admin role', () => {
const result = ProfileFormatter.getTeamRole('admin');
expect(result).toEqual({
text: 'Admin',
badgeClasses: 'bg-purple-500/10 text-purple-400 border-purple-500/30',
});
});
it('should return correct display data for steward role', () => {
const result = ProfileFormatter.getTeamRole('steward');
expect(result).toEqual({
text: 'Steward',
badgeClasses: 'bg-blue-500/10 text-blue-400 border-blue-500/30',
});
});
it('should return correct display data for member role', () => {
const result = ProfileFormatter.getTeamRole('member');
expect(result).toEqual({
text: 'Member',
badgeClasses: 'bg-primary-blue/10 text-primary-blue border-primary-blue/30',
});
});
it('should default to member for unknown role', () => {
const result = ProfileFormatter.getTeamRole('unknown');
expect(result).toEqual({
text: 'Member',
badgeClasses: 'bg-primary-blue/10 text-primary-blue border-primary-blue/30',
});
});
});
});

View File

@@ -0,0 +1,70 @@
import { describe, it, expect } from 'vitest';
import { RaceStatusFormatter } from './RaceStatusFormatter';
describe('RaceStatusFormatter', () => {
describe('getLabel', () => {
it('should return "Scheduled" for scheduled status', () => {
expect(RaceStatusFormatter.getLabel('scheduled')).toBe('Scheduled');
});
it('should return "LIVE" for running status', () => {
expect(RaceStatusFormatter.getLabel('running')).toBe('LIVE');
});
it('should return "Completed" for completed status', () => {
expect(RaceStatusFormatter.getLabel('completed')).toBe('Completed');
});
it('should return "Cancelled" for cancelled status', () => {
expect(RaceStatusFormatter.getLabel('cancelled')).toBe('Cancelled');
});
it('should return uppercase status for unknown status', () => {
expect(RaceStatusFormatter.getLabel('unknown')).toBe('UNKNOWN');
});
});
describe('getVariant', () => {
it('should return "primary" for scheduled status', () => {
expect(RaceStatusFormatter.getVariant('scheduled')).toBe('primary');
});
it('should return "success" for running status', () => {
expect(RaceStatusFormatter.getVariant('running')).toBe('success');
});
it('should return "default" for completed status', () => {
expect(RaceStatusFormatter.getVariant('completed')).toBe('default');
});
it('should return "warning" for cancelled status', () => {
expect(RaceStatusFormatter.getVariant('cancelled')).toBe('warning');
});
it('should return "neutral" for unknown status', () => {
expect(RaceStatusFormatter.getVariant('unknown')).toBe('neutral');
});
});
describe('getIconName', () => {
it('should return "Clock" for scheduled status', () => {
expect(RaceStatusFormatter.getIconName('scheduled')).toBe('Clock');
});
it('should return "PlayCircle" for running status', () => {
expect(RaceStatusFormatter.getIconName('running')).toBe('PlayCircle');
});
it('should return "CheckCircle2" for completed status', () => {
expect(RaceStatusFormatter.getIconName('completed')).toBe('CheckCircle2');
});
it('should return "XCircle" for cancelled status', () => {
expect(RaceStatusFormatter.getIconName('cancelled')).toBe('XCircle');
});
it('should return "HelpCircle" for unknown status', () => {
expect(RaceStatusFormatter.getIconName('unknown')).toBe('HelpCircle');
});
});
});

View File

@@ -0,0 +1,62 @@
import { describe, it, expect } from 'vitest';
import { RatingTrendFormatter } from './RatingTrendFormatter';
describe('RatingTrendFormatter', () => {
describe('getTrend', () => {
it('should return "up" when current rating is higher than previous', () => {
expect(RatingTrendFormatter.getTrend(1200, 1100)).toBe('up');
expect(RatingTrendFormatter.getTrend(1500, 1400)).toBe('up');
});
it('should return "down" when current rating is lower than previous', () => {
expect(RatingTrendFormatter.getTrend(1100, 1200)).toBe('down');
expect(RatingTrendFormatter.getTrend(1400, 1500)).toBe('down');
});
it('should return "same" when current rating equals previous', () => {
expect(RatingTrendFormatter.getTrend(1200, 1200)).toBe('same');
});
it('should return "same" when previous rating is undefined', () => {
expect(RatingTrendFormatter.getTrend(1200, undefined)).toBe('same');
});
it('should return "same" when previous rating is null', () => {
expect(RatingTrendFormatter.getTrend(1200, null)).toBe('same');
});
});
describe('getChangeIndicator', () => {
it('should return "+X" when current rating is higher than previous', () => {
expect(RatingTrendFormatter.getChangeIndicator(1200, 1100)).toBe('+100');
expect(RatingTrendFormatter.getChangeIndicator(1500, 1400)).toBe('+100');
});
it('should return "-X" when current rating is lower than previous', () => {
expect(RatingTrendFormatter.getChangeIndicator(1100, 1200)).toBe('-100');
expect(RatingTrendFormatter.getChangeIndicator(1400, 1500)).toBe('-100');
});
it('should return "0" when current rating equals previous', () => {
expect(RatingTrendFormatter.getChangeIndicator(1200, 1200)).toBe('0');
});
it('should return "0" when previous rating is undefined', () => {
expect(RatingTrendFormatter.getChangeIndicator(1200, undefined)).toBe('0');
});
it('should return "0" when previous rating is null', () => {
expect(RatingTrendFormatter.getChangeIndicator(1200, null)).toBe('0');
});
it('should handle small changes', () => {
expect(RatingTrendFormatter.getChangeIndicator(1201, 1200)).toBe('+1');
expect(RatingTrendFormatter.getChangeIndicator(1199, 1200)).toBe('-1');
});
it('should handle large changes', () => {
expect(RatingTrendFormatter.getChangeIndicator(2000, 1000)).toBe('+1000');
expect(RatingTrendFormatter.getChangeIndicator(1000, 2000)).toBe('-1000');
});
});
});

View File

@@ -0,0 +1,83 @@
import { describe, it, expect } from 'vitest';
import { RelativeTimeFormatter } from './RelativeTimeFormatter';
describe('RelativeTimeFormatter', () => {
describe('format', () => {
it('should return "Just now" for less than 1 hour ago', () => {
const now = new Date();
const thirtyMinutesAgo = new Date(now.getTime() - 30 * 60 * 1000);
const result = RelativeTimeFormatter.format(thirtyMinutesAgo, now);
expect(result).toBe('Just now');
});
it('should return "Xh ago" for less than 24 hours ago', () => {
const now = new Date();
const fiveHoursAgo = new Date(now.getTime() - 5 * 60 * 60 * 1000);
const result = RelativeTimeFormatter.format(fiveHoursAgo, now);
expect(result).toBe('5h ago');
});
it('should return "Yesterday" for exactly 1 day ago', () => {
const now = new Date();
const oneDayAgo = new Date(now.getTime() - 24 * 60 * 60 * 1000);
const result = RelativeTimeFormatter.format(oneDayAgo, now);
expect(result).toBe('Yesterday');
});
it('should return "Xd ago" for less than 7 days ago', () => {
const now = new Date();
const threeDaysAgo = new Date(now.getTime() - 3 * 24 * 60 * 60 * 1000);
const result = RelativeTimeFormatter.format(threeDaysAgo, now);
expect(result).toBe('3d ago');
});
it('should return absolute date for more than 7 days ago', () => {
const now = new Date('2026-01-24T23:49:00Z');
const tenDaysAgo = new Date('2026-01-14T23:49:00Z');
const result = RelativeTimeFormatter.format(tenDaysAgo, now);
expect(result).toBe('Jan 14');
});
it('should return "Starting soon" for less than 1 hour in the future', () => {
const now = new Date();
const thirtyMinutesFromNow = new Date(now.getTime() + 30 * 60 * 1000);
const result = RelativeTimeFormatter.format(thirtyMinutesFromNow, now);
expect(result).toBe('Starting soon');
});
it('should return "In Xh" for less than 24 hours in the future', () => {
const now = new Date();
const fiveHoursFromNow = new Date(now.getTime() + 5 * 60 * 60 * 1000);
const result = RelativeTimeFormatter.format(fiveHoursFromNow, now);
expect(result).toBe('In 5h');
});
it('should return "Tomorrow" for exactly 1 day in the future', () => {
const now = new Date();
const oneDayFromNow = new Date(now.getTime() + 24 * 60 * 60 * 1000);
const result = RelativeTimeFormatter.format(oneDayFromNow, now);
expect(result).toBe('Tomorrow');
});
it('should return "In X days" for less than 7 days in the future', () => {
const now = new Date();
const threeDaysFromNow = new Date(now.getTime() + 3 * 24 * 60 * 60 * 1000);
const result = RelativeTimeFormatter.format(threeDaysFromNow, now);
expect(result).toBe('In 3 days');
});
it('should return absolute date for more than 7 days in the future', () => {
const now = new Date('2026-01-24T23:49:00Z');
const tenDaysFromNow = new Date('2026-02-03T23:49:00Z');
const result = RelativeTimeFormatter.format(tenDaysFromNow, now);
expect(result).toBe('Feb 3');
});
it('should handle string input', () => {
const now = new Date();
const thirtyMinutesAgo = new Date(now.getTime() - 30 * 60 * 1000);
const result = RelativeTimeFormatter.format(thirtyMinutesAgo.toISOString(), now);
expect(result).toBe('Just now');
});
});
});

View File

@@ -0,0 +1,33 @@
import { describe, it, expect } from 'vitest';
import { SeasonStatusFormatter } from './SeasonStatusFormatter';
describe('SeasonStatusFormatter', () => {
describe('getDisplay', () => {
it('should return correct display data for active status', () => {
const result = SeasonStatusFormatter.getDisplay('active');
expect(result).toEqual({
color: 'text-performance-green',
bg: 'bg-performance-green/10',
label: 'Active Season',
});
});
it('should return correct display data for upcoming status', () => {
const result = SeasonStatusFormatter.getDisplay('upcoming');
expect(result).toEqual({
color: 'text-warning-amber',
bg: 'bg-warning-amber/10',
label: 'Starting Soon',
});
});
it('should return correct display data for completed status', () => {
const result = SeasonStatusFormatter.getDisplay('completed');
expect(result).toEqual({
color: 'text-gray-400',
bg: 'bg-gray-400/10',
label: 'Season Ended',
});
});
});
});

View File

@@ -0,0 +1,92 @@
import { describe, it, expect } from 'vitest';
import { SkillLevelFormatter } from './SkillLevelFormatter';
describe('SkillLevelFormatter', () => {
describe('getLabel', () => {
it('should return "Pro" for pro level', () => {
expect(SkillLevelFormatter.getLabel('pro')).toBe('Pro');
});
it('should return "Advanced" for advanced level', () => {
expect(SkillLevelFormatter.getLabel('advanced')).toBe('Advanced');
});
it('should return "Intermediate" for intermediate level', () => {
expect(SkillLevelFormatter.getLabel('intermediate')).toBe('Intermediate');
});
it('should return "Beginner" for beginner level', () => {
expect(SkillLevelFormatter.getLabel('beginner')).toBe('Beginner');
});
it('should return the input for unknown level', () => {
expect(SkillLevelFormatter.getLabel('unknown')).toBe('unknown');
});
});
describe('getColor', () => {
it('should return "text-yellow-400" for pro level', () => {
expect(SkillLevelFormatter.getColor('pro')).toBe('text-yellow-400');
});
it('should return "text-purple-400" for advanced level', () => {
expect(SkillLevelFormatter.getColor('advanced')).toBe('text-purple-400');
});
it('should return "text-primary-blue" for intermediate level', () => {
expect(SkillLevelFormatter.getColor('intermediate')).toBe('text-primary-blue');
});
it('should return "text-green-400" for beginner level', () => {
expect(SkillLevelFormatter.getColor('beginner')).toBe('text-green-400');
});
it('should return "text-gray-400" for unknown level', () => {
expect(SkillLevelFormatter.getColor('unknown')).toBe('text-gray-400');
});
});
describe('getBgColor', () => {
it('should return "bg-yellow-400/10" for pro level', () => {
expect(SkillLevelFormatter.getBgColor('pro')).toBe('bg-yellow-400/10');
});
it('should return "bg-purple-400/10" for advanced level', () => {
expect(SkillLevelFormatter.getBgColor('advanced')).toBe('bg-purple-400/10');
});
it('should return "bg-primary-blue/10" for intermediate level', () => {
expect(SkillLevelFormatter.getBgColor('intermediate')).toBe('bg-primary-blue/10');
});
it('should return "bg-green-400/10" for beginner level', () => {
expect(SkillLevelFormatter.getBgColor('beginner')).toBe('bg-green-400/10');
});
it('should return "bg-gray-400/10" for unknown level', () => {
expect(SkillLevelFormatter.getBgColor('unknown')).toBe('bg-gray-400/10');
});
});
describe('getBorderColor', () => {
it('should return "border-yellow-400/30" for pro level', () => {
expect(SkillLevelFormatter.getBorderColor('pro')).toBe('border-yellow-400/30');
});
it('should return "border-purple-400/30" for advanced level', () => {
expect(SkillLevelFormatter.getBorderColor('advanced')).toBe('border-purple-400/30');
});
it('should return "border-primary-blue/30" for intermediate level', () => {
expect(SkillLevelFormatter.getBorderColor('intermediate')).toBe('border-primary-blue/30');
});
it('should return "border-green-400/30" for beginner level', () => {
expect(SkillLevelFormatter.getBorderColor('beginner')).toBe('border-green-400/30');
});
it('should return "border-gray-400/30" for unknown level', () => {
expect(SkillLevelFormatter.getBorderColor('unknown')).toBe('border-gray-400/30');
});
});
});

View File

@@ -0,0 +1,31 @@
import { describe, it, expect } from 'vitest';
import { SkillLevelIconFormatter } from './SkillLevelIconFormatter';
describe('SkillLevelIconFormatter', () => {
describe('getIcon', () => {
it('should return "🥉" for beginner level', () => {
expect(SkillLevelIconFormatter.getIcon('beginner')).toBe('🥉');
});
it('should return "🥈" for intermediate level', () => {
expect(SkillLevelIconFormatter.getIcon('intermediate')).toBe('🥈');
});
it('should return "🥇" for advanced level', () => {
expect(SkillLevelIconFormatter.getIcon('advanced')).toBe('🥇');
});
it('should return "👑" for expert level', () => {
expect(SkillLevelIconFormatter.getIcon('expert')).toBe('👑');
});
it('should return "🏁" for unknown level', () => {
expect(SkillLevelIconFormatter.getIcon('unknown')).toBe('🏁');
});
it('should return "🏁" for any other level', () => {
expect(SkillLevelIconFormatter.getIcon('pro')).toBe('🏁');
expect(SkillLevelIconFormatter.getIcon('master')).toBe('🏁');
});
});
});

View File

@@ -0,0 +1,62 @@
import { describe, it, expect } from 'vitest';
import { StatusFormatter } from './StatusFormatter';
describe('StatusFormatter', () => {
describe('transactionStatus', () => {
it('should format "paid" correctly', () => {
expect(StatusFormatter.transactionStatus('paid')).toBe('Paid');
});
it('should format "pending" correctly', () => {
expect(StatusFormatter.transactionStatus('pending')).toBe('Pending');
});
it('should format "overdue" correctly', () => {
expect(StatusFormatter.transactionStatus('overdue')).toBe('Overdue');
});
it('should format "failed" correctly', () => {
expect(StatusFormatter.transactionStatus('failed')).toBe('Failed');
});
it('should handle unknown status', () => {
expect(StatusFormatter.transactionStatus('unknown')).toBe('unknown');
});
});
describe('raceStatus', () => {
it('should format "scheduled" correctly', () => {
expect(StatusFormatter.raceStatus('scheduled')).toBe('Scheduled');
});
it('should format "running" correctly', () => {
expect(StatusFormatter.raceStatus('running')).toBe('Live');
});
it('should format "completed" correctly', () => {
expect(StatusFormatter.raceStatus('completed')).toBe('Completed');
});
it('should handle unknown status', () => {
expect(StatusFormatter.raceStatus('unknown')).toBe('unknown');
});
});
describe('protestStatus', () => {
it('should format "pending" correctly', () => {
expect(StatusFormatter.protestStatus('pending')).toBe('Pending');
});
it('should format "under_review" correctly', () => {
expect(StatusFormatter.protestStatus('under_review')).toBe('Under Review');
});
it('should format "resolved" correctly', () => {
expect(StatusFormatter.protestStatus('resolved')).toBe('Resolved');
});
it('should handle unknown status', () => {
expect(StatusFormatter.protestStatus('unknown')).toBe('unknown');
});
});
});

View File

@@ -0,0 +1,14 @@
import { describe, it, expect } from 'vitest';
import { TeamCreationStatusFormatter } from './TeamCreationStatusFormatter';
describe('TeamCreationStatusFormatter', () => {
describe('statusMessage', () => {
it('should return success message when team created successfully', () => {
expect(TeamCreationStatusFormatter.statusMessage(true)).toBe('Team created successfully!');
});
it('should return failure message when team creation failed', () => {
expect(TeamCreationStatusFormatter.statusMessage(false)).toBe('Failed to create team.');
});
});
});

View File

@@ -0,0 +1,41 @@
import { describe, it, expect } from 'vitest';
import { TimeFormatter } from './TimeFormatter';
describe('TimeFormatter', () => {
describe('timeAgo', () => {
it('should return "Just now" for less than 1 minute ago', () => {
const now = new Date();
const thirtySecondsAgo = new Date(now.getTime() - 30 * 1000);
const result = TimeFormatter.timeAgo(thirtySecondsAgo);
expect(result).toBe('Just now');
});
it('should return "X min ago" for less than 1 hour ago', () => {
const now = new Date();
const thirtyMinutesAgo = new Date(now.getTime() - 30 * 60 * 1000);
const result = TimeFormatter.timeAgo(thirtyMinutesAgo);
expect(result).toBe('30 min ago');
});
it('should return "X h ago" for less than 24 hours ago', () => {
const now = new Date();
const fiveHoursAgo = new Date(now.getTime() - 5 * 60 * 60 * 1000);
const result = TimeFormatter.timeAgo(fiveHoursAgo);
expect(result).toBe('5 h ago');
});
it('should return "X d ago" for 24 hours or more ago', () => {
const now = new Date();
const twoDaysAgo = new Date(now.getTime() - 2 * 24 * 60 * 60 * 1000);
const result = TimeFormatter.timeAgo(twoDaysAgo);
expect(result).toBe('2 d ago');
});
it('should handle string input', () => {
const now = new Date();
const thirtyMinutesAgo = new Date(now.getTime() - 30 * 60 * 1000);
const result = TimeFormatter.timeAgo(thirtyMinutesAgo.toISOString());
expect(result).toBe('30 min ago');
});
});
});

View File

@@ -0,0 +1,28 @@
import { describe, it, expect } from 'vitest';
import { TransactionTypeFormatter } from './TransactionTypeFormatter';
describe('TransactionTypeFormatter', () => {
describe('format', () => {
it('should capitalize the first letter and lowercase the rest', () => {
expect(TransactionTypeFormatter.format('deposit')).toBe('Deposit');
expect(TransactionTypeFormatter.format('withdrawal')).toBe('Withdrawal');
expect(TransactionTypeFormatter.format('refund')).toBe('Refund');
});
it('should handle single character strings', () => {
expect(TransactionTypeFormatter.format('a')).toBe('A');
});
it('should handle already capitalized strings', () => {
expect(TransactionTypeFormatter.format('Deposit')).toBe('Deposit');
});
it('should handle all uppercase strings', () => {
expect(TransactionTypeFormatter.format('DEPOSIT')).toBe('Deposit');
});
it('should handle empty string', () => {
expect(TransactionTypeFormatter.format('')).toBe('');
});
});
});

View File

@@ -0,0 +1,26 @@
import { describe, it, expect } from 'vitest';
import { UserRoleFormatter } from './UserRoleFormatter';
describe('UserRoleFormatter', () => {
describe('roleLabel', () => {
it('should format "owner" correctly', () => {
expect(UserRoleFormatter.roleLabel('owner')).toBe('Owner');
});
it('should format "admin" correctly', () => {
expect(UserRoleFormatter.roleLabel('admin')).toBe('Admin');
});
it('should format "user" correctly', () => {
expect(UserRoleFormatter.roleLabel('user')).toBe('User');
});
it('should handle unknown roles', () => {
expect(UserRoleFormatter.roleLabel('unknown')).toBe('unknown');
});
it('should handle empty string', () => {
expect(UserRoleFormatter.roleLabel('')).toBe('');
});
});
});

View File

@@ -0,0 +1,94 @@
import { describe, it, expect } from 'vitest';
import { UserStatusFormatter } from './UserStatusFormatter';
describe('UserStatusFormatter', () => {
describe('statusLabel', () => {
it('should format "active" correctly', () => {
expect(UserStatusFormatter.statusLabel('active')).toBe('Active');
});
it('should format "suspended" correctly', () => {
expect(UserStatusFormatter.statusLabel('suspended')).toBe('Suspended');
});
it('should format "deleted" correctly', () => {
expect(UserStatusFormatter.statusLabel('deleted')).toBe('Deleted');
});
it('should handle unknown status', () => {
expect(UserStatusFormatter.statusLabel('unknown')).toBe('unknown');
});
});
describe('statusVariant', () => {
it('should return "performance-green" for active status', () => {
expect(UserStatusFormatter.statusVariant('active')).toBe('performance-green');
});
it('should return "yellow-500" for suspended status', () => {
expect(UserStatusFormatter.statusVariant('suspended')).toBe('yellow-500');
});
it('should return "racing-red" for deleted status', () => {
expect(UserStatusFormatter.statusVariant('deleted')).toBe('racing-red');
});
it('should return "gray-500" for unknown status', () => {
expect(UserStatusFormatter.statusVariant('unknown')).toBe('gray-500');
});
});
describe('canSuspend', () => {
it('should return true for active status', () => {
expect(UserStatusFormatter.canSuspend('active')).toBe(true);
});
it('should return false for suspended status', () => {
expect(UserStatusFormatter.canSuspend('suspended')).toBe(false);
});
it('should return false for deleted status', () => {
expect(UserStatusFormatter.canSuspend('deleted')).toBe(false);
});
it('should return false for unknown status', () => {
expect(UserStatusFormatter.canSuspend('unknown')).toBe(false);
});
});
describe('canActivate', () => {
it('should return false for active status', () => {
expect(UserStatusFormatter.canActivate('active')).toBe(false);
});
it('should return true for suspended status', () => {
expect(UserStatusFormatter.canActivate('suspended')).toBe(true);
});
it('should return false for deleted status', () => {
expect(UserStatusFormatter.canActivate('deleted')).toBe(false);
});
it('should return false for unknown status', () => {
expect(UserStatusFormatter.canActivate('unknown')).toBe(false);
});
});
describe('canDelete', () => {
it('should return true for active status', () => {
expect(UserStatusFormatter.canDelete('active')).toBe(true);
});
it('should return true for suspended status', () => {
expect(UserStatusFormatter.canDelete('suspended')).toBe(true);
});
it('should return false for deleted status', () => {
expect(UserStatusFormatter.canDelete('deleted')).toBe(false);
});
it('should return true for unknown status', () => {
expect(UserStatusFormatter.canDelete('unknown')).toBe(true);
});
});
});

View File

@@ -0,0 +1,54 @@
import { describe, it, expect } from 'vitest';
import { WinRateFormatter } from './WinRateFormatter';
describe('WinRateFormatter', () => {
describe('calculate', () => {
it('should return "0.0" when no races completed', () => {
expect(WinRateFormatter.calculate(0, 0)).toBe('0.0');
});
it('should calculate win rate correctly', () => {
expect(WinRateFormatter.calculate(10, 5)).toBe('50.0');
expect(WinRateFormatter.calculate(100, 25)).toBe('25.0');
expect(WinRateFormatter.calculate(100, 75)).toBe('75.0');
});
it('should handle 100% win rate', () => {
expect(WinRateFormatter.calculate(10, 10)).toBe('100.0');
});
it('should handle 0% win rate', () => {
expect(WinRateFormatter.calculate(10, 0)).toBe('0.0');
});
it('should handle decimal win rates', () => {
expect(WinRateFormatter.calculate(10, 3)).toBe('30.0');
expect(WinRateFormatter.calculate(10, 7)).toBe('70.0');
});
});
describe('format', () => {
it('should format rate with 1 decimal place and % sign', () => {
expect(WinRateFormatter.format(50.0)).toBe('50.0%');
expect(WinRateFormatter.format(25.5)).toBe('25.5%');
expect(WinRateFormatter.format(100.0)).toBe('100.0%');
});
it('should handle null rate', () => {
expect(WinRateFormatter.format(null)).toBe('0.0%');
});
it('should handle undefined rate', () => {
expect(WinRateFormatter.format(undefined)).toBe('0.0%');
});
it('should handle zero rate', () => {
expect(WinRateFormatter.format(0)).toBe('0.0%');
});
it('should handle decimal rates', () => {
expect(WinRateFormatter.format(12.34)).toBe('12.3%');
expect(WinRateFormatter.format(99.99)).toBe('100.0%');
});
});
});