UNPKG

node-red-contrib-sunevents

Version:

A node for node-red that generates events based on the position of the Sun at the appropriate time of day

226 lines (203 loc) 10.7 kB
/** * Copyright 2013-2023 Freak Enterprises * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * node-red-contrib-sunevents * This module provides a thin event emitting wrapper around the excellent SunCalc Module. * **/ const helper = require("node-red-node-test-helper") helper.init(require.resolve('node-red')); const SunEventsNode = require("../lib/sun-events-node.js") const test_lat = 37.53 const test_lng = -122.26 const events = ['sunrise', 'sunriseEnd', 'goldenHourEnd', 'solarNoon', 'goldenHour', 'sunsetStart', 'sunset', 'dusk', 'nauticalDusk', 'night', 'nightEnd', 'nauticalDawn', 'dawn', 'nadir'] describe('sun-events Node', function () { beforeEach(function (done) { jasmine.clock().install() helper.startServer(done); }); afterEach(function (done) { jasmine.clock().uninstall() helper.unload().then(function() { helper.stopServer(done); }) }); it('should be loaded', function (done) { let flow = [{ id: "n1", type: "sun events", name: "test name" }] helper.load(SunEventsNode, flow, function () { try { var n1 = helper.getNode("n1") expect(n1).toEqual(jasmine.objectContaining({ name: 'test name' })) done() } catch (err) { done(err) } }); }); it('should initialise a set of sun events', function(done) { var flow = [{ id: "n1", type: "sun events", name: "test name", wires: [["n2"]] }, { id: "n2", type: "helper" }]; helper.load(SunEventsNode, flow, function () { var n1 = helper.getNode("n1"); var n2 = helper.getNode("n2"); n2.on("input", function (msg) { try { //It should preserve any extra values passed in the msg expect(msg.misc).toEqual("hello world") expect(msg.payload.pi).toEqual(3.1459) expect(msg.payload.latitude).toEqual(test_lat) expect(msg.payload.longitude).toEqual(test_lng) expect(events.includes(msg.payload.sunevent)).toBeTrue() done(); } catch(err) { console.log(err) done(err) } }); for(let day = 0; day < 10; day++) { n1.receive({ misc: "hello world", payload: {pi: 3.1459, latitude: test_lat, longitude: test_lng }}); jasmine.clock().tick(1000 * 60 * 60 * 24) } }); }); it('should initialise a set of sun events with lat and lng as strings', function (done) { const test_lat_str = "51.501364" const test_lng_str = "-0.1440787" const flow = [{ id: "n1", type: "sun events", name: "test name", wires: [["n2"]] }, { id: "n2", type: "helper" }]; helper.load(SunEventsNode, flow, function () { let n2 = helper.getNode("n2"); let n1 = helper.getNode("n1"); n2.on("input", function (msg) { try { expect(msg.payload.lat).toEqual(test_lat_str) expect(msg.payload.lng).toEqual(test_lng_str) expect(events.includes(msg.payload.sunevent)).toBeTrue() done(); } catch(err) { done(err) } }); n1.receive({ payload: {lat: test_lat_str, lng: test_lng_str }}); jasmine.clock().tick(1000 * 60 * 60 * 24) }); }); it('should use lat and long from node configuration if none supplied in msg.payload, payload contains a date', function(done) { const test_credentials = { "n1": {'latitude': "51.501364", 'longitude': '-0.1440787' } } const flow = [{ id: "n1", type: "sun events", name: "test name", wires: [["n2"]] }, { id: "n2", type: "helper" }]; const timestamp = new Date() helper.load(SunEventsNode, flow, test_credentials, function () { let n1 = helper.getNode("n1"); let n2 = helper.getNode("n2"); expect(n2).toEqual(jasmine.objectContaining({ type: 'helper' })) // Don't forget to pass "done" into the it function !!! n2.on("input", function (msg) { try { // We didn't pass the lat and lng in so it shouldn't be in the payload // expect(msg.payload.lat).withContext("should match latitude").toEqual(test_credentials.n1.latitude) // expect(msg.payload.lng).withContext("should match longitude").toEqual(test_credentials.n1.longitude) expect(msg.payload).withContext(`payload ${msg.payload} should be a date`).toEqual(timestamp) expect(events.includes(msg.payload.sunevent)).withContext(`sunevent ${msg.payload.sunevent} is not known`).toBeTrue() done(); } catch(err) { done(err) } }); spyOn(n1, "error") n1.receive({ payload: timestamp }) expect(n1.error).not.toHaveBeenCalled() jasmine.clock().tick(1000 * 60 * 60 * 24) }); }) it('should use lat and long from node configuration if none supplied in msg.payload, payload contains a string', function(done) { const test_credentials = { "n1": {'latitude': "51.501364", 'longitude': '-0.1440787' } } const flow = [{ id: "n1", type: "sun events", name: "test name", wires: [["n2"]] }, { id: "n2", type: "helper" }]; helper.load(SunEventsNode, flow, test_credentials, function () { let n1 = helper.getNode("n1"); let n2 = helper.getNode("n2"); expect(n2).toEqual(jasmine.objectContaining({ type: 'helper' })) // Don't forget to pass "done" into the it function !!! n2.on("input", function (msg) { try { // We didn't pass the lat and lng in so it shouldn't be in the payload // expect(msg.payload.lat).withContext("should match latitude").toEqual(test_credentials.n1.latitude) // expect(msg.payload.lng).withContext("should match longitude").toEqual(test_credentials.n1.longitude) expect(msg.payload.value).toEqual('some random string') expect(events.includes(msg.payload.sunevent)).withContext(`sunevent ${msg.payload.sunevent} is not known`).toBeTrue() done(); } catch(err) { done(err) } }); spyOn(n1, "error") n1.receive({ payload: 'some random string' }) expect(n1.error).not.toHaveBeenCalled() jasmine.clock().tick(1000 * 60 * 60 * 24) }); }) it('should fail gracefully if no lat or long is supplied', function(done) { const test_credentials = { "n1": {} } const flow = [{ id: "n1", type: "sun events", name: "test name", wires: [["n2"]] }, { id: "n2", type: "helper" }]; helper.load(SunEventsNode, flow, test_credentials, function () { let n1 = helper.getNode("n1"); let n2 = helper.getNode("n2"); expect(n2).toEqual(jasmine.objectContaining({ type: 'helper' })) // Don't forget to pass "done" into the it function !!! n2.on("input", function (msg) { try { fail('no events should be output') done(); } catch(err) { done(err) } }); spyOn(n1, "error") spyOn(n2, "on") n1.receive({ payload: 'some random string' }) expect(n1.error).toHaveBeenCalled() jasmine.clock().tick(1000 * 60 * 60 * 24) expect(n2.on).not.toHaveBeenCalled() done() }); }) it('should return a set of missed events in the payload', function (done) { const start_date = new Date() const test_lat_str = "51.501364" const test_lng_str = "-0.1440787" const flow = [{ id: "n1", type: "sun events", name: "test name", wires: [["n2"], ["n3"]] }, { id: "n2", type: "helper" }, { id: "n3", type: "helper" }]; helper.load(SunEventsNode, flow, function () { let n1 = helper.getNode("n1"); let n2 = helper.getNode("n2"); let n3 = helper.getNode("n3"); n3.on("input", function (msg) { try { expect(msg.payload["sunevents"]).withContext(`looking for missed sunevents in msg.payload ${JSON.stringify(msg.payload)}`).toBeDefined() let last_event = msg.payload.sunevents[0] expect(last_event.datetime) .withContext(`Most recent missed event ${last_event.datetime.toISOString()} should be older than our start date ${start_date.toISOString()}`) .toBeLessThan(start_date) let event_before_last = msg.payload.sunevents[1] expect(event_before_last.datetime) .withContext(`Missed event before last ${event_before_last.datetime.toISOString()} should be older than the last event ${last_event.datetime.toISOString()}`) .toBeLessThan(last_event.datetime) let event_count = msg.payload.sunevents.filter( e => e.event_name == last_event.event_name).length expect(event_count) .withContext(`Missed event ${last_event.event_name} should only appear once ${JSON.stringify(msg.payload.sunevents)}`) .toBe(1) done(); } catch(err) { done(err) } }); n1.receive({ payload: {lat: test_lat_str, lng: test_lng_str }}); jasmine.clock().tick(1000 * 60 * 60 * 24) }); }); });