update window range

This commit is contained in:
Marshal
2026-06-13 07:59:48 +00:00
parent d3a479c142
commit b2f13c95c5
5 changed files with 426 additions and 16 deletions

View File

@@ -3,6 +3,9 @@ import {
listBatchWindowsForDate,
listBatchWindowsForBookings,
BATCH_WINDOW_START_HOURS,
boardWindowForTimestamp,
listBoardWindowsForRange,
groupBookingsIntoBoardWindows,
} from './batch-window.util';
describe('batch-window.util', () => {
@@ -50,3 +53,84 @@ describe('batch-window.util', () => {
expect(getBatchWindowForTimestamp(fullyExecutedAt).key).toBe(overnight!.key);
});
});
describe('batch-window board windows (midnight-based 3h slots)', () => {
it('maps 04:00 EAT to the 03:0006:00 slot', () => {
// 01:00 UTC = 04:00 EAT on 11 Jun
const w = boardWindowForTimestamp(new Date('2026-06-11T01:00:00.000Z'));
expect(w.label).toContain('03:00');
expect(w.label).toContain('06:00');
expect(w.date).toBe('2026-06-11');
expect(w.dateLabel).toContain('11 Jun');
});
it('maps 00:30 EAT to the 00:0003:00 slot of that EAT day', () => {
// 21:30 UTC on 10 Jun = 00:30 EAT on 11 Jun
const w = boardWindowForTimestamp(new Date('2026-06-10T21:30:00.000Z'));
expect(w.label).toContain('00:00');
expect(w.label).toContain('03:00');
expect(w.date).toBe('2026-06-11');
});
it('maps 23:00 EAT to the final 21:0024:00 slot', () => {
// 20:00 UTC = 23:00 EAT on 11 Jun
const w = boardWindowForTimestamp(new Date('2026-06-11T20:00:00.000Z'));
expect(w.label).toContain('21:00');
expect(w.label).toContain('24:00');
expect(w.date).toBe('2026-06-11');
});
it('lists a continuous range open→departure clamped at both ends', () => {
// open 05 Jun 08:00 EAT (05:00 UTC) → departs 08 Jun 14:00 EAT (11:00 UTC)
const open = new Date('2026-06-05T05:00:00.000Z');
const departure = new Date('2026-06-08T11:00:00.000Z');
const windows = listBoardWindowsForRange(open, departure);
// Day 5: 06,09,12,15,18,21 = 6 ; Days 6,7: 8 each ; Day 8: 00,03,06,09,12 = 5
expect(windows).toHaveLength(6 + 8 + 8 + 5);
expect(windows[0].date).toBe('2026-06-05');
expect(windows[0].label).toContain('06:00');
expect(windows[0].label).toContain('09:00');
const last = windows[windows.length - 1];
expect(last.date).toBe('2026-06-08');
expect(last.label).toContain('12:00');
expect(last.label).toContain('15:00');
// chronological + unique keys
const keys = windows.map((w) => w.key);
expect(new Set(keys).size).toBe(keys.length);
});
it('handles a same-day open→departure range', () => {
const open = new Date('2026-06-05T05:00:00.000Z'); // 08:00 EAT (0609 slot)
const departure = new Date('2026-06-05T11:00:00.000Z'); // 14:00 EAT (1215 slot)
const windows = listBoardWindowsForRange(open, departure);
// 06,09,12 = 3 slots
expect(windows).toHaveLength(3);
expect(windows.every((w) => w.date === '2026-06-05')).toBe(true);
});
it('buckets bookings by fullyExecutedAt and keeps empty + pending windows', () => {
const open = new Date('2026-06-05T05:00:00.000Z');
const departure = new Date('2026-06-06T11:00:00.000Z');
const items = [
{ id: 'a', ts: new Date('2026-06-05T05:30:00.000Z') }, // 08:30 EAT → 0609 on 5th
{ id: 'b', ts: null }, // pending
];
const map = groupBookingsIntoBoardWindows(
items,
(i) => i.ts,
open,
departure,
'pending-contract',
);
const pending = map.get('pending-contract');
expect(pending?.items.map((i) => i.id)).toEqual(['b']);
const withA = [...map.values()].find((b) => b.items.some((i) => i.id === 'a'));
expect(withA?.window?.date).toBe('2026-06-05');
// empty slots are retained for the UI
const emptyCount = [...map.values()].filter(
(b) => b.window && b.items.length === 0,
).length;
expect(emptyCount).toBeGreaterThan(0);
});
});