diff --git a/server/src/classes/EventTimer.js b/server/src/classes/EventTimer.js index 7a00dff3e..1d0f8a43a 100644 --- a/server/src/classes/EventTimer.js +++ b/server/src/classes/EventTimer.js @@ -1,6 +1,6 @@ import { Timer } from './Timer.js'; import { Server } from 'socket.io'; -import { getSelectionByRoll } from './classUtils.js'; +import {DAYMS, getSelectionByRoll} from './classUtils.js'; /* * EventTimer adds functions specific to APP @@ -11,9 +11,6 @@ import { getSelectionByRoll } from './classUtils.js'; */ export class EventTimer extends Timer { - // AUX - DAYMS = 86400000; - // Socket IO Object io = null; @@ -701,7 +698,7 @@ export class EventTimer extends Timer { const start = e.timeStart == null || e.timeStart === '' ? 0 : e.timeStart; let end = e.timeEnd == null || e.timeEnd === '' ? 0 : e.timeEnd; // in case the end is earlier than start, we assume is the day after - if (end < start) end += this.DAYMS; + if (end < start) end += DAYMS; // time stuff changes on wheter we keep the running clock diff --git a/server/src/classes/Timer.js b/server/src/classes/Timer.js index 8cf6eea38..1cfd8b700 100644 --- a/server/src/classes/Timer.js +++ b/server/src/classes/Timer.js @@ -24,29 +24,6 @@ export class Timer { constructor() {} - // call setup separately - setupWithSeconds(seconds, autoStart = false) { - // aux - const now = this._getCurrentTime(); - this.clock = now; - - // populate targets - this.duration = seconds * 1000; - this._finishAt = now + seconds * 1000; - - // start counting - this._startedAt = now; - - if (autoStart) { - this.state = 'start'; - } else { - this._pausedAt = now; - this._pausedInterval = 0; - } - this._pausedTotal = 0; - this.update(); - } - // update() update() { // get current time diff --git a/server/src/classes/__tests__/classUtils.test.js b/server/src/classes/__tests__/classUtils.test.js index 0ba14c61a..e896a583f 100644 --- a/server/src/classes/__tests__/classUtils.test.js +++ b/server/src/classes/__tests__/classUtils.test.js @@ -1,4 +1,4 @@ -import { getSelectionByRoll, sortArrayByProperty } from '../classUtils.js'; +import {DAYMS, getSelectionByRoll, normaliseEndTime, sortArrayByProperty} from '../classUtils.js'; // test sortArrayByProperty() describe('sort simple arrays of objects', () => { @@ -244,6 +244,7 @@ describe('test that roll loads selection in right order', () => { }); // test getSelectionByRoll() + describe('test that roll behaviour with overlapping times', () => { const eventlist = [ { @@ -382,3 +383,90 @@ describe('test that roll behaviour with overlapping times', () => { expect(state).toStrictEqual(expected); }); }); + + +// test getSelectionByRoll() on issue #58 +describe('test that roll behaviour multi day event edge cases', () => { + + it('if the start time is the day after end time, and start time is earlier than now', () => { + const now = 66600000; // 19:30 + const eventlist = [ + { + id: 1, + timeStart: 66000000, // 19:20 + timeEnd: 54600000, // 16:10 + isPublic: false, + } + ]; + const expected = { + nowIndex: 0, + nowId: 1, + publicIndex: null, + nextIndex: null, + publicNextIndex: null, + timers: { + _startedAt: eventlist[0].timeStart, + _finishAt: eventlist[0].timeEnd, + current: eventlist[0].timeEnd + DAYMS - now, + duration: DAYMS - eventlist[0].timeStart + eventlist[0].timeEnd, + }, + timeToNext: null, + }; + + const state = getSelectionByRoll(eventlist, now); + expect(state).toStrictEqual(expected); + }); + + it('if the start time is the day after end time, and both are later than now', () => { + const now = 66840000; // 19:34 + const eventlist = [ + { + id: 1, + timeStart: 67200000, // 19:40 + timeEnd: 66900000, // 19:35 + isPublic: false, + } + ]; + const expected = { + nowIndex: null, + nowId: null, + publicIndex: null, + nextIndex: 0, + publicNextIndex: null, + timers: null, + timeToNext: eventlist[0].timeStart - now, + }; + + const state = getSelectionByRoll(eventlist, now); + expect(state).toStrictEqual(expected); + }); +}); + +// test normaliseEndTime() on issue #58 +test('test typical scenarios', () => { + + const t1 = { + start: 10, + end: 20, + } + const t1_expected = 20; + + expect(normaliseEndTime(t1.start, t1.end)).toBe(t1_expected); + + const t2 = { + start: 10+DAYMS, + end: 20, + } + const t2_expected = 20+DAYMS; + + expect(normaliseEndTime(t2.start, t2.end)).toBe(t2_expected); + + const t3 = { + start: 10, + end: 10, + } + const t3_expected = 10; + + expect(normaliseEndTime(t3.start, t3.end)).toBe(t3_expected); +}); + diff --git a/server/src/classes/__tests__/timer.test.js b/server/src/classes/__tests__/timer.test.js new file mode 100644 index 000000000..4b975300e --- /dev/null +++ b/server/src/classes/__tests__/timer.test.js @@ -0,0 +1,20 @@ +import {Timer} from "../Timer"; + +test('object instantiates correctly', () => { + const t = new Timer(); + + expect(t.clock).toBeNull; + expect(t.duration).toBeNull; + expect(t.current).toBeNull; + expect(t.timeTag).toBeNull; + expect(t.secondaryTimer).toBeNull; + expect(t._secondaryTarget).toBeNull; + expect(t._finishAt).toBeNull; + expect(t._finishedAt).toBeNull; + expect(t._finishedFlag).toBeFalsy; + expect(t._startedAt).toBeNull; + expect(t._pausedAt).toBeNull; + expect(t._pausedInterval).toBeNull; + expect(t._pausedTotal).toBeNull; + expect(t.state).toBe('stop'); +}) \ No newline at end of file diff --git a/server/src/classes/classUtils.js b/server/src/classes/classUtils.js index e369d2fcc..81d866fbc 100644 --- a/server/src/classes/classUtils.js +++ b/server/src/classes/classUtils.js @@ -1,3 +1,14 @@ +export const DAYMS = 86400000; + +/** + * @description handle events that span over midnight + * @param {num} start - When does the event start + * @param {num} end - When does the event end + * @returns {num} normalised time + */ +export const normaliseEndTime = (start, end) => (end < start ? end + DAYMS : end); + + /** * @description Sorts an array of objects by given property * @param {array} arr - array to be sorted @@ -41,8 +52,9 @@ export const getSelectionByRoll = (arr, now) => { let nowFound = false; // exit early if we are past the events - const lastEventEnd = orderedEvents[orderedEvents.length - 1].timeEnd; - if (now > lastEventEnd) { + const lastEvent = orderedEvents[orderedEvents.length - 1]; + const lastNormalEnd = normaliseEndTime(lastEvent.timeStart, lastEvent.timeEnd); + if (now > lastNormalEnd) { return { nowIndex, nowId, @@ -57,8 +69,7 @@ export const getSelectionByRoll = (arr, now) => { // loop through events, look for where we should be for (const e of orderedEvents) { // When does the event end (handle midnight) - const normalEnd = - e.timeEnd < e.timeStart ? (e.timeEnd += this.DAYMS) : e.timeEnd; + const normalEnd = normaliseEndTime(e.timeStart, e.timeEnd); if (normalEnd <= now) { // event ran already @@ -83,7 +94,7 @@ export const getSelectionByRoll = (arr, now) => { // set timers timers = { _startedAt: e.timeStart, - _finishAt: normalEnd, + _finishAt: e.timeEnd, duration: normalEnd - e.timeStart, current: normalEnd - now, }; @@ -118,3 +129,4 @@ export const getSelectionByRoll = (arr, now) => { timeToNext, }; }; + diff --git a/server/src/utils/__tests__/time.tests.js b/server/src/utils/__tests__/time.tests.js index 5c576c9ea..6c2c7d61b 100644 --- a/server/src/utils/__tests__/time.tests.js +++ b/server/src/utils/__tests__/time.tests.js @@ -70,7 +70,7 @@ describe('test excel date parser', () => { expect(excelDateStringToMillis(d2)).toBe(d2Millis); }); - it.only('handles an invalid date string', () => { + it('handles an invalid date string', () => { const s = 'hello'; expect(excelDateStringToMillis(s)).toBe(null); });