mirror of https://github.com/ghostfolio/ghostfolio
committed by
GitHub
6 changed files with 470 additions and 34 deletions
@ -0,0 +1,141 @@ |
|||
import { addDays, format } from 'date-fns'; |
|||
|
|||
import { |
|||
getTimeAxisUnit, |
|||
getTimeSeriesTickCallback, |
|||
getTradingDayItems |
|||
} from './chart-helper'; |
|||
import { DATE_FORMAT } from './helper'; |
|||
|
|||
describe('getTimeAxisUnit', () => { |
|||
it.each([ |
|||
['1d', 'hour'], |
|||
['wtd', 'day'], |
|||
['mtd', 'day'], |
|||
['ytd', 'month'], |
|||
['1y', false], |
|||
['2025', 'month'], |
|||
['5y', false], |
|||
['max', false], |
|||
[undefined, 'year'] |
|||
])('uses the unit of %s', (dateRange, unit) => { |
|||
expect(getTimeAxisUnit(dateRange)).toBe(unit); |
|||
}); |
|||
}); |
|||
|
|||
describe('getTradingDayItems', () => { |
|||
// Thursday
|
|||
const now = new Date(2026, 11, 24); |
|||
|
|||
it('skips the weekends', () => { |
|||
const items = getTradingDayItems({ |
|||
dateRange: '1y', |
|||
now, |
|||
items: [ |
|||
{ date: '2026-12-18', value: 1 }, |
|||
{ date: '2026-12-19', value: 1 }, |
|||
{ date: '2026-12-20', value: 1 }, |
|||
{ date: '2026-12-21', value: 2 } |
|||
] |
|||
}); |
|||
|
|||
expect(items.map(({ date }) => date)).toEqual(['2026-12-18', '2026-12-21']); |
|||
}); |
|||
|
|||
it('adds the remaining trading days of the year', () => { |
|||
const items = getTradingDayItems({ |
|||
dateRange: 'ytd', |
|||
now, |
|||
items: [{ date: '2026-12-24', value: 1 }] |
|||
}); |
|||
|
|||
expect(items).toEqual([ |
|||
{ date: '2026-12-24', value: 1 }, |
|||
{ date: '2026-12-25', value: null }, |
|||
{ date: '2026-12-28', value: null }, |
|||
{ date: '2026-12-29', value: null }, |
|||
{ date: '2026-12-30', value: null }, |
|||
{ date: '2026-12-31', value: null } |
|||
]); |
|||
}); |
|||
}); |
|||
|
|||
describe('getTimeSeriesTickCallback', () => { |
|||
it('labels the first point of each hour', () => { |
|||
const ticks = [ |
|||
new Date(2026, 9, 22, 9, 0), |
|||
new Date(2026, 9, 22, 9, 30), |
|||
new Date(2026, 9, 22, 10, 0), |
|||
new Date(2026, 9, 22, 10, 30) |
|||
].map((date) => { |
|||
return { value: date.getTime() }; |
|||
}); |
|||
|
|||
const callback = getTimeSeriesTickCallback('hour'); |
|||
|
|||
expect( |
|||
ticks.map(({ value }, index) => { |
|||
return callback(value, index, ticks); |
|||
}) |
|||
).toEqual(['09:00', '', '10:00', '']); |
|||
}); |
|||
|
|||
it('labels the start of each trading day, also after a post-market past midnight', () => { |
|||
const ticks = [ |
|||
new Date(2026, 9, 22, 21, 0), |
|||
new Date(2026, 9, 22, 23, 0), |
|||
new Date(2026, 9, 23, 1, 0), |
|||
new Date(2026, 9, 23, 9, 0) |
|||
].map((date) => { |
|||
return { value: date.getTime() }; |
|||
}); |
|||
|
|||
const callback = getTimeSeriesTickCallback('day'); |
|||
|
|||
expect( |
|||
ticks.map(({ value }, index) => { |
|||
return callback(value, index, ticks); |
|||
}) |
|||
).toEqual(['Thu 22', '', '', 'Fri 23']); |
|||
}); |
|||
|
|||
it('thins out the labels', () => { |
|||
const ticks = Array.from({ length: 20 }, (_, index) => { |
|||
return { value: new Date(2026, 0, 1 + index).getTime() }; |
|||
}); |
|||
|
|||
const callback = getTimeSeriesTickCallback('day', 5); |
|||
const labels = ticks |
|||
.map(({ value }, index) => { |
|||
return callback(value, index, ticks); |
|||
}) |
|||
.filter(Boolean); |
|||
|
|||
expect(labels.length).toBeLessThanOrEqual(5); |
|||
}); |
|||
}); |
|||
|
|||
describe('getTradingDayItems with many items', () => { |
|||
it('keeps one point per week (the last trading day)', () => { |
|||
const items = Array.from({ length: 28 }, (_, index) => { |
|||
return { |
|||
date: format(addDays(new Date(2026, 0, 5), index), DATE_FORMAT), |
|||
value: index |
|||
}; |
|||
}); |
|||
|
|||
const result = getTradingDayItems({ dateRange: '1y', items, maxItems: 10 }); |
|||
|
|||
expect( |
|||
result.map(({ date }) => { |
|||
return date; |
|||
}) |
|||
).toEqual([ |
|||
'2026-01-05', |
|||
'2026-01-09', |
|||
'2026-01-16', |
|||
'2026-01-23', |
|||
'2026-01-30' |
|||
]); |
|||
}); |
|||
}); |
|||
Loading…
Reference in new issue