c4726c2953
Deploy / deploy (push) Successful in 1m9s
Continues the full-year sanctoral import: Ss. Tiburtius and Susanna, Ss. Hippolytus and Cassian, the Vigil of the Assumption, St. Joachim (Duplex II Classis, own full proper content), St. Hyacinth, St. John Eudes, St. Jane Frances de Chantal, the Immaculate Heart of the BVM (Duplex II Classis, instituted 1942, full proper content), St. Joseph Calasanctius, and St. Raymond Nonnatus. Several of the new fixed dates (Aug 16, 17, 21, 22) fall within or adjacent to St. Lawrence's and the Assumption's overlapping octave windows and now win outright there under the ordinary-feria/ordinary- sunday precedence rules, displacing what several existing tests expected to be bare octave commemorations or ferial fallbacks. Updated: - august-sanctoral.test.ts: Aug 22 now correctly shows the Immaculate Heart of Mary as the winner, with the Assumption's octave still commemorated alongside her. - day-label.test.ts: the two octave-priority tests pinned to Aug 17 (now St. Hyacinth's own day) moved their "day 8 alone" case to All Saints' own octave (Nov 8, still open); the two-octaves-overlap comparison can no longer be demonstrated via any real date in this app since every day where St. Lawrence's and the Assumption's octaves genuinely overlap is now real sanctoral content -- the underlying `pickWinningOctave` mechanism itself stays covered by tests/calendar/octaves.test.ts's own synthetic-data unit test. - vespers.test.ts: the Thursday Ps 138 split test moved off Aug 20, whose own first Vespers is now claimed by St. Jane Frances de Chantal's fixed day (Aug 21). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
194 lines
11 KiB
TypeScript
194 lines
11 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
|
import { resolveDay } from '../../src/calendar';
|
|
import { getDayLabel } from '../../src/calendar/day-label';
|
|
import type { LiturgicalDay } from '../../src/calendar/types';
|
|
|
|
describe('getDayLabel — ordinal temporal label', () => {
|
|
it("labels an anchor's own partial week as \"Weekday after {Anchor}\"", () => {
|
|
// Not 2026 (Trinity Sunday May 31, so Trinity Monday June 1): that
|
|
// date is now St. Angela Merici's own fixed day (Duplex, added per
|
|
// the full-year sanctoral import), which would win outright and hide
|
|
// this purely-temporal label case. 2027's Trinity Sunday is May 23,
|
|
// so Trinity Monday is May 24 -- free of any sanctoral entry.
|
|
expect(getDayLabel(resolveDay('2027-05-24'))).toBe('Monday after Trinity Sunday');
|
|
expect(getDayLabel(resolveDay('2026-01-07'))).toBe('Wednesday after Epiphany'); // Epiphany 2026 is a Tuesday
|
|
});
|
|
|
|
it('names the anchor day itself, not "day after itself"', () => {
|
|
// Trinity Sunday 2026 (May 31) is now also the Queenship of the
|
|
// Blessed Virgin Mary's own fixed day (Duplex II Classis, added per
|
|
// the full-year sanctoral import) — since this app models Trinitytide
|
|
// Sundays as plain `ordinary-sunday` with no special first-class
|
|
// standing of their own, the Duplex+ sanctoral feast wins outright
|
|
// here per the normal ordinary-Sunday rule (see
|
|
// tests/calendar/transfer.test.ts's own May 31 case for the full
|
|
// winner/commemorations breakdown), so the label now reflects her,
|
|
// not Trinity Sunday itself.
|
|
expect(getDayLabel(resolveDay('2026-05-31'))).toBe('The Queenship of the Blessed Virgin Mary');
|
|
expect(getDayLabel(resolveDay('2026-04-05'))).toBe('Easter');
|
|
expect(getDayLabel(resolveDay('2026-02-18'))).toBe('Ash Wednesday');
|
|
});
|
|
|
|
it('gives the correct week-after-Trinity ordinal', () => {
|
|
// Not 2026 (Jul 6): that date is now the Octave Day of Ss. Peter and
|
|
// Paul's own fixed day (Duplex majus, added per the full-year
|
|
// sanctoral import), which wins outright. 2027's Trinity Sunday is
|
|
// May 23, so 5 full weeks after the first Sunday-after-Trinity
|
|
// (May 30) is Jun 28 -- free of any sanctoral entry.
|
|
expect(getDayLabel(resolveDay('2027-06-28'))).toBe('Monday in the 5th week after Trinity');
|
|
});
|
|
|
|
it("Advent's own anchor Sunday is already week 1, not a separate anchor-week case", () => {
|
|
// 2025-11-30 is also St. Andrew's own day (Duplex II. classis) — since
|
|
// the November sanctoral pull, he's correctly commemorated alongside
|
|
// Advent I rather than simply absent (confirmed against the live
|
|
// reference engine, which shows the same pairing), so the label
|
|
// reflects both, feast name first, same pattern as Trinity Sunday's
|
|
// own St. Felix I case above.
|
|
expect(getDayLabel(resolveDay('2025-11-30'))).toBe('St. Andrew, Apostle — The 1st Sunday of Advent');
|
|
expect(getDayLabel(resolveDay('2025-12-01'))).toBe('Monday in the 1st week of Advent');
|
|
});
|
|
|
|
it('falls back to weekday + season name for seasons with no ordinal convention modeled', () => {
|
|
// 2026-05-15 is now St. John Baptist de la Salle's own fixed day
|
|
// (Duplex, added per the full-year sanctoral import) -- moved to
|
|
// May 21, still within Ascensiontide 2026 (May 14-23) and still
|
|
// free of any sanctoral entry.
|
|
expect(getDayLabel(resolveDay('2026-05-21'))).toContain('in Ascensiontide');
|
|
});
|
|
});
|
|
|
|
describe('getDayLabel — resumed post-Epiphany Sunday (overflow years)', () => {
|
|
it('labels a resumed Sunday/weekday as "after Epiphany", not the next Trinity-counted number', () => {
|
|
// 2026: post-epiphany-5 is Nov 8, post-epiphany-6 is Nov 15 (both
|
|
// Sundays) -- see calendar/temporal-id.test.ts for the id-level
|
|
// coverage this label check builds on.
|
|
expect(getDayLabel(resolveDay('2026-11-08'))).toBe('The 5th Sunday after Epiphany');
|
|
// 2026-11-09 is also the Dedication of the Basilica of the Most Holy
|
|
// Savior (Duplex II Classis, added 2026-08 — see
|
|
// dedication-of-the-basilica-of-the-most-holy-savior.yml) — an
|
|
// ordinary (non-privileged) Monday fully yields to a real winning
|
|
// saint, so the label is just her name, not the ferial fallback; the
|
|
// 11-16 assertion below covers that fallback format on a genuinely
|
|
// saint-free day instead.
|
|
expect(getDayLabel(resolveDay('2026-11-09'))).toBe(
|
|
'Dedication of the Basilica of the Most Holy Savior (the Lateran)',
|
|
);
|
|
expect(getDayLabel(resolveDay('2026-11-15'))).toBe('The 6th Sunday after Epiphany');
|
|
expect(getDayLabel(resolveDay('2026-11-16'))).toBe('Monday in the 6th week after Epiphany');
|
|
});
|
|
|
|
it('the fixed final Sunday of the year always shows the fixed 23rd-after-Trinity ordinal, not a raw elapsed-week count', () => {
|
|
// 2026-11-22 is the fixed post-pentecost-24 Sunday (Sunday XXIV after
|
|
// Pentecost's own fixed formulary; this app's Trinity-counted display
|
|
// is one week off from that Pentecost-counted id, so XXIV - 1 = 23).
|
|
// Every year 1900-2100 lands on this same id for its own last Sunday
|
|
// before Advent, so this ordinal is fixed, not overflow-year-specific
|
|
// -- confirmed against a non-overflow year (1943) too.
|
|
expect(getDayLabel(resolveDay('2026-11-22'))).toBe('The 23rd Sunday after Trinity');
|
|
// 1943-11-21 is also the Presentation of the BVM (Duplex Majus, added
|
|
// 2026-08 — see presentation-of-the-bvm.yml), which meets this app's
|
|
// existing privileged-Sunday rank threshold (commemorations.ts's
|
|
// `privileged-sunday` case requires only duplex-majus+) and so wins
|
|
// outright rather than being commemorated — a pre-existing rule, not
|
|
// new behavior from adding her. 2026-11-22 above (no saint collision)
|
|
// still covers the fixed-ordinal label itself.
|
|
expect(getDayLabel(resolveDay('1943-11-21'))).toBe('The Presentation of the Blessed Virgin Mary');
|
|
});
|
|
});
|
|
|
|
describe('getDayLabel — active octave', () => {
|
|
it('shows the octave day itself as the primary label, plus a lesser saint commemorated alongside it', () => {
|
|
// St. Lawrence's own octave (Aug 10-17); Aug 12 is day 3, and also St.
|
|
// Clare's own day -- Simplex, below the octave's semiduplex threshold,
|
|
// so she's commemorated rather than winning. Matches the live engine's
|
|
// own title for this date directly (see saints/st-clare.yml).
|
|
expect(getDayLabel(resolveDay('2026-08-12'))).toBe('3rd Day within the Octave of St. Lawrence, Martyr — St. Clare, Virgin');
|
|
});
|
|
|
|
it('shows the octave day alone when nothing is separately commemorated that day', () => {
|
|
// Not Aug 17 (day 8, the last day, of St. Lawrence's octave): that
|
|
// date is now St. Hyacinth's own fixed day (Duplex, added per the
|
|
// full-year sanctoral import), which wins outright. All Saints' own
|
|
// octave (Nov 1-8) still has a genuinely open day 8 -- 2028-11-08 is
|
|
// a Wednesday, clear of both a Sunday and any sanctoral entry.
|
|
expect(getDayLabel(resolveDay('2028-11-08'))).toBe('8th Day within the Octave of All Saints');
|
|
});
|
|
|
|
it("a season's own named anchor day outranks an active octave, even though Trinity Sunday is technically also day 8 of Pentecost's own octave", () => {
|
|
// Not 2026 (May 31, the Queenship of the Blessed Virgin Mary's own
|
|
// fixed day, see tests/calendar/transfer.test.ts) and not 2023
|
|
// (June 4, now St. Francis Caracciolo's own fixed day) -- both would
|
|
// muddy this specifically octave-vs-anchor-day check with a sanctoral
|
|
// winner. 2030's Trinity Sunday (June 16) has no sanctoral entry at
|
|
// all, isolating the octave interaction cleanly.
|
|
expect(getDayLabel(resolveDay('2030-06-16'))).toBe('Trinity Sunday');
|
|
});
|
|
|
|
it("a temporal day with real standing of its own (not ordinary-feria) never shows an octave name at all, even with one active -- live-verified counterexample: the Christmas Octave's own stack (Dec 30) titles itself off the Sunday, never any of the four octaves layered on top of it", () => {
|
|
const day = resolveDay('2033-12-30');
|
|
expect(day.temporalCategory).toBe('privileged-feria-minor');
|
|
expect(getDayLabel(day)).not.toContain('Octave');
|
|
expect(getDayLabel(day)).toBe('Friday in Christmastide');
|
|
});
|
|
|
|
it("picks the higher-ranked of two genuinely overlapping octaves for the label -- St. Lawrence's own elevated closing day (Aug 17) over the Assumption's ordinary day 3, even though the Assumption's octave started later and the Assumption is the higher-ranked feast overall", () => {
|
|
// Aug 17 itself is no longer available to demonstrate the
|
|
// octave-vs-octave priority pick through a real date: it's now St.
|
|
// Hyacinth's own fixed day (Duplex, added per the full-year
|
|
// sanctoral import), which wins outright over both octaves. In
|
|
// fact every day where St. Lawrence's (Aug 10-17) and the
|
|
// Assumption's (Aug 15-22) octaves genuinely overlap (Aug 15-17) is
|
|
// now occupied by real sanctoral content (the Assumption herself,
|
|
// St. Joachim, St. Hyacinth) -- there's no remaining real calendar
|
|
// date left in this app where that specific priority comparison is
|
|
// observable. The underlying mechanism itself (`pickWinningOctave`)
|
|
// is still directly unit-tested with synthetic data in
|
|
// tests/calendar/octaves.test.ts's own "picks the higher-ranked
|
|
// octave regardless of order or start date" case. Aug 18 (day 4 of
|
|
// the Assumption's octave alone, Lawrence's already over) is still
|
|
// a valid, uncontested check.
|
|
expect(getDayLabel(resolveDay('2026-08-17'))).toBe('St. Hyacinth, Confessor');
|
|
expect(getDayLabel(resolveDay('2026-08-18'))).toBe('4th Day within the Octave of The Assumption of the Blessed Virgin Mary');
|
|
});
|
|
|
|
it('a real Sunday with standing of its own wins over both octaves entirely, showing the plain ordinal Sunday label -- not an octave name at all', () => {
|
|
// 2026-08-16 is a Sunday genuinely within both St. Lawrence's and the
|
|
// Assumption's overlapping octave windows.
|
|
const day = resolveDay('2026-08-16');
|
|
expect(day.weekday).toBe('sunday');
|
|
expect(getDayLabel(day)).not.toContain('Octave');
|
|
});
|
|
});
|
|
|
|
describe('getDayLabel — feast name combination', () => {
|
|
const base: LiturgicalDay = {
|
|
date: '2026-06-15',
|
|
weekday: 'monday',
|
|
season: 'trinitytide',
|
|
temporalCategory: 'ordinary-feria',
|
|
winner: { kind: 'temporal', id: 'post-pentecost-02' },
|
|
commemorations: [],
|
|
};
|
|
|
|
it('shows just the feast name when it wins outright', () => {
|
|
const day: LiturgicalDay = {
|
|
...base,
|
|
winner: { kind: 'sanctoral', id: 'x', name: 'St. Ereden', rank: 'duplex' },
|
|
};
|
|
expect(getDayLabel(day)).toBe('St. Ereden');
|
|
});
|
|
|
|
it('shows both, feast first, when the feast is merely commemorated', () => {
|
|
const day: LiturgicalDay = {
|
|
...base,
|
|
commemorations: [{ kind: 'sanctoral', id: 'x', name: 'St. Ereden', rank: 'duplex-2-classis' }],
|
|
};
|
|
expect(getDayLabel(day)).toBe('St. Ereden — Monday in the 2nd week after Trinity');
|
|
});
|
|
|
|
it('shows just the temporal label when nothing is commemorated at all', () => {
|
|
expect(getDayLabel(base)).toBe('Monday in the 2nd week after Trinity');
|
|
});
|
|
});
|