energy-manager-iot
Version:
Library for energy management in IoT devices via MQTT protocol. Documentation: https://jonhvmp.github.io/energy-manager-iot-docs/
194 lines (193 loc) • 8.96 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
const index_1 = require("../index");
const error_handler_1 = require("../utils/error-handler");
const mqtt = __importStar(require("mqtt"));
jest.mock('mqtt', () => {
const mockClient = {
on: jest.fn().mockReturnThis(),
end: jest.fn((_, __, cb) => cb && cb()),
publish: jest.fn((_, __, ___, cb) => cb && cb()),
subscribe: jest.fn((_, __, cb) => cb && cb()),
unsubscribe: jest.fn((_, cb) => cb && cb()),
removeAllListeners: jest.fn()
};
return {
connect: jest.fn().mockReturnValue(mockClient)
};
});
/**
* Advanced coverage tests for the EnergyManager class
*
* These tests focus on improving code coverage by testing specific
* behaviors and edge cases not covered by the main test suite.
*/
describe('EnergyManager - Advanced Coverage', () => {
let energyManager;
let mockMqttClient;
beforeEach(() => {
jest.clearAllMocks();
energyManager = new index_1.EnergyManager({
topicPrefix: 'advanced/test/',
statusInterval: 500
});
mockMqttClient = mqtt.connect('mqtt://localhost:1883');
});
afterEach(() => {
if (energyManager['statusCheckInterval']) {
clearInterval(energyManager['statusCheckInterval']);
}
energyManager.removeAllListeners();
});
describe('Topics and IDs', () => {
test('should correctly extract device ID from topic', () => {
// @ts-ignore - Access private method
const deviceId = energyManager['extractDeviceIdFromStatusTopic']('advanced/test/sensor123/status');
expect(deviceId).toBe('sensor123');
});
test('should return null for invalid topics', () => {
// @ts-ignore - Access private method
const deviceId1 = energyManager['extractDeviceIdFromStatusTopic']('wrong-prefix/sensor123/status');
// @ts-ignore - Access private method
const deviceId2 = energyManager['extractDeviceIdFromStatusTopic']('advanced/test/sensor123/command');
expect(deviceId1).toBeNull();
expect(deviceId2).toBeNull();
});
test('should generate unique request IDs', () => {
// @ts-ignore - Access private method
const requestId = energyManager['generateRequestId']();
expect(requestId).toMatch(/^req_\d+_[a-z0-9]+$/);
});
});
describe('Command Errors', () => {
test('should throw error when sending command to non-existent device', async () => {
// Simulate MQTT connection
Object.defineProperty(energyManager['mqtt'], 'isClientConnected', {
value: () => true
});
await expect(energyManager.sendCommand('non-existent', index_1.CommandType.SLEEP)).rejects.toThrow(error_handler_1.EnergyManagerError);
});
test('should handle error when publishing command', async () => {
// Register device
energyManager.registerDevice('sensor1', 'Sensor', index_1.DeviceType.SENSOR);
// Simulate MQTT connection
Object.defineProperty(energyManager['mqtt'], 'isClientConnected', {
value: () => true
});
// Simulate publish error
energyManager['mqtt'].publish = jest.fn().mockRejectedValue(new Error('Publish failed'));
await expect(energyManager.sendCommand('sensor1', index_1.CommandType.SLEEP)).rejects.toThrow();
});
test('should propagate error when sending command to group', async () => {
// Create group and add device
energyManager.createGroup('test-group');
energyManager.registerDevice('sensor1', 'Sensor', index_1.DeviceType.SENSOR);
energyManager.addDeviceToGroup('sensor1', 'test-group');
// Simulate MQTT connection
Object.defineProperty(energyManager['mqtt'], 'isClientConnected', {
value: () => true
});
// Simulate command error
energyManager.sendCommand = jest.fn().mockRejectedValue(new Error('Command failed'));
await expect(energyManager.sendCommandToGroup('test-group', index_1.CommandType.SLEEP)).rejects.toThrow(error_handler_1.EnergyManagerError);
});
});
describe('MQTT Events', () => {
beforeEach(() => {
// Simulate MQTT connection to test events
const connectPromise = energyManager.connect('mqtt://localhost:1883');
// Simulate connect callback
const onConnect = mockMqttClient.on.mock.calls.find((c) => c[0] === 'connect')?.[1];
if (onConnect)
onConnect();
return connectPromise;
});
test('should emit reconnect event', () => {
const reconnectListener = jest.fn();
energyManager.on('reconnecting', reconnectListener);
// Simulate reconnect event
const onReconnect = mockMqttClient.on.mock.calls.find((c) => c[0] === 'reconnect')?.[1];
if (onReconnect)
onReconnect();
expect(reconnectListener).toHaveBeenCalled();
});
test('should emit error event', () => {
const errorListener = jest.fn();
energyManager.on('error', errorListener);
const testError = new Error('Test error');
// Simulate error event
const onError = mockMqttClient.on.mock.calls.find((c) => c[0] === 'error')?.[1];
if (onError)
onError(testError);
expect(errorListener).toHaveBeenCalledWith(testError);
});
});
describe('Topic Subscriptions', () => {
test('should subscribe to all device status topics', async () => {
// Register devices
energyManager.registerDevice('sensor1', 'Sensor 1', index_1.DeviceType.SENSOR);
energyManager.registerDevice('sensor2', 'Sensor 2', index_1.DeviceType.SENSOR);
// Spy on subscribe method
const subscribeSpy = jest.spyOn(energyManager['mqtt'], 'subscribe')
.mockResolvedValue();
// Simulate connected state
Object.defineProperty(energyManager['mqtt'], 'isClientConnected', {
value: () => true
});
// @ts-ignore - Access private method
await energyManager['subscribeToAllDeviceStatuses']();
// Should call subscribe for each device
expect(subscribeSpy).toHaveBeenCalledTimes(2);
expect(subscribeSpy).toHaveBeenCalledWith('advanced/test/sensor1/status');
expect(subscribeSpy).toHaveBeenCalledWith('advanced/test/sensor2/status');
});
test('should not attempt to subscribe when disconnected', async () => {
// Register device
energyManager.registerDevice('sensor1', 'Sensor', index_1.DeviceType.SENSOR);
// Spy on subscribe method
const subscribeSpy = jest.spyOn(energyManager['mqtt'], 'subscribe')
.mockResolvedValue();
// Simulate disconnected state
Object.defineProperty(energyManager['mqtt'], 'isClientConnected', {
value: () => false
});
// @ts-ignore - Access private method
await energyManager['subscribeToAllDeviceStatuses']();
// Should not call subscribe
expect(subscribeSpy).not.toHaveBeenCalled();
});
});
});