Files
vu/tests/calendar/immaculate-heart-of-mary.test.ts
will 5e79fb4edf
Deploy / deploy (push) Successful in 1m21s
Generalize non-Sunday movable feasts into one Easter-offset resolver
The bespoke applyImmaculateHeart function (following the applyMarianSaturday/
applyChristTheKing precedent of one hand-written override function per
feast) doesn't scale: several more feasts are planned that all reduce to
"weekday N days from Easter Sunday" (Ember/Rogation days, more
Sacred-Heart-family Marian devotions, St. Joseph's pre-1955 Eastertide
feast, Lenten Friday Passion devotions), and one-off functions invite
subtle ordering bugs -- applyImmaculateHeart had to be sequenced after
applyMarianSaturday specifically or it would have been silently clobbered.

Replaced with calendar/movable-feasts.ts's generic applyMovableFeasts,
which scans calendar/temporal-feasts.ts's existing per-feast YAML records
for a new optional `easterOffset` field. Adding the next movable feast is
now a new data/calendar/temporal-feasts/<id>.yml file with `rank` and
`easterOffset` set, not a new TypeScript function. Same rank-compared,
commemorate-the-loser semantics as before, just centralized instead of
duplicated per feast.

christ-the-king, marian-saturday, and christmas-octave-sunday stay as
their own functions -- they're structurally different rules (a fixed
month-position search, a date-less fallback default, and a fixed-date-
range Sunday search, respectively), not Easter offsets, so force-fitting
them into this table wouldn't actually simplify anything.

No behavior change -- the existing Immaculate Heart of Mary test suite
passes unchanged through the new generic path.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VZSAgRi4QE4XRTqVto93zA
2026-08-22 06:33:15 -04:00

38 lines
2.1 KiB
TypeScript

import { describe, expect, it } from 'vitest';
import { resolveDay } from '../../src/calendar';
import { getDayCollect, getBenedictusAntiphon, getMagnificatAntiphon } from '../../src/hours/resolve-common';
// Relocated off the fixed Aug 22 date (2026-08-22 user decision, see
// TODO.md) -- that date collided outright with the Assumption's own
// octave-closing day. Moved to Easter+69: the Saturday after the Feast of
// the Sacred Heart (Easter+68, always a Friday), the feast's own real
// diocesan date from 1914 until Pius XII's 1944 fixed-date decree, and
// also the date the 1969 reform returned to.
describe('Immaculate Heart of Mary (calendar/movable-feasts.ts, generic Easter-offset resolver)', () => {
it('wins outright on Easter+69, with real content resolved via the temporal propers store', () => {
const day = resolveDay('2026-06-13'); // Easter 2026-04-05 + 69 days
expect(day.winner).toEqual({ kind: 'temporal', id: 'immaculate-heart-of-mary' });
expect(getDayCollect(day).status.en).toBe('verified');
expect(getBenedictusAntiphon(day).status.en).toBe('verified');
expect(getMagnificatAntiphon(day).status.en).toBe('verified');
});
it('correctly finds Easter+69 in a different year (early Easter)', () => {
const day = resolveDay('2027-06-05'); // Easter 2027-03-28 + 69 days
expect(day.winner).toEqual({ kind: 'temporal', id: 'immaculate-heart-of-mary' });
});
it('does not apply on the Saturday before or after', () => {
const before = resolveDay('2026-06-06');
const after = resolveDay('2026-06-20');
expect(before.winner).not.toEqual({ kind: 'temporal', id: 'immaculate-heart-of-mary' });
expect(after.winner).not.toEqual({ kind: 'temporal', id: 'immaculate-heart-of-mary' });
});
it('no longer wins or appears anywhere on Aug 22, which reverts to the Assumption octave alone', () => {
const day = resolveDay('2026-08-22');
expect(day.winner).not.toEqual(expect.objectContaining({ id: 'immaculate-heart-of-mary' }));
expect(day.commemorations).not.toContainEqual(expect.objectContaining({ id: 'immaculate-heart-of-mary' }));
});
});