money scenarios: forecast horizon 1–100y (?horizon=), today’s-euro view, scaling gridlines, career paths with job hops and plateaus, crash cycles per portfolio, retirement at 68 with withdrawals, salary path table
All checks were successful
Deploy production / deploy (push) Successful in 2m49s

This commit is contained in:
2026-10-24 15:13:20 +00:00
parent c4689adda4
commit 61ae72e50b
8 changed files with 642 additions and 129 deletions

View File

@@ -5,6 +5,9 @@ import {
balanceSeries,
forecastSeries,
parseHistoryRange,
gridFor,
horizonEnd,
parseHorizon,
timeGrid,
yearLabels,
utilityEstimate,
@@ -349,4 +352,25 @@ describe('history range', () => {
]);
expect(timeGrid('2026-01-02', '2026-01-01', 'months')).toEqual([]);
});
it('reads the forecast horizon and picks gridlines that scale with the span', () => {
expect(parseHorizon('10y')).toBe('10y');
expect(parseHorizon('2y')).toBe('5y');
expect(parseHorizon(null)).toBe('5y');
expect(horizonEnd('100y', '2026-10-24')).toBe('2126-10-24');
expect(gridFor('2025-10-24', '2027-10-24')).toBe('months');
expect(gridFor('2025-10-24', '2056-10-24')).toBe('years');
expect(gridFor('2025-10-24', '2076-10-24')).toBe('decades');
const decades = timeGrid('2025-10-24', '2126-10-24', 'decades');
expect(decades.map((line) => line.date.slice(0, 4))).toEqual(
[2030, 2040, 2050, 2060, 2070, 2080, 2090, 2100, 2110, 2120].map(String)
);
expect(yearLabels(decades, 5).map((date) => date.slice(0, 4))).toEqual([
'2040',
'2060',
'2080',
'2100',
'2120'
]);
});
});