diff --git a/apps/server/src/services/__tests__/timerUtils.test.ts b/apps/server/src/services/__tests__/timerUtils.test.ts index 288bbc382..b593046f9 100644 --- a/apps/server/src/services/__tests__/timerUtils.test.ts +++ b/apps/server/src/services/__tests__/timerUtils.test.ts @@ -975,6 +975,36 @@ describe('getRuntimeOffset()', () => { expect(absolute).toBe(25); }); + it('paused time is delayed time when the pause spans midnight', () => { + const state = { + eventNow: { + id: '1', + timeStart: 23 * MILLIS_PER_HOUR, // 23:00 + timeEnd: 1 * MILLIS_PER_HOUR, // 01:00 + dayOffset: 0, + }, + clock: 3 * MILLIS_PER_MINUTE, // 00:03 (after midnight) + timer: { + startedAt: 23 * MILLIS_PER_HOUR, // started on time at 23:00 + current: 25, // still counting down + addedTime: 0, + }, + _timer: { + pausedAt: 23 * MILLIS_PER_HOUR + 58 * MILLIS_PER_MINUTE, // 23:58, before midnight + }, + rundown: { + actualStart: 23 * MILLIS_PER_HOUR, + plannedStart: 23 * MILLIS_PER_HOUR, + currentDay: 0, + }, + _startDayOffset: 0, + } as RuntimeState; + + // paused from 23:58 to 00:03 -> 5 minutes, regardless of the midnight wrap + const { absolute } = getRuntimeOffset(state); + expect(absolute).toBe(5 * MILLIS_PER_MINUTE); + }); + it('offset doesnt exist if we havent started', () => { const state = { clock: 78480789, diff --git a/apps/server/src/stores/__tests__/runtimeState.test.ts b/apps/server/src/stores/__tests__/runtimeState.test.ts index b5b532789..dc8550d07 100644 --- a/apps/server/src/stores/__tests__/runtimeState.test.ts +++ b/apps/server/src/stores/__tests__/runtimeState.test.ts @@ -248,6 +248,53 @@ describe('mutation on runtimeState', () => { state = getState(); expect(state.timer.elapsed).toBe(3 * MILLIS_PER_MINUTE); }); + + test('elapsed excludes a pause that spans midnight', async () => { + clearState(); + // an event that runs over midnight (23:00 -> 01:00) + const event = { + ...mockEvent, + id: 'elapsed-pause-midnight', + timeStart: 23 * MILLIS_PER_HOUR, + timeEnd: 1 * MILLIS_PER_HOUR, + duration: 2 * MILLIS_PER_HOUR, + }; + const mockRundown = makeRundown({ + entries: { [event.id]: event }, + order: [event.id], + }); + + await initRundown(mockRundown, {}); + vi.runAllTimers(); + + const { metadata, rundown } = rundownCache.get(); + + // start before midnight + vi.setSystemTime('jan 1 23:50'); + load(event, rundown, metadata); + start(); + + // 8 minutes of active running before we pause + vi.setSystemTime('jan 1 23:58'); + update(); + expect(getState().timer.elapsed).toBe(8 * MILLIS_PER_MINUTE); + pause(); + + // resume 5 minutes later, having crossed midnight (23:58 -> 00:03) + vi.setSystemTime('jan 2 00:03'); + start(); + let state = getState(); + // the pause lasted 5 minutes, regardless of the midnight wrap + expect(state._timer.pausedDuration).toBe(5 * MILLIS_PER_MINUTE); + // elapsed must still exclude the paused time -> only the 8 active minutes + expect(state.timer.elapsed).toBe(8 * MILLIS_PER_MINUTE); + + // 2 more active minutes after resume -> 10 minutes elapsed + vi.setSystemTime('jan 2 00:05'); + update(); + state = getState(); + expect(state.timer.elapsed).toBe(10 * MILLIS_PER_MINUTE); + }); }); test('runtime offset', async () => {