add unit test suite: 80 tests across utils, api, auth, clients, events, emails

- Vitest + React Testing Library + jsdom setup
- utils.test.ts: cn, formatDate, formatFullDate, getInitials, getRelativeTime, getDaysUntil
- api.test.ts: token management, auth, CRUD for clients/events/emails, admin, error handling
- auth.test.ts: login, logout, checkSession, setUser
- clients.test.ts: fetch, create, update, delete, markContacted, filters
- events.test.ts: fetch, create, update, delete, syncAll
- emails.test.ts: fetch, generate, update, send, delete
This commit is contained in:
2026-01-28 22:12:38 +00:00
parent c838a714d2
commit b6de50ba5e
10 changed files with 2063 additions and 3 deletions

140
src/lib/utils.test.ts Normal file
View File

@@ -0,0 +1,140 @@
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
import { cn, formatDate, formatFullDate, getInitials, getRelativeTime, getDaysUntil } from './utils';
describe('cn', () => {
it('merges class names', () => {
expect(cn('foo', 'bar')).toBe('foo bar');
});
it('handles conditional classes', () => {
expect(cn('base', false && 'hidden', 'visible')).toBe('base visible');
});
it('merges tailwind conflicts', () => {
expect(cn('px-4', 'px-2')).toBe('px-2');
});
});
describe('formatDate', () => {
beforeEach(() => {
vi.useFakeTimers();
vi.setSystemTime(new Date('2026-01-28T12:00:00Z'));
});
afterEach(() => {
vi.useRealTimers();
});
it('returns empty string for undefined', () => {
expect(formatDate(undefined)).toBe('');
});
it('returns "Today" for today\'s date', () => {
expect(formatDate('2026-01-28')).toBe('Today');
});
it('returns "Tomorrow" for tomorrow\'s date', () => {
expect(formatDate('2026-01-29')).toBe('Tomorrow');
});
it('returns "Yesterday" for yesterday\'s date', () => {
expect(formatDate('2026-01-27')).toBe('Yesterday');
});
it('returns short format for same year', () => {
const result = formatDate('2026-03-15');
expect(result).toBe('Mar 15');
});
it('returns full format for different year', () => {
const result = formatDate('2025-03-15');
expect(result).toBe('Mar 15, 2025');
});
});
describe('formatFullDate', () => {
it('returns empty string for undefined', () => {
expect(formatFullDate(undefined)).toBe('');
});
it('returns full formatted date', () => {
const result = formatFullDate('2026-01-28');
expect(result).toContain('January');
expect(result).toContain('28');
expect(result).toContain('2026');
});
});
describe('getInitials', () => {
it('returns initials from first and last name', () => {
expect(getInitials('John', 'Doe')).toBe('JD');
});
it('handles empty strings', () => {
expect(getInitials('', '')).toBe('');
});
it('handles single name', () => {
expect(getInitials('Alice', '')).toBe('A');
});
});
describe('getRelativeTime', () => {
beforeEach(() => {
vi.useFakeTimers();
vi.setSystemTime(new Date('2026-01-28T12:00:00Z'));
});
afterEach(() => {
vi.useRealTimers();
});
it('returns "Never" for undefined', () => {
expect(getRelativeTime(undefined)).toBe('Never');
});
it('returns "Today" for today', () => {
expect(getRelativeTime('2026-01-28T10:00:00Z')).toBe('Today');
});
it('returns "Yesterday" for yesterday', () => {
expect(getRelativeTime('2026-01-27T10:00:00Z')).toBe('Yesterday');
});
it('returns days ago for recent dates', () => {
expect(getRelativeTime('2026-01-25T10:00:00Z')).toBe('3 days ago');
});
it('returns weeks ago', () => {
expect(getRelativeTime('2026-01-14T10:00:00Z')).toBe('2 weeks ago');
});
it('returns months ago', () => {
expect(getRelativeTime('2025-11-28T10:00:00Z')).toBe('2 months ago');
});
});
describe('getDaysUntil', () => {
beforeEach(() => {
vi.useFakeTimers();
vi.setSystemTime(new Date('2026-01-28T12:00:00Z'));
});
afterEach(() => {
vi.useRealTimers();
});
it('returns 0 for today', () => {
expect(getDaysUntil('2026-01-28')).toBe(0);
});
it('returns positive for future dates', () => {
expect(getDaysUntil('2026-02-01')).toBe(4);
});
it('projects past dates to next occurrence', () => {
// Jan 15 already passed, should project to next year
const days = getDaysUntil('2025-01-15');
expect(days).toBeGreaterThan(300); // ~352 days to Jan 15 2027
});
});