thats-me/frontend/test/vitest/calendar-date.spec.js
Kevin Adametz 83c6c5813d Frontend: Offline-Warteschlange, PWA, Event-Panel und Markenauftritt
Offline
- Alle Schreibzugriffe von API-Nutzern laufen über eine Warteschlange in
  IndexedDB (services/syncQueue.js): FIFO, zusammengefasste Updates,
  Wiederholung bei Netz/Sichtbarkeit/Backoff, 4xx wird als Fehler gemeldet.
- Medien-Uploads liegen mit Bytes in der Queue, erscheinen sofort mit
  Marker und werden nach dem Upload durch das Server-Objekt ersetzt.
- PWA-Modus mit Service Worker für die App-Hülle; API nie gecacht.
  npm run build erzeugt dist/pwa.
- Speicherzustand im Panel: ausstehend / Fehler mit Wiederholen-Knopf,
  Verbindungsanzeige im Header.

Event
- Event entsteht erst mit dem ersten Eintrag; jede Löschung fragt nach.
- Key Image als 4:3-Rahmen, Galerie mit Video, mehrere Sprachnotizen mit
  Notiz, Live-Pegel beim Aufnehmen, WAV-Umwandlung für lokale Aufnahmen.
- Neue Felder: Zeitraum, Kategorie, Personen, Meilenstein; Stimmung als
  kompakte Zeile mit ausklappbarer Punktfarbe.

Oberfläche
- Untere Leiste: Darstellung und Zoom links, Jahres-Pille mittig, Plus rechts.
- Logos und Goldpalette, Login neu, zehn Wellen-Presets mit Vorschau,
  Hintergrundbilder als Kacheln, Kontomenü und Einstellungen bereinigt,
  Escape schließt Ebenen, größere Touch-Ziele.
- Alten Sync-Service und ungenutzte Legacy-Seiten entfernt.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-25 07:00:35 +00:00

78 lines
2.7 KiB
JavaScript

import { describe, expect, it } from 'vitest'
import {
calendarMonthIndex,
calendarYear,
compareCalendarDates,
formatCalendarDate,
parseCalendarDate
} from 'src/utils/calendarDate'
/**
* The process timezone is fixed at start-up, so a single run cannot cover
* several zones. Instead these tests state the invariant directly: whatever
* zone the runner is in, the parsed day, month and year must equal the
* digits in the string. `npm run test:tz` runs the suite under the zones
* that used to shift the date.
*/
describe('calendar dates are parsed as calendar dates, not as UTC instants (A18)', () => {
it.each([
['2026-01-01', 2026, 0, 1],
['2025-12-31', 2025, 11, 31],
['2014-08-12', 2014, 7, 12],
['2000-02-29', 2000, 1, 29]
])('%s keeps its year, month and day in %s', (value, year, month, day) => {
const date = parseCalendarDate(value)
expect(date.getFullYear()).toBe(year)
expect(date.getMonth()).toBe(month)
expect(date.getDate()).toBe(day)
})
it('exposes the same year and month index used by the timeline labels', () => {
expect(calendarYear('2026-01-01')).toBe(2026)
expect(calendarMonthIndex('2026-01-01')).toBe(0)
})
it('formats without shifting into the previous day', () => {
expect(formatCalendarDate('2026-01-01')).toBe('01. Januar 2026')
})
it('ignores a trailing time portion instead of letting it move the day', () => {
expect(calendarYear('2026-01-01T00:00:00.000Z')).toBe(2026)
expect(calendarMonthIndex('2026-01-01T00:00:00.000Z')).toBe(0)
})
it('returns null for values that are not calendar dates', () => {
expect(parseCalendarDate('')).toBeNull()
expect(parseCalendarDate(null)).toBeNull()
expect(parseCalendarDate('gestern')).toBeNull()
expect(calendarYear(undefined)).toBeNull()
})
it('leaves unparseable input untouched when formatting', () => {
expect(formatCalendarDate('gestern')).toBe('gestern')
})
it('sorts chronologically without allocating a Date', () => {
const dates = ['2026-01-01', '2014-08-12', '2025-12-31', '2025-12-30']
expect([...dates].sort(compareCalendarDates)).toEqual([
'2014-08-12', '2025-12-30', '2025-12-31', '2026-01-01'
])
expect(compareCalendarDates('2025-12-31', '2026-01-01')).toBeLessThan(0)
expect(compareCalendarDates('2026-01-01', '2026-01-01')).toBe(0)
})
it('documents the old behaviour it replaces', () => {
// This is the bug: in any zone west of UTC, the local getters of a
// UTC-parsed instant point at the day before.
const offsetMinutes = new Date('2026-01-01').getTimezoneOffset()
const oldDay = new Date('2026-01-01').getDate()
if (offsetMinutes > 0) {
expect(oldDay).toBe(31)
}
expect(parseCalendarDate('2026-01-01').getDate()).toBe(1)
})
})