0955f7cbd1
Deploy / deploy (push) Successful in 1m9s
Continues the full-year sanctoral import: the Guardian Angels (Duplex majus, full proper content), St. Thérèse of Lisieux, St. Bruno, St. Bridget of Sweden, St. Francis Borgia, the Maternity of the BVM (Duplex II Classis, instituted 1931 for the 1500th anniversary of the Council of Ephesus, full proper content), St. Edward the Confessor, St. Teresa of Avila (distinct from St. Thérèse of Lisieux -- two different Carmelite saints sharing a name), St. Margaret Mary Alacoque, St. Peter of Alcantara, St. John Cantius, and St. Raphael the Archangel (own full proper content, matching st-gabriel-archangel.yml's established pattern for a Sancti file that redirects wholesale to another date's file but still carries its own real content). St. Raphael's new fixed day (Oct 24, Duplex majus) collided with the "clean, empty Saturday" fixture used by three tests for Marian Saturday/Lauds-psalmody-override behavior; moved all three to 2026-07-04, verified genuinely free of any sanctoral entry (not even a commemorated Simplex). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
120 lines
6.7 KiB
TypeScript
120 lines
6.7 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
|
import { resolveOrdo } from '../../src/hours';
|
|
|
|
describe('Lauds psalmody override (duplex-majus+ sanctoral, and Marian Saturday)', () => {
|
|
it("substitutes St. Lawrence's own proper psalmody on his own day (Duplex II. classis, above the threshold)", () => {
|
|
const ordo = resolveOrdo('lauds', '2026-08-10');
|
|
const psalmNumbers = ordo.parts
|
|
.filter((p) => p.kind === 'psalm')
|
|
.map((p) => (p.kind === 'psalm' ? p.psalmNumber : undefined));
|
|
expect(psalmNumbers).toEqual([66, 92, 99, 62, 148, 149, 150]);
|
|
|
|
const ps92 = ordo.parts.find((p) => p.kind === 'psalm' && p.psalmNumber === 92);
|
|
expect(ps92?.kind === 'psalm' ? ps92.antiphon?.text.en : undefined).toContain('Lawrence went in to be a martyr');
|
|
|
|
const canticle = ordo.parts.find((p) => p.kind === 'canticle' && p.canticleId !== 'benedictus');
|
|
expect(canticle?.kind === 'canticle' ? canticle.canticleId : undefined).toBe('canticum-trium-puerorum');
|
|
});
|
|
|
|
it("resolves St. Lawrence's own office bundle (capitulum/responsory/hymn/versicle) on his own day, not the plain weekday default -- a real gap flagged in TODO.md, now filled", () => {
|
|
const ordo = resolveOrdo('lauds', '2026-08-10');
|
|
const chapter = ordo.parts.find((p) => p.kind === 'chapter');
|
|
expect(chapter?.kind === 'chapter' ? chapter.text.citation?.la : undefined).toBe('2 Cor 9:6');
|
|
const hymn = ordo.parts.find((p) => p.kind === 'hymn');
|
|
expect(hymn?.kind === 'hymn' ? hymn.text.text.la : undefined).toContain('Martyr Dei');
|
|
const responsory = ordo.parts.find((p) => p.kind === 'responsory');
|
|
expect(responsory?.kind === 'responsory' ? responsory.text.text.la : undefined).toContain('Glória et honóre');
|
|
});
|
|
|
|
it("resolves the same office bundle on day 3 of St. Lawrence's own octave, not the plain weekday default -- resolveOfficeWinner", () => {
|
|
const ordo = resolveOrdo('lauds', '2026-08-12');
|
|
const chapter = ordo.parts.find((p) => p.kind === 'chapter');
|
|
expect(chapter?.kind === 'chapter' ? chapter.text.citation?.la : undefined).toBe('2 Cor 9:6');
|
|
});
|
|
|
|
it("doesn't override a saint below duplex-majus (e.g. Semiduplex) -- plain weekday psalmody still used", () => {
|
|
// 2026-09-19: St. Januarius, Semiduplex (below duplex-majus) -- see
|
|
// tests/calendar/marian-saturday.test.ts for confirming he wins
|
|
// outright as the day's winner despite it being a Saturday.
|
|
const ordo = resolveOrdo('lauds', '2026-09-19');
|
|
const psalmNumbers = ordo.parts
|
|
.filter((p) => p.kind === 'psalm')
|
|
.map((p) => (p.kind === 'psalm' ? p.psalmNumber : undefined));
|
|
// Saturday's own plain default (Ps 50 + 142), not the Common-shaped
|
|
// override -- no lauds-psalmody-overrides/st-januarius.yml exists.
|
|
expect(psalmNumbers).toEqual([66, 50, 142, 148, 149, 150]);
|
|
});
|
|
|
|
it("substitutes Our Lady's Saturday own proper psalmody, unconditionally, whenever it wins", () => {
|
|
// Not 2026-10-24: that date is now St. Raphael the Archangel's own
|
|
// fixed day (Duplex majus, added per the full-year sanctoral
|
|
// import), which wins outright. 2026-07-04 is a clean, otherwise-
|
|
// empty Marian Saturday (see tests/calendar/marian-saturday.test.ts).
|
|
const ordo = resolveOrdo('lauds', '2026-07-04');
|
|
const psalmNumbers = ordo.parts
|
|
.filter((p) => p.kind === 'psalm')
|
|
.map((p) => (p.kind === 'psalm' ? p.psalmNumber : undefined));
|
|
expect(psalmNumbers).toEqual([66, 92, 99, 62, 148, 149, 150]);
|
|
|
|
const ps92 = ordo.parts.find((p) => p.kind === 'psalm' && p.psalmNumber === 92);
|
|
expect(ps92?.kind === 'psalm' ? ps92.antiphon?.text.la : undefined).toContain('Dum esset Rex');
|
|
|
|
const benedictus = ordo.parts.find((p) => p.kind === 'canticle' && p.canticleId === 'benedictus');
|
|
expect(benedictus?.kind === 'canticle' ? benedictus.antiphon?.text.la : undefined).toContain('Beáta Dei Génitrix');
|
|
|
|
const collect = ordo.parts.find((p) => p.kind === 'prayer');
|
|
expect(collect?.kind === 'prayer' ? collect.text.text.en : undefined).toContain('glorious intercession of the Blessed Mary');
|
|
});
|
|
|
|
it("drops the Holy Cross and Blessed Virgin Mary suffrages on Our Lady's Saturday (the latter redundant with the day's already-Marian office; the former because Marian Saturday isn't a bare ferial office either), keeping Joseph, Apostles, and Peace", () => {
|
|
const ordo = resolveOrdo('lauds', '2026-07-04');
|
|
const labels = ordo.parts.filter((p) => p.kind === 'preces' && p.label).map((p) => (p.kind === 'preces' ? p.label : undefined));
|
|
expect(labels).toEqual(['Of St. Joseph', 'Of the Holy Apostles Peter and Paul', 'For Peace', 'Salve Regina']);
|
|
});
|
|
|
|
it("substitutes Christ the King's own proper psalmody and office bundle, and omits the suffrages entirely (Duplex I. classis)", () => {
|
|
const ordo = resolveOrdo('lauds', '2026-10-25');
|
|
const psalmNumbers = ordo.parts
|
|
.filter((p) => p.kind === 'psalm')
|
|
.map((p) => (p.kind === 'psalm' ? p.psalmNumber : undefined));
|
|
expect(psalmNumbers).toEqual([66, 92, 99, 62, 148, 149, 150]);
|
|
|
|
const ps92 = ordo.parts.find((p) => p.kind === 'psalm' && p.psalmNumber === 92);
|
|
expect(ps92?.kind === 'psalm' ? ps92.antiphon?.text.en : undefined).toContain('The God of heaven');
|
|
|
|
const chapter = ordo.parts.find((p) => p.kind === 'chapter');
|
|
expect(chapter?.kind === 'chapter' ? chapter.text.citation?.en : undefined).toBe('Col 1:12-13');
|
|
|
|
const hymn = ordo.parts.find((p) => p.kind === 'hymn');
|
|
expect(hymn?.kind === 'hymn' ? hymn.text.text.la : undefined).toContain('Vexílla Christus ínclita');
|
|
|
|
const benedictus = ordo.parts.find((p) => p.kind === 'canticle' && p.canticleId === 'benedictus');
|
|
expect(benedictus?.kind === 'canticle' ? benedictus.antiphon?.text.en : undefined).toContain(
|
|
'He hath made us',
|
|
);
|
|
|
|
// One extra collect (the commemorated Sunday's own, still an
|
|
// unlabeled 'prayer' -- a temporal commemoration, not a sanctoral
|
|
// one) plus the Simplex saint already commemorated under that Sunday
|
|
// before Christ the King displaced it too, now a labeled 'preces'
|
|
// block rather than a third bare 'prayer' -- see
|
|
// tests/calendar/christ-the-king.test.ts.
|
|
const collects = ordo.parts.filter((p) => p.kind === 'prayer');
|
|
expect(collects.length).toBe(2);
|
|
const sanctoralCommemoration = ordo.parts.find(
|
|
(p) => p.kind === 'preces' && p.label?.startsWith('Commemoration of'),
|
|
);
|
|
expect(sanctoralCommemoration).toBeDefined();
|
|
|
|
const SUFFRAGE_LABELS = new Set([
|
|
'Of the Holy Cross',
|
|
'Of the Blessed Virgin Mary',
|
|
'Of St. Joseph',
|
|
'Of the Holy Apostles Peter and Paul',
|
|
'For Peace',
|
|
]);
|
|
const suffrages = ordo.parts.filter((p) => p.kind === 'preces' && p.label && SUFFRAGE_LABELS.has(p.label));
|
|
expect(suffrages).toEqual([]);
|
|
});
|
|
});
|