refactor: move lib-root files to lib/shared/ and finalize domain structure
- Move api.server.ts, errors.ts, types.ts, utils.ts, relativeTime.ts to lib/shared/ - Move person relationship components to lib/person/relationship/ - Move Stammbaum components to lib/person/genealogy/ - Move HelpPopover to lib/shared/primitives/ - Update all import paths across routes, specs, and lib files - Update vi.mock() paths in server-project test files - Remove now-empty legacy directories (components/, hooks/, server/, etc.) - Update vite.config.ts coverage include paths for new structure - Update frontend/CLAUDE.md to reflect domain-based lib/ layout Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
69
frontend/src/lib/shared/relativeTime.spec.ts
Normal file
69
frontend/src/lib/shared/relativeTime.spec.ts
Normal file
@@ -0,0 +1,69 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { relativeTimeDe, relativeYearsDe } from './relativeTime';
|
||||
|
||||
const NOW = new Date('2026-04-20T12:00:00Z');
|
||||
|
||||
describe('relativeTimeDe', () => {
|
||||
it('returns minutes for a gap under one hour', () => {
|
||||
const from = new Date('2026-04-20T11:58:00Z');
|
||||
expect(relativeTimeDe(from, NOW)).toContain('2');
|
||||
expect(relativeTimeDe(from, NOW)).toMatch(/Minute/i);
|
||||
});
|
||||
|
||||
it('returns hours for a gap between 1 and 24 hours', () => {
|
||||
const from = new Date('2026-04-20T09:00:00Z');
|
||||
expect(relativeTimeDe(from, NOW)).toContain('3');
|
||||
expect(relativeTimeDe(from, NOW)).toMatch(/Stunde/i);
|
||||
});
|
||||
|
||||
it('returns days for a gap of 24 hours or more', () => {
|
||||
const from = new Date('2026-04-18T12:00:00Z');
|
||||
expect(relativeTimeDe(from, NOW)).toContain('2');
|
||||
expect(relativeTimeDe(from, NOW)).toMatch(/Tag/i);
|
||||
});
|
||||
|
||||
it('rounds minutes to the nearest whole number', () => {
|
||||
const from = new Date('2026-04-20T11:58:20Z');
|
||||
expect(relativeTimeDe(from, NOW)).toContain('2');
|
||||
});
|
||||
|
||||
it('handles zero gap as 0 minutes', () => {
|
||||
expect(relativeTimeDe(NOW, NOW)).toMatch(/0/);
|
||||
expect(relativeTimeDe(NOW, NOW)).toMatch(/Minute/i);
|
||||
});
|
||||
|
||||
it('falls back to 0 minutes when the input Date is invalid', () => {
|
||||
const invalid = new Date('not-a-real-date');
|
||||
// Never crash the UI if the backend ever ships a malformed uploadedAt.
|
||||
expect(relativeTimeDe(invalid, NOW)).toMatch(/0/);
|
||||
expect(relativeTimeDe(invalid, NOW)).toMatch(/Minute/i);
|
||||
});
|
||||
});
|
||||
|
||||
describe('relativeYearsDe', () => {
|
||||
it('returns singular "vor 1 Jahr" for exactly one whole year ago', () => {
|
||||
const from = new Date('2025-04-20T12:00:00Z');
|
||||
expect(relativeYearsDe(from, NOW)).toBe('vor 1 Jahr');
|
||||
});
|
||||
|
||||
it('returns plural "vor N Jahren" for more than one year', () => {
|
||||
const from = new Date('1940-04-20T12:00:00Z');
|
||||
expect(relativeYearsDe(from, NOW)).toBe('vor 86 Jahren');
|
||||
});
|
||||
|
||||
it('floors a partial year down (eleven months ago = 0 years)', () => {
|
||||
const from = new Date('2025-06-01T00:00:00Z');
|
||||
// We show "vor weniger als 1 Jahr" rather than rounding up to 1.
|
||||
expect(relativeYearsDe(from, NOW)).toBe('vor weniger als 1 Jahr');
|
||||
});
|
||||
|
||||
it('returns empty string when the input Date is invalid', () => {
|
||||
const invalid = new Date('not-a-real-date');
|
||||
expect(relativeYearsDe(invalid, NOW)).toBe('');
|
||||
});
|
||||
|
||||
it('returns empty string for future dates', () => {
|
||||
const future = new Date('2030-01-01T00:00:00Z');
|
||||
expect(relativeYearsDe(future, NOW)).toBe('');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user