node-red-contrib-mysensors
Version:
Mysensors related nodes, for decoding / encoding mysensors serial protocol and MQTT topic, and wrapping arbitrary messages into mysensors compatible messages
377 lines (329 loc) • 11 kB
text/typescript
import { expect } from 'chai';
import { NodeContextData } from 'node-red';
import { useSinonSandbox } from '../../test/sinon';
import {NoderedStorage} from './nodered-storage';
describe('lib/nodered-storage', () => {
const sinon = useSinonSandbox();
function setupStub(storageKey = 'test-key', store = 'test-store') {
const get = sinon.stub().named('get');
const set = sinon.stub().named('set');
const keys = sinon.stub().named('keys');
const context: NodeContextData = {
get,
set,
keys,
};
sinon.clock.setSystemTime(new Date('2023-01-01 01:00Z'));
return {
get,
set,
keys,
nodeRedStorage: new NoderedStorage(context, storageKey, store)
};
}
it('should set node heard attribute', async () => {
const {get, set, nodeRedStorage} = setupStub();
await nodeRedStorage.nodeHeard(1);
sinon.assert.calledOnce(get);
sinon.assert.calledWith(set, 'test-key', {
'1': {
batteryLevel: -1,
nodeId: 1,
label: '',
lastHeard: new Date('2023-01-01T01:00:00.000Z'),
lastRestart: new Date('2023-01-01T01:00:00.000Z'),
parentId: -1,
sensors: [],
sketchName: '',
sketchVersion: '',
used: 1
}
});
});
it('should set sketch name', async () => {
const {set, nodeRedStorage} = setupStub();
await nodeRedStorage.sketchName(2, 'test');
sinon.assert.calledWith(set, 'test-key', {
'2': {
batteryLevel: -1,
nodeId: 2,
label: '',
lastHeard: new Date('2023-01-01T01:00:00.000Z'),
lastRestart: new Date('2023-01-01T01:00:00.000Z'),
parentId: -1,
sensors: [],
sketchName: 'test',
sketchVersion: '',
used: 1
}
});
});
it('should set sketch version', async () => {
const {get, set, nodeRedStorage} = setupStub();
get.returns({
'2': {
batteryLevel: -1,
nodeId: 2,
label: '',
lastHeard: new Date('2023-01-01T01:00:00.000Z'),
lastRestart: new Date('2023-01-01T01:00:00.000Z'),
parentId: -1,
sensors: [],
sketchName: 'not-altered',
sketchVersion: 'not-valid',
used: 1
}
});
await nodeRedStorage.sketchVersion(2, '1.5');
sinon.assert.calledWith(set, 'test-key', {
'2': {
batteryLevel: -1,
nodeId: 2,
label: '',
lastHeard: new Date('2023-01-01T01:00:00.000Z'),
lastRestart: new Date('2023-01-01T01:00:00.000Z'),
parentId: -1,
sensors: [],
sketchName: 'not-altered',
sketchVersion: '1.5',
used: 1
}
});
});
it('should set child as heard', async () => {
const {get, set, nodeRedStorage} = setupStub();
get.returns({
'2': {
batteryLevel: -1,
nodeId: 2,
label: '',
lastHeard: new Date('1972-01-01T00:00:00.000Z'),
lastRestart: new Date('1972-01-01T00:00:00.000Z'),
parentId: -1,
sensors: [
{
childId: 5,
description: 'not-altered',
lastHeard: new Date('1969-01-01T00:00:00.000Z'),
nodeId: 2,
sType: 0,
},
],
sketchName: 'not-altered',
sketchVersion: 'not-valid',
used: 1
}
});
await nodeRedStorage.childHeard(2, 5);
sinon.assert.calledWith(set, 'test-key', {
'2': {
batteryLevel: -1,
nodeId: 2,
label: '',
lastHeard: new Date('1972-01-01T00:00:00.000Z'),
lastRestart: new Date('1972-01-01T00:00:00.000Z'),
parentId: -1,
sensors: [
{
childId: 5,
description: 'not-altered',
lastHeard: new Date('2023-01-01T01:00:00.000Z'),
nodeId: 2,
sType: 0,
},
],
sketchName: 'not-altered',
sketchVersion: 'not-valid',
used: 1
}
}, 'test-store');
});
it('should not set child node if there is no parent', async () => {
const {get, set, nodeRedStorage} = setupStub();
get.returns({
'2': {
batteryLevel: -1,
nodeId: 2,
label: '',
lastHeard: new Date('1972-01-01T00:00:00.000Z'),
lastRestart: new Date('1972-01-01T00:00:00.000Z'),
parentId: -1,
sensors: [
{
childId: 5,
description: 'not-altered',
lastHeard: new Date('1969-01-01T00:00:00.000Z'),
nodeId: 2,
sType: 0,
},
],
sketchName: 'not-altered',
sketchVersion: 'not-valid',
used: 1
}
});
await nodeRedStorage.childHeard(3, 5);
sinon.assert.notCalled(set);
});
it('should get list of nodes', async () => {
const { get, nodeRedStorage } = setupStub();
get.resolves({
'1': {
sketchName: 'heard',
used: true,
},
'2': {
sketchName: 'unknown',
used: false,
}
});
const result = await nodeRedStorage.getNodeList();
expect(result).to.deep.equal([
{
sketchName: 'heard',
used: true,
}
]);
});
it('should get a free node id to assign to a new node', async () => {
const { get, nodeRedStorage } = setupStub();
get.resolves({
'1': {
nodeId: 1,
sketchName: 'heard',
used: true,
},
'2': {
nodeId: 2,
sketchName: 'unknown',
used: false,
}
});
const result = await nodeRedStorage.getFreeNodeId();
expect(result).to.equal(2);
});
it('should get default child info if none is found', async () => {
const { get, nodeRedStorage } = setupStub();
get.resolves({
'1': {
nodeId: 1,
sketchName: 'heard',
used: true,
sensors: []
}
});
const result = await nodeRedStorage.getChild(1, 2);
expect(result).to.deep.equal({
nodeId: 1,
childId: 2,
sType: 0,
description: '',
lastHeard: new Date('2023-01-01T01:00:00.000Z'),
});
});
it('should get child info from context', async () => {
const { get, nodeRedStorage } = setupStub();
get.resolves({
'1': {
nodeId: 1,
sketchName: 'heard',
used: true,
sensors: [
{
childId: 2,
nodeId: 1,
lastHeard: new Date('1985-01-01'),
description: 'known child',
sType: 2,
}
]
}
});
const result = await nodeRedStorage.getChild(1, 2);
expect(result).to.deep.equal({
nodeId: 1,
childId: 2,
sType: 2,
description: 'known child',
lastHeard: new Date('1985-01-01'),
});
});
it('should set child details', async() => {
const { get, set, nodeRedStorage } = setupStub();
get.resolves({
'1': {
nodeId: 1,
sketchName: 'heard',
used: true,
sensors: [],
}
});
const result = await nodeRedStorage.child(1, 2, 5, 'some description');
expect(result).to.equal(undefined);
sinon.assert.calledWith(set, 'test-key', {
'1': {
nodeId: 1,
sketchName: 'heard',
used: true,
sensors: [
{
nodeId: 1,
childId: 2,
sType: 5,
description: 'some description',
lastHeard: new Date('2023-01-01T01:00:00.000Z'),
}
],
}
}, 'test-store');
});
it('should set parent node', async () => {
const { get, set, nodeRedStorage } = setupStub();
get.resolves({
'1': {
nodeId: 1,
sketchName: 'heard',
used: true,
sensors: [],
}
});
const result = await nodeRedStorage.setParent(1, 2);
expect(result).to.equal(undefined);
sinon.assert.calledWith(set, 'test-key', {
'1': {
nodeId: 1,
sketchName: 'heard',
used: true,
sensors: [],
parentId: 2,
}
}, 'test-store');
});
it('should set batterylevel for node', async () => {
const { get, set, nodeRedStorage } = setupStub();
get.resolves({
'1': {
nodeId: 1,
sketchName: 'heard',
used: true,
sensors: [],
}
});
const result = await nodeRedStorage.setBatteryLevel(1, 2);
expect(result).to.equal(undefined);
sinon.assert.calledWith(set, 'test-key', {
'1': {
nodeId: 1,
sketchName: 'heard',
used: true,
sensors: [],
batteryLevel: 2,
}
}, 'test-store');
});
it('should handle undefined context gracefully', async () => {
const nodeRedStorage = new NoderedStorage(undefined, '');
const result = await nodeRedStorage.setBatteryLevel(1, 2);
expect(result).to.equal(undefined);
});
});