church-website/src/utils/recurrenceDescription.test.ts
Benno Tielen 7fed715d6b
Some checks failed
Deploy / deploy (push) Has been cancelled
fix: timezone
2026-04-24 12:10:34 +02:00

94 lines
3.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { describe, it, expect } from 'vitest'
import { describeRecurrence } from './recurrenceDescription'
// All test dates fall inside EU DST (Mar 29 Oct 25, 2026), so Berlin is UTC+2.
// We spell the UTC instant explicitly so tests are timezone-independent.
const tuesdayFirstOfMonth = '2026-04-07T16:30:00.000Z' // Tue 2026-04-07 18:30 Berlin
const monday2ndOfMonth = '2026-04-13T16:30:00.000Z' // Mon 2026-04-13 18:30 Berlin
const sunday13thOfMonth = '2026-09-13T08:00:00.000Z' // Sun 2026-09-13 10:00 Berlin
const monday5thOfMonth = '2026-03-30T18:00:00.000Z' // Mon 2026-03-30 20:00 Berlin
describe('describeRecurrence', () => {
it('returns undefined for none / missing recurrenceType', () => {
expect(describeRecurrence({ recurrenceType: 'none', date: monday2ndOfMonth })).toBeUndefined()
expect(describeRecurrence({ recurrenceType: null, date: monday2ndOfMonth } as never)).toBeUndefined()
})
it('describes daily with time from event.date', () => {
const dateAt10 = '2026-04-13T08:00:00.000Z' // 10:00 Berlin
expect(describeRecurrence({ recurrenceType: 'daily', date: dateAt10 })).toBe(
'Täglich um 10:00 Uhr',
)
})
it('describes weekly using the weekday and time of event.date', () => {
expect(describeRecurrence({ recurrenceType: 'weekly', date: tuesdayFirstOfMonth })).toBe(
'Jeden Dienstag um 18:30 Uhr',
)
})
it('describes biweekly', () => {
expect(describeRecurrence({ recurrenceType: 'biweekly', date: monday2ndOfMonth })).toBe(
'Alle 2 Wochen, Montag um 18:30 Uhr',
)
})
it('describes monthlyByDate using the day-of-month from event.date', () => {
expect(describeRecurrence({ recurrenceType: 'monthlyByDate', date: sunday13thOfMonth })).toBe(
'Monatlich am 13. um 10:00 Uhr',
)
})
it('describes monthlyByWeekday using the Nth weekday from event.date', () => {
expect(describeRecurrence({ recurrenceType: 'monthlyByWeekday', date: monday2ndOfMonth })).toBe(
'Monatlich am 2. Montag um 18:30 Uhr',
)
expect(describeRecurrence({ recurrenceType: 'monthlyByWeekday', date: tuesdayFirstOfMonth })).toBe(
'Monatlich am 1. Dienstag um 18:30 Uhr',
)
})
it('clamps a 5th-occurrence weekday to the 4th (matches generator)', () => {
expect(describeRecurrence({ recurrenceType: 'monthlyByWeekday', date: monday5thOfMonth })).toBe(
'Monatlich am 4. Montag um 20:00 Uhr',
)
})
it('joins multiple custom rules and appends time once', () => {
const desc = describeRecurrence({
recurrenceType: 'custom',
date: monday2ndOfMonth,
recurrenceRules: [
{ frequency: 'monthlyByWeekday', weekday: 'tuesday', weekOfMonth: 'third' },
{ frequency: 'monthlyByWeekday', weekday: 'thursday', weekOfMonth: 'fourth' },
],
})
expect(desc).toBe(
'Am 3. Dienstag jedes Monats · Am 4. Donnerstag jedes Monats um 18:30 Uhr',
)
})
it('skips incomplete custom rules and returns Benutzerdefiniert if none are valid', () => {
expect(
describeRecurrence({
recurrenceType: 'custom',
date: monday2ndOfMonth,
recurrenceRules: [
// missing weekOfMonth
{ frequency: 'monthlyByWeekday', weekday: 'tuesday' },
],
}),
).toBe('Benutzerdefiniert um 18:30 Uhr')
})
it('omits the time clause when event.date is missing', () => {
expect(describeRecurrence({ recurrenceType: 'daily', date: null } as never)).toBe('Täglich')
})
it('pads minutes correctly (08:05, not 8:5)', () => {
const dateEarly = '2026-04-13T06:05:00.000Z' // 08:05 Berlin
expect(describeRecurrence({ recurrenceType: 'daily', date: dateEarly })).toBe(
'Täglich um 08:05 Uhr',
)
})
})