UNPKG

@tbowmo/node-red-small-timer

Version:

Small timer node for Node-RED with support for sunrise, sunset etc. timers

264 lines (234 loc) 8.21 kB
import { expect } from 'chai' import { useSinonSandbox } from '../../test' import { TimeCalc } from './time-calculation' import sunCalc from 'suncalc' describe('lib/time-calculation', () => { const sinon = useSinonSandbox() function setupTest() { const getMoonTimes = sinon.stub(sunCalc, 'getMoonTimes').returns({ rise: new Date('2023-01-01 11:00'), set: new Date('2023-01-01 12:00'), }) const getTimes = sinon.stub(sunCalc, 'getTimes').returns({ nightEnd: new Date('2023-01-01 04:00'), sunrise: new Date('2023-01-01 05:00'), dawn: new Date('2023-01-01 06:00'), solarNoon: new Date('2023-01-01 11:00'), sunset: new Date('2023-01-01 19:00'), dusk: new Date('2023-01-01 21:00'), night: new Date('2023-01-01 23:00'), // eslint-disable-next-line @typescript-eslint/no-explicit-any } as any) return { getMoonTimes, getTimes, } } it('should do basic on the hour on / off detection', () => { const stubs = setupTest() const currentTime = new Date('2023-01-01 11:00') sinon.clock.setSystemTime(currentTime) const minutes = currentTime.getHours() * 60 + currentTime.getMinutes() const timeCalc = new TimeCalc( undefined, undefined, false, minutes - 120, // 09:00 minutes + 120, // 12:00 0, 0, 0, ) sinon.assert.notCalled(stubs.getTimes) expect(timeCalc.getOnState()).to.equal(true) expect(timeCalc.getTimeToNextStartEvent()).to.equal(1320) expect(timeCalc.getTimeToNextEndEvent()).to.equal(120) timeCalc.setStartEndTime(minutes + 120, minutes + 180, -5, -10) expect(timeCalc.getOnState()).to.equal(false) expect(timeCalc.getTimeToNextStartEvent()).to.equal(115) expect(timeCalc.getTimeToNextEndEvent()).to.equal(170) }) it('should wrap around midnight', () => { setupTest() const currentTime = new Date('2023-01-01 01:00') sinon.clock.setSystemTime(currentTime) const timeCalc = new TimeCalc( 10, 10, true, 5005, 5006, 0, 0, 0, ) expect(timeCalc.getOnState()).to.equal(true) expect(timeCalc.getTimeToNextEndEvent()).to.equal(180) expect(timeCalc.getTimeToNextStartEvent()).to.equal(22 * 60) expect(timeCalc.operationToday()).to.equal('normal') }) it('should indicate that on time wraps midnight, if off time is before on time', () => { setupTest() const currentTime = new Date('2023-01-01 01:00') sinon.clock.setSystemTime(currentTime) const timeCalc = new TimeCalc( 10, 10, false, 5005, 5006, 0, 0, 0, ) expect(timeCalc.getOnState()).to.equal(false) expect(timeCalc.getTimeToNextEndEvent()).to.equal(180) expect(timeCalc.getTimeToNextStartEvent()).to.equal(22 * 60) expect(timeCalc.operationToday()).to.equal('noMidnightWrap') }) it('should indicate that on time is lower than minimum on time', () => { setupTest() const currentTime = new Date('2023-01-01 01:00') sinon.clock.setSystemTime(currentTime) const timeCalc = new TimeCalc( 10, 10, false, 45, 75, 0, 0, 60, ) expect(timeCalc.getOnState()).to.equal(false) expect(timeCalc.getTimeToNextEndEvent()).to.equal(15) expect(timeCalc.getTimeToNextStartEvent()).to.equal(1425) expect(timeCalc.operationToday()).to.equal('minimumOnTimeNotMet') }) const testData: { startTime: number, endTime: number, wrap: boolean, expectedStart: number, expectedEnd: number }[] = [ // dawn / dusk - 06:00 / 21:00 { startTime: 5000, endTime: 5001, wrap: false, expectedStart: 1080, expectedEnd: 540 }, // sunrise / solarNoon - 05:00 / 11:00 { startTime: 5003, endTime: 5002, wrap: false, expectedStart: 1020, expectedEnd: 1380 }, // sunset / night - 19:00 / 23:00 { startTime: 5004, endTime: 5005, wrap: false, expectedStart: 420, expectedEnd: 660 }, // nightEnd / moonrise - 123:00 / 11:00 { startTime: 5006, endTime: 5007, wrap: false, expectedStart: 960, expectedEnd: 1380 }, // moonset / dawn - :00 / :00 { startTime: 5008, endTime: 5000, wrap: false, expectedStart: 0, expectedEnd: 1080 }, { startTime: 13 * 60, endTime: 10090, wrap: false, expectedStart: 60, expectedEnd: 150 }, ] testData.forEach((data) => { it(`should use start ${data.startTime} and end ${data.endTime}`, () => { setupTest() sinon.clock.setSystemTime(new Date('2023-01-01 12:00')) const timeCalc = new TimeCalc( 10, 10, data.wrap, data.startTime, data.endTime, 0, 0, 0, ) expect(timeCalc.getTimeToNextStartEvent()).to.equal(data.expectedStart, 'startEvent') expect(timeCalc.getTimeToNextEndEvent()).to.equal(data.expectedEnd, 'endTime') }) }) it('should handle that moon time set rise could be false', () => { const stubs = setupTest() sinon.clock.setSystemTime(new Date('2023-01-01 12:05')) stubs.getMoonTimes.returns({ rise: false, set: false, // eslint-disable-next-line @typescript-eslint/no-explicit-any } as any) const timeCalc = new TimeCalc( 10, 10, false, 5007, 5008, 0, 0, 0, ) expect(timeCalc.getTimeToNextStartEvent()).to.equal(714, 'startEvent') expect(timeCalc.getTimeToNextEndEvent()).to.equal(715, 'endTime') }) it('should throw error if time can not be looked up', () => { setupTest() sinon.clock.setSystemTime(new Date('2023-01-01 13:00')) const timeCalc = new TimeCalc( 10, 10, true, 5000, 5001, 0, 0, 0, ) expect(timeCalc.setStartEndTime.bind(timeCalc, 6001, 6002)) .to.throw('Can\'t look up the correct time \'6001\' \'0\'') }) it.skip('should throw error if position is not set and dynamic time is requested', () => { setupTest() sinon.clock.setSystemTime(new Date('2023-01-01 13:00')) const timeCalc = new TimeCalc( undefined, undefined, true, 5000, 5001, 0, 0, 0, ) expect(timeCalc.setStartEndTime.bind(timeCalc, 5101, 5102)) .to.throw('Something went wrong, latitude and longitude not specified') }) it('should create data suitable for debug', () => { setupTest() sinon.clock.setSystemTime(new Date('2023-01-01 13:00')) const timeCalc = new TimeCalc( 10, 10, true, 5001, 5002, 0, 0, 0, ) expect(timeCalc.debug()).to.deep.equal({ moonTimes: { rise: 660, set: 720, }, now: 780, sunTimes: { dawn: 360, dusk: 1260, night: 1380, nightEnd: 240, solarNoon: 660, sunrise: 300, sunset: 1140, }, nextEnd: 1320, nextStart: 480, operationToday: 'normal', actualEnd: 660, actualStart: 1260, onState: false, }) }) })