From d499433f937ae3006bf7167681caacd22e48519f Mon Sep 17 00:00:00 2001 From: Julien Calixte Date: Wed, 17 Jun 2026 01:40:34 +0200 Subject: [PATCH] test(model): cover the authored plan span Add coverage for start/end extending, snapping, never-clipping, and the empty-plan case. The bundled sample now demonstrates the keys, so its expected week range moves to the authored bounds. --- src/data/sample.ts | 6 ++++++ src/model/plan.test.ts | 38 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/src/data/sample.ts b/src/data/sample.ts index 7ffbba6..d1203e0 100644 --- a/src/data/sample.ts +++ b/src/data/sample.ts @@ -3,6 +3,12 @@ // an overdue Feature, and a Milestone with unmet required Features. export const SAMPLE_PLAN = `title = "Q3 — Checkout revamp" +# Optional plan span: pad the plan with lead-in / trailing weeks. +# Rule: start ≤ every Feature's start, and end ≥ every Feature's last week. +# Omit both to auto-fit the columns to the Features and Milestones. +start = 2026-05-25 +end = 2026-08-03 + # A Feature: start week, Original Estimate (the immovable baseline), then any # Re-estimates, an optional Delivery, and an optional Learning / Status. # Dates are TOML date literals; any day is snapped to that week's Monday. diff --git a/src/model/plan.test.ts b/src/model/plan.test.ts index 4fbd6eb..57255d1 100644 --- a/src/model/plan.test.ts +++ b/src/model/plan.test.ts @@ -111,8 +111,8 @@ describe('bar extent relative to now', () => { describe('plan derivation', () => { it('derives a contiguous week range and places the now line', () => { const plan = buildPlan(parseMacroplan(SAMPLE_PLAN), TODAY) - expect(plan.weeks[0]).toBe('2026-06-01') // earliest start - expect(plan.weeks.at(-1)).toBe('2026-07-20') // latest marker (Payments delivery) + expect(plan.weeks[0]).toBe('2026-05-25') // authored span start (lead-in before earliest Feature) + expect(plan.weeks.at(-1)).toBe('2026-08-03') // authored span end (trailing past last marker) // contiguous, weekly expect(plan.weeks).toContain('2026-06-29') expect(plan.nowWeek).toBe('2026-06-15') @@ -128,6 +128,40 @@ describe('plan derivation', () => { }) }) +describe('authored plan span (start / end)', () => { + const body = '[[feature]]\nname="X"\nstart=2026-06-08\noriginal=2026-06-15\ndelivered=2026-06-15\n' + + it('extends the range earlier to `start` and later to `end`', () => { + const plan = buildPlan(parseMacroplan(`start = 2026-06-01\nend = 2026-06-29\n${body}`), TODAY) + expect(plan.weeks).toEqual(weekRange('2026-06-01', '2026-06-29')) + expect(plan.weeks[0]).toBe('2026-06-01') // before the earliest Feature week (06-08) + expect(plan.weeks.at(-1)).toBe('2026-06-29') // after the last marker (06-15) + }) + + it('snaps authored bounds to their Monday', () => { + const plan = buildPlan(parseMacroplan(`start = 2026-06-03\nend = 2026-06-24\n${body}`), TODAY) + expect(plan.weeks[0]).toBe('2026-06-01') // Wed 06-03 → Mon 06-01 + expect(plan.weeks.at(-1)).toBe('2026-06-22') // Wed 06-24 → Mon 06-22 + }) + + it('only extends — a marker outside the authored bounds is never clipped', () => { + // end 06-08 is before the Feature's 06-15 delivery → the range still includes it + const plan = buildPlan(parseMacroplan(`start = 2026-06-08\nend = 2026-06-08\n${body}`), TODAY) + expect(plan.weeks[0]).toBe('2026-06-08') + expect(plan.weeks.at(-1)).toBe('2026-06-15') + }) + + it('renders an empty plan across the authored bounds when there are no Features', () => { + const plan = buildPlan(parseMacroplan('start = 2026-06-01\nend = 2026-06-22\n'), TODAY) + expect(plan.rows).toHaveLength(0) + expect(plan.weeks).toEqual(weekRange('2026-06-01', '2026-06-22')) + }) + + it('rejects a non-date span bound', () => { + expect(() => parseMacroplan('start = 123\n')).toThrow(/start/) + }) +}) + describe('parse validation', () => { it('rejects a feature missing its Original Estimate', () => { expect(() => parseMacroplan('[[feature]]\nname = "A"\nstart = 2026-06-01\n')).toThrow(