The app becomes a Rails 8 application; the Vue frontend moves to app/frontend and is served through vite_rails. - Without an account documents stay in the browser (IndexedDB). Sign-in is by magic link or the 6-digit code from the same mail; afterwards local documents can be uploaded into the account. - Server documents (/d/<id>) with versioned saves and a single-editor lock per browser tab; others see them read-only and follow by polling. - Sharing via link (works without an account) and via e-mail invitation, roles viewer/editor; the owner manages links and people. - Store gains a read-only mode that blocks all content changes. - Solid Queue, Cache and Cable share the one PostgreSQL database. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
49 lines
2.0 KiB
TypeScript
49 lines
2.0 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
import { dateToSerial, timeSerial } from '../../engine';
|
|
import { formatValue } from '../format';
|
|
|
|
describe('formatValue: date/time', () => {
|
|
const day = dateToSerial(2026, 9, 2); // a Wednesday
|
|
const noon = timeSerial(12, 0, 0);
|
|
const dayAtNoon = day + noon;
|
|
|
|
it('renders a date per locale', () => {
|
|
expect(formatValue(day, 'de-DE', 'date')).toBe('02.09.2026');
|
|
expect(formatValue(day, 'en-US', 'date')).toBe('09/02/2026');
|
|
expect(formatValue(day, 'plain', 'date')).toBe('2026-09-02');
|
|
});
|
|
|
|
it('renders a time per locale', () => {
|
|
expect(formatValue(noon, 'de-DE', 'time')).toBe('12:00');
|
|
expect(formatValue(noon, 'plain', 'time')).toBe('12:00');
|
|
});
|
|
|
|
it('renders date + time together', () => {
|
|
expect(formatValue(dayAtNoon, 'de-DE', 'datetime')).toBe('02.09.2026 12:00');
|
|
expect(formatValue(dayAtNoon, 'plain', 'datetime')).toBe('2026-09-02 12:00');
|
|
});
|
|
|
|
it('date + time shows only the time for a bare time of day (no 1899 date)', () => {
|
|
expect(formatValue(timeSerial(12, 23, 0), 'de-DE', 'datetime')).toBe('12:23');
|
|
});
|
|
|
|
it('"duration" keeps counting hours past 24', () => {
|
|
expect(formatValue(37.5 / 24, 'de-DE', 'duration')).toBe('37:30');
|
|
expect(formatValue(timeSerial(8, 5, 0), 'de-DE', 'duration')).toBe('08:05');
|
|
expect(formatValue((100 * 3600 + 30) / 86400, 'de-DE', 'duration')).toBe('100:00:30');
|
|
expect(formatValue(-1.5 / 24, 'de-DE', 'duration')).toBe('-01:30');
|
|
expect(formatValue(0, 'de-DE', 'duration')).toBe('00:00');
|
|
});
|
|
|
|
it('empty cell / error still short-circuit before any date formatting', () => {
|
|
expect(formatValue(null, 'de-DE', 'date')).toBe('');
|
|
});
|
|
|
|
it('"dateiso" renders YYYY-MM-DD regardless of the active locale', () => {
|
|
expect(formatValue(day, 'de-DE', 'dateiso')).toBe('2026-09-02');
|
|
expect(formatValue(day, 'en-US', 'dateiso')).toBe('2026-09-02');
|
|
expect(formatValue(day, 'fr-FR', 'dateiso')).toBe('2026-09-02');
|
|
expect(formatValue(day, 'plain', 'dateiso')).toBe('2026-09-02');
|
|
});
|
|
});
|