homebridge-tsvesync 1.3.11 → 1.3.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +26 -0
- package/README.md +3 -0
- package/dist/accessories/air-quality-sensor.accessory.d.ts +4 -0
- package/dist/accessories/air-quality-sensor.accessory.d.ts.map +1 -1
- package/dist/accessories/air-quality-sensor.accessory.js +81 -12
- package/dist/accessories/air-quality-sensor.accessory.js.map +1 -1
- package/dist/accessories/base.accessory.d.ts.map +1 -1
- package/dist/accessories/base.accessory.js +1 -3
- package/dist/accessories/base.accessory.js.map +1 -1
- package/dist/accessories/light.accessory.d.ts.map +1 -1
- package/dist/accessories/light.accessory.js +27 -2
- package/dist/accessories/light.accessory.js.map +1 -1
- package/dist/types/device.types.d.ts +6 -0
- package/dist/types/device.types.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/__tests__/accessories/air-purifier-integration.test.ts +2 -2
- package/src/__tests__/accessories/air-quality-methods.test.ts +10 -12
- package/src/__tests__/accessories/air-quality-sensor.accessory.test.ts +231 -0
- package/src/__tests__/base.accessory.test.ts +2 -2
- package/src/__tests__/devices/light.test.ts +4 -0
- package/src/accessories/air-quality-sensor.accessory.ts +93 -15
- package/src/accessories/base.accessory.ts +1 -2
- package/src/accessories/light.accessory.ts +28 -2
- package/src/types/device.types.ts +3 -0
- package/src/__tests__/accessories/air-purifier-air-quality.test.ts +0 -483
|
@@ -1,483 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Unit tests for AirPurifierAccessory air quality features
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { API } from 'homebridge';
|
|
6
|
-
import { Logger } from 'homebridge';
|
|
7
|
-
import { CharacteristicValue } from 'homebridge';
|
|
8
|
-
import { TSVESyncPlatform } from '../../platform';
|
|
9
|
-
import { VeSync } from 'tsvesync';
|
|
10
|
-
import { AirPurifierAccessory } from '../../accessories/air-purifier.accessory';
|
|
11
|
-
import { createMockLogger, createMockVeSync, createMockService } from '../utils/test-helpers';
|
|
12
|
-
|
|
13
|
-
// Extended mock for air purifier with air quality features
|
|
14
|
-
interface MockAirPurifierWithAirQuality {
|
|
15
|
-
deviceName: string;
|
|
16
|
-
deviceType: string;
|
|
17
|
-
cid: string;
|
|
18
|
-
uuid: string;
|
|
19
|
-
deviceStatus: string;
|
|
20
|
-
hasFeature: jest.Mock;
|
|
21
|
-
airQualityValue: number;
|
|
22
|
-
pm1: number;
|
|
23
|
-
pm10: number;
|
|
24
|
-
filterLife: number;
|
|
25
|
-
details?: {
|
|
26
|
-
air_quality_value?: number;
|
|
27
|
-
pm25?: number;
|
|
28
|
-
pm1?: number;
|
|
29
|
-
pm10?: number;
|
|
30
|
-
filter_life?: number | { percent: number };
|
|
31
|
-
};
|
|
32
|
-
getDetails: jest.Mock;
|
|
33
|
-
turnOn: jest.Mock;
|
|
34
|
-
turnOff: jest.Mock;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
describe('AirPurifierAccessory Air Quality Features', () => {
|
|
38
|
-
let mockAPI: jest.Mocked<API>;
|
|
39
|
-
let platform: TSVESyncPlatform;
|
|
40
|
-
let logger: jest.Mocked<Logger>;
|
|
41
|
-
let api: jest.Mocked<VeSync>;
|
|
42
|
-
let airQualityService: any;
|
|
43
|
-
let airPurifierService: any;
|
|
44
|
-
let infoService: any;
|
|
45
|
-
|
|
46
|
-
beforeEach(() => {
|
|
47
|
-
logger = createMockLogger();
|
|
48
|
-
api = createMockVeSync();
|
|
49
|
-
|
|
50
|
-
mockAPI = {
|
|
51
|
-
hap: {
|
|
52
|
-
Characteristic: {
|
|
53
|
-
AirQuality: jest.fn(),
|
|
54
|
-
PM2_5Density: jest.fn(),
|
|
55
|
-
PM10Density: jest.fn(),
|
|
56
|
-
Active: jest.fn(),
|
|
57
|
-
CurrentAirPurifierState: jest.fn(),
|
|
58
|
-
TargetAirPurifierState: jest.fn(),
|
|
59
|
-
RotationSpeed: jest.fn(),
|
|
60
|
-
Manufacturer: jest.fn(),
|
|
61
|
-
Model: jest.fn(),
|
|
62
|
-
SerialNumber: jest.fn(),
|
|
63
|
-
},
|
|
64
|
-
Service: {
|
|
65
|
-
AirPurifier: jest.fn(),
|
|
66
|
-
AirQualitySensor: jest.fn(),
|
|
67
|
-
AccessoryInformation: jest.fn(),
|
|
68
|
-
},
|
|
69
|
-
uuid: {
|
|
70
|
-
generate: jest.fn(),
|
|
71
|
-
},
|
|
72
|
-
},
|
|
73
|
-
platformAccessory: jest.fn(),
|
|
74
|
-
} as any;
|
|
75
|
-
|
|
76
|
-
platform = new TSVESyncPlatform(logger, {} as any, mockAPI);
|
|
77
|
-
(platform as any).api = api;
|
|
78
|
-
|
|
79
|
-
// Setup mock services
|
|
80
|
-
airQualityService = createMockService();
|
|
81
|
-
airPurifierService = createMockService();
|
|
82
|
-
infoService = {
|
|
83
|
-
setCharacteristic: jest.fn().mockReturnThis(),
|
|
84
|
-
};
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
function createMockAirPurifier(config: Partial<MockAirPurifierWithAirQuality> = {}): MockAirPurifierWithAirQuality {
|
|
88
|
-
return {
|
|
89
|
-
deviceName: config.deviceName || 'Test Air Purifier',
|
|
90
|
-
deviceType: config.deviceType || 'Core300S',
|
|
91
|
-
cid: config.cid || 'test-cid',
|
|
92
|
-
uuid: config.uuid || 'test-uuid',
|
|
93
|
-
deviceStatus: config.deviceStatus || 'on',
|
|
94
|
-
airQualityValue: config.airQualityValue || 25,
|
|
95
|
-
pm1: config.pm1 || 15,
|
|
96
|
-
pm10: config.pm10 || 35,
|
|
97
|
-
filterLife: config.filterLife || 75,
|
|
98
|
-
details: config.details || {
|
|
99
|
-
air_quality_value: config.airQualityValue || 25,
|
|
100
|
-
pm1: config.pm1 || 15,
|
|
101
|
-
pm10: config.pm10 || 35,
|
|
102
|
-
filter_life: config.filterLife || 75,
|
|
103
|
-
},
|
|
104
|
-
hasFeature: jest.fn().mockImplementation((feature: string) => {
|
|
105
|
-
return feature === 'air_quality';
|
|
106
|
-
}),
|
|
107
|
-
getDetails: jest.fn().mockResolvedValue(true),
|
|
108
|
-
turnOn: jest.fn().mockResolvedValue(true),
|
|
109
|
-
turnOff: jest.fn().mockResolvedValue(true),
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
describe('Air Quality Service Setup', () => {
|
|
114
|
-
it('should create air quality service for devices with air quality support', () => {
|
|
115
|
-
const mockDevice = createMockAirPurifier({ airQualityValue: 20 });
|
|
116
|
-
|
|
117
|
-
const accessory = {
|
|
118
|
-
getService: jest.fn((service) => {
|
|
119
|
-
if (service === platform.Service.AccessoryInformation) return infoService;
|
|
120
|
-
if (service === platform.Service.AirPurifier) return airPurifierService;
|
|
121
|
-
if (service === platform.Service.AirQualitySensor) return null; // Not created yet
|
|
122
|
-
return null;
|
|
123
|
-
}),
|
|
124
|
-
addService: jest.fn((service) => {
|
|
125
|
-
if (service === platform.Service.AirQualitySensor) return airQualityService;
|
|
126
|
-
return airQualityService;
|
|
127
|
-
}),
|
|
128
|
-
};
|
|
129
|
-
|
|
130
|
-
const airPurifier = new AirPurifierAccessory(platform, accessory as any, mockDevice as any);
|
|
131
|
-
|
|
132
|
-
// Verify air quality service was added
|
|
133
|
-
expect(accessory.addService).toHaveBeenCalledWith(platform.Service.AirQualitySensor);
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
it('should not create air quality service for devices without air quality support', () => {
|
|
137
|
-
const mockDevice = createMockAirPurifier();
|
|
138
|
-
mockDevice.hasFeature = jest.fn().mockReturnValue(false);
|
|
139
|
-
|
|
140
|
-
const accessory = {
|
|
141
|
-
getService: jest.fn((service) => {
|
|
142
|
-
if (service === platform.Service.AccessoryInformation) return infoService;
|
|
143
|
-
if (service === platform.Service.AirPurifier) return airPurifierService;
|
|
144
|
-
return null;
|
|
145
|
-
}),
|
|
146
|
-
addService: jest.fn(),
|
|
147
|
-
};
|
|
148
|
-
|
|
149
|
-
const airPurifier = new AirPurifierAccessory(platform, accessory as any, mockDevice as any);
|
|
150
|
-
|
|
151
|
-
// Verify air quality service was not added
|
|
152
|
-
expect(accessory.addService).not.toHaveBeenCalledWith(platform.Service.AirQualitySensor);
|
|
153
|
-
});
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
describe('Air Quality Value Conversion', () => {
|
|
157
|
-
let airPurifier: AirPurifierAccessory;
|
|
158
|
-
let mockDevice: MockAirPurifierWithAirQuality;
|
|
159
|
-
|
|
160
|
-
beforeEach(() => {
|
|
161
|
-
mockDevice = createMockAirPurifier();
|
|
162
|
-
|
|
163
|
-
const accessory = {
|
|
164
|
-
getService: jest.fn((service) => {
|
|
165
|
-
if (service === platform.Service.AccessoryInformation) return infoService;
|
|
166
|
-
if (service === platform.Service.AirPurifier) return airPurifierService;
|
|
167
|
-
if (service === platform.Service.AirQualitySensor) return airQualityService;
|
|
168
|
-
return null;
|
|
169
|
-
}),
|
|
170
|
-
addService: jest.fn(),
|
|
171
|
-
};
|
|
172
|
-
|
|
173
|
-
airPurifier = new AirPurifierAccessory(platform, accessory as any, mockDevice as any);
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
it('should convert PM2.5 values to HomeKit air quality scale', async () => {
|
|
177
|
-
const testCases = [
|
|
178
|
-
{ pm25: 0, expected: 1 }, // EXCELLENT
|
|
179
|
-
{ pm25: 12, expected: 1 }, // EXCELLENT (0-12)
|
|
180
|
-
{ pm25: 13, expected: 2 }, // GOOD (13-35)
|
|
181
|
-
{ pm25: 35, expected: 2 }, // GOOD
|
|
182
|
-
{ pm25: 36, expected: 3 }, // FAIR (36-55)
|
|
183
|
-
{ pm25: 55, expected: 3 }, // FAIR
|
|
184
|
-
{ pm25: 56, expected: 4 }, // INFERIOR (56-150)
|
|
185
|
-
{ pm25: 150, expected: 4 }, // INFERIOR
|
|
186
|
-
{ pm25: 151, expected: 5 }, // POOR (>150)
|
|
187
|
-
{ pm25: 300, expected: 5 }, // POOR
|
|
188
|
-
];
|
|
189
|
-
|
|
190
|
-
for (const testCase of testCases) {
|
|
191
|
-
mockDevice.airQualityValue = testCase.pm25;
|
|
192
|
-
mockDevice.details!.air_quality_value = testCase.pm25;
|
|
193
|
-
|
|
194
|
-
const result = await (airPurifier as any).getAirQuality();
|
|
195
|
-
expect(result).toBe(testCase.expected);
|
|
196
|
-
}
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
it('should handle edge cases in PM2.5 conversion', async () => {
|
|
200
|
-
// Test boundary values
|
|
201
|
-
mockDevice.airQualityValue = 12.5;
|
|
202
|
-
mockDevice.details!.air_quality_value = 12.5;
|
|
203
|
-
let result = await (airPurifier as any).getAirQuality();
|
|
204
|
-
expect(result).toBe(1); // Should round down to EXCELLENT
|
|
205
|
-
|
|
206
|
-
mockDevice.airQualityValue = 35.5;
|
|
207
|
-
mockDevice.details!.air_quality_value = 35.5;
|
|
208
|
-
result = await (airPurifier as any).getAirQuality();
|
|
209
|
-
expect(result).toBe(3); // Should round to FAIR
|
|
210
|
-
});
|
|
211
|
-
|
|
212
|
-
it('should handle zero PM2.5 values', async () => {
|
|
213
|
-
mockDevice.airQualityValue = 0;
|
|
214
|
-
mockDevice.details!.air_quality_value = 0;
|
|
215
|
-
|
|
216
|
-
const result = await (airPurifier as any).getAirQuality();
|
|
217
|
-
expect(result).toBe(1); // EXCELLENT
|
|
218
|
-
});
|
|
219
|
-
|
|
220
|
-
it('should handle extremely high PM2.5 values', async () => {
|
|
221
|
-
mockDevice.airQualityValue = 999;
|
|
222
|
-
mockDevice.details!.air_quality_value = 999;
|
|
223
|
-
|
|
224
|
-
const result = await (airPurifier as any).getAirQuality();
|
|
225
|
-
expect(result).toBe(5); // POOR
|
|
226
|
-
});
|
|
227
|
-
});
|
|
228
|
-
|
|
229
|
-
describe('PM2.5 Density Characteristic', () => {
|
|
230
|
-
let airPurifier: AirPurifierAccessory;
|
|
231
|
-
let mockDevice: MockAirPurifierWithAirQuality;
|
|
232
|
-
|
|
233
|
-
beforeEach(() => {
|
|
234
|
-
mockDevice = createMockAirPurifier();
|
|
235
|
-
|
|
236
|
-
const accessory = {
|
|
237
|
-
getService: jest.fn((service) => {
|
|
238
|
-
if (service === platform.Service.AirQualitySensor) return airQualityService;
|
|
239
|
-
return airPurifierService;
|
|
240
|
-
}),
|
|
241
|
-
addService: jest.fn(),
|
|
242
|
-
};
|
|
243
|
-
|
|
244
|
-
airPurifier = new AirPurifierAccessory(platform, accessory as any, mockDevice as any);
|
|
245
|
-
});
|
|
246
|
-
|
|
247
|
-
it('should return PM2.5 density within HomeKit limits', async () => {
|
|
248
|
-
mockDevice.airQualityValue = 42;
|
|
249
|
-
mockDevice.details!.air_quality_value = 42;
|
|
250
|
-
|
|
251
|
-
const result = await (airPurifier as any).getPM25Density();
|
|
252
|
-
expect(result).toBe(42);
|
|
253
|
-
expect(result).toBeGreaterThanOrEqual(0);
|
|
254
|
-
expect(result).toBeLessThanOrEqual(1000);
|
|
255
|
-
});
|
|
256
|
-
|
|
257
|
-
it('should clamp PM2.5 values above 1000', async () => {
|
|
258
|
-
mockDevice.airQualityValue = 1500;
|
|
259
|
-
mockDevice.details!.air_quality_value = 1500;
|
|
260
|
-
|
|
261
|
-
const result = await (airPurifier as any).getPM25Density();
|
|
262
|
-
expect(result).toBe(1000); // Clamped to maximum
|
|
263
|
-
});
|
|
264
|
-
|
|
265
|
-
it('should handle negative PM2.5 values', async () => {
|
|
266
|
-
mockDevice.airQualityValue = -10;
|
|
267
|
-
mockDevice.details!.air_quality_value = -10;
|
|
268
|
-
|
|
269
|
-
const result = await (airPurifier as any).getPM25Density();
|
|
270
|
-
expect(result).toBe(0); // Clamped to minimum
|
|
271
|
-
});
|
|
272
|
-
|
|
273
|
-
it('should fallback to pm25 field if air_quality_value is missing', async () => {
|
|
274
|
-
mockDevice.airQualityValue = 35;
|
|
275
|
-
mockDevice.details!.pm25 = 35;
|
|
276
|
-
delete mockDevice.details!.air_quality_value;
|
|
277
|
-
|
|
278
|
-
const result = await (airPurifier as any).getPM25Density();
|
|
279
|
-
expect(result).toBe(35);
|
|
280
|
-
});
|
|
281
|
-
});
|
|
282
|
-
|
|
283
|
-
describe('PM10 Density Characteristic', () => {
|
|
284
|
-
let airPurifier: AirPurifierAccessory;
|
|
285
|
-
let mockDevice: MockAirPurifierWithAirQuality;
|
|
286
|
-
|
|
287
|
-
beforeEach(() => {
|
|
288
|
-
mockDevice = createMockAirPurifier({ pm10: 45 });
|
|
289
|
-
|
|
290
|
-
const accessory = {
|
|
291
|
-
getService: jest.fn((service) => {
|
|
292
|
-
if (service === platform.Service.AirQualitySensor) return airQualityService;
|
|
293
|
-
return airPurifierService;
|
|
294
|
-
}),
|
|
295
|
-
addService: jest.fn(),
|
|
296
|
-
};
|
|
297
|
-
|
|
298
|
-
airPurifier = new AirPurifierAccessory(platform, accessory as any, mockDevice as any);
|
|
299
|
-
});
|
|
300
|
-
|
|
301
|
-
it('should return PM10 density when available', async () => {
|
|
302
|
-
const result = await (airPurifier as any).getPM10Density();
|
|
303
|
-
expect(result).toBe(45);
|
|
304
|
-
});
|
|
305
|
-
|
|
306
|
-
it('should handle PM10 values above HomeKit limit', async () => {
|
|
307
|
-
mockDevice.pm10 = 1200;
|
|
308
|
-
mockDevice.details!.pm10 = 1200;
|
|
309
|
-
|
|
310
|
-
const result = await (airPurifier as any).getPM10Density();
|
|
311
|
-
expect(result).toBe(1000); // Clamped to maximum
|
|
312
|
-
});
|
|
313
|
-
|
|
314
|
-
it('should handle missing PM10 data', async () => {
|
|
315
|
-
mockDevice.pm10 = 0;
|
|
316
|
-
delete mockDevice.details!.pm10;
|
|
317
|
-
|
|
318
|
-
const result = await (airPurifier as any).getPM10Density();
|
|
319
|
-
expect(result).toBe(0);
|
|
320
|
-
});
|
|
321
|
-
|
|
322
|
-
it('should only add PM10 characteristic when data is available', () => {
|
|
323
|
-
// Device without PM10 data
|
|
324
|
-
const deviceWithoutPM10 = createMockAirPurifier({ pm10: 0 });
|
|
325
|
-
delete deviceWithoutPM10.details!.pm10;
|
|
326
|
-
|
|
327
|
-
const accessory = {
|
|
328
|
-
getService: jest.fn(() => airQualityService),
|
|
329
|
-
addService: jest.fn(() => airQualityService),
|
|
330
|
-
};
|
|
331
|
-
|
|
332
|
-
const setupCharacteristicSpy = jest.spyOn(AirPurifierAccessory.prototype as any, 'setupCharacteristic');
|
|
333
|
-
|
|
334
|
-
new AirPurifierAccessory(platform, accessory as any, deviceWithoutPM10 as any);
|
|
335
|
-
|
|
336
|
-
// PM10 characteristic should not be set up
|
|
337
|
-
const pm10Calls = setupCharacteristicSpy.mock.calls.filter(call =>
|
|
338
|
-
call[0] === platform.Characteristic.PM10Density
|
|
339
|
-
);
|
|
340
|
-
expect(pm10Calls).toHaveLength(0);
|
|
341
|
-
});
|
|
342
|
-
});
|
|
343
|
-
|
|
344
|
-
describe('Air Quality Data Updates', () => {
|
|
345
|
-
let airPurifier: AirPurifierAccessory;
|
|
346
|
-
let mockDevice: MockAirPurifierWithAirQuality;
|
|
347
|
-
let mockCharacteristic: any;
|
|
348
|
-
|
|
349
|
-
beforeEach(() => {
|
|
350
|
-
mockCharacteristic = {
|
|
351
|
-
updateValue: jest.fn(),
|
|
352
|
-
};
|
|
353
|
-
|
|
354
|
-
mockDevice = createMockAirPurifier();
|
|
355
|
-
|
|
356
|
-
const accessory = {
|
|
357
|
-
getService: jest.fn(() => ({
|
|
358
|
-
getCharacteristic: jest.fn(() => mockCharacteristic),
|
|
359
|
-
})),
|
|
360
|
-
addService: jest.fn(),
|
|
361
|
-
};
|
|
362
|
-
|
|
363
|
-
airPurifier = new AirPurifierAccessory(platform, accessory as any, mockDevice as any);
|
|
364
|
-
});
|
|
365
|
-
|
|
366
|
-
it('should update air quality characteristics when device updates', async () => {
|
|
367
|
-
// Simulate device update
|
|
368
|
-
mockDevice.airQualityValue = 55;
|
|
369
|
-
mockDevice.pm10 = 75;
|
|
370
|
-
|
|
371
|
-
await (airPurifier as any).updateDeviceState();
|
|
372
|
-
|
|
373
|
-
// Verify characteristics were updated (exact calls depend on implementation)
|
|
374
|
-
expect(mockCharacteristic.updateValue).toHaveBeenCalled();
|
|
375
|
-
});
|
|
376
|
-
|
|
377
|
-
it('should handle real-time air quality changes', async () => {
|
|
378
|
-
const initialPM25 = 20;
|
|
379
|
-
const updatedPM25 = 80;
|
|
380
|
-
|
|
381
|
-
// Initial state
|
|
382
|
-
mockDevice.airQualityValue = initialPM25;
|
|
383
|
-
await (airPurifier as any).getAirQuality();
|
|
384
|
-
|
|
385
|
-
// Update state
|
|
386
|
-
mockDevice.airQualityValue = updatedPM25;
|
|
387
|
-
mockDevice.details!.air_quality_value = updatedPM25;
|
|
388
|
-
|
|
389
|
-
const newResult = await (airPurifier as any).getAirQuality();
|
|
390
|
-
expect(newResult).toBe(4); // Should be INFERIOR for PM2.5 = 80
|
|
391
|
-
});
|
|
392
|
-
|
|
393
|
-
it('should handle air quality improvements', async () => {
|
|
394
|
-
// Start with poor air quality
|
|
395
|
-
mockDevice.airQualityValue = 200;
|
|
396
|
-
let result = await (airPurifier as any).getAirQuality();
|
|
397
|
-
expect(result).toBe(5); // POOR
|
|
398
|
-
|
|
399
|
-
// Air quality improves
|
|
400
|
-
mockDevice.airQualityValue = 25;
|
|
401
|
-
mockDevice.details!.air_quality_value = 25;
|
|
402
|
-
result = await (airPurifier as any).getAirQuality();
|
|
403
|
-
expect(result).toBe(2); // GOOD
|
|
404
|
-
});
|
|
405
|
-
});
|
|
406
|
-
|
|
407
|
-
describe('Error Handling', () => {
|
|
408
|
-
let airPurifier: AirPurifierAccessory;
|
|
409
|
-
let mockDevice: MockAirPurifierWithAirQuality;
|
|
410
|
-
|
|
411
|
-
beforeEach(() => {
|
|
412
|
-
mockDevice = createMockAirPurifier();
|
|
413
|
-
|
|
414
|
-
const accessory = {
|
|
415
|
-
getService: jest.fn(() => airQualityService),
|
|
416
|
-
addService: jest.fn(),
|
|
417
|
-
};
|
|
418
|
-
|
|
419
|
-
airPurifier = new AirPurifierAccessory(platform, accessory as any, mockDevice as any);
|
|
420
|
-
});
|
|
421
|
-
|
|
422
|
-
it('should handle missing air quality data gracefully', async () => {
|
|
423
|
-
mockDevice.airQualityValue = 0;
|
|
424
|
-
delete mockDevice.details!.air_quality_value;
|
|
425
|
-
delete mockDevice.details!.pm25;
|
|
426
|
-
|
|
427
|
-
const result = await (airPurifier as any).getAirQuality();
|
|
428
|
-
expect(result).toBe(1); // Default to EXCELLENT for 0 value
|
|
429
|
-
});
|
|
430
|
-
|
|
431
|
-
it('should handle device API errors', async () => {
|
|
432
|
-
mockDevice.getDetails = jest.fn().mockRejectedValue(new Error('API Error'));
|
|
433
|
-
|
|
434
|
-
// Should not throw error
|
|
435
|
-
await expect((airPurifier as any).getAirQuality()).resolves.toBeDefined();
|
|
436
|
-
});
|
|
437
|
-
|
|
438
|
-
it('should handle corrupted device data', async () => {
|
|
439
|
-
mockDevice.details = null as any;
|
|
440
|
-
|
|
441
|
-
const result = await (airPurifier as any).getAirQuality();
|
|
442
|
-
expect(result).toBe(1); // Default to EXCELLENT
|
|
443
|
-
});
|
|
444
|
-
|
|
445
|
-
it('should handle non-numeric air quality values', async () => {
|
|
446
|
-
mockDevice.airQualityValue = NaN;
|
|
447
|
-
mockDevice.details!.air_quality_value = NaN;
|
|
448
|
-
|
|
449
|
-
const result = await (airPurifier as any).getAirQuality();
|
|
450
|
-
expect(result).toBe(1); // Default to EXCELLENT for NaN
|
|
451
|
-
});
|
|
452
|
-
});
|
|
453
|
-
|
|
454
|
-
describe('Feature Detection', () => {
|
|
455
|
-
it('should detect air quality support correctly', () => {
|
|
456
|
-
const deviceWithAirQuality = createMockAirPurifier();
|
|
457
|
-
deviceWithAirQuality.hasFeature = jest.fn().mockReturnValue(true);
|
|
458
|
-
|
|
459
|
-
const accessory = {
|
|
460
|
-
getService: jest.fn(),
|
|
461
|
-
addService: jest.fn(() => airQualityService),
|
|
462
|
-
};
|
|
463
|
-
|
|
464
|
-
const airPurifier = new AirPurifierAccessory(platform, accessory as any, deviceWithAirQuality as any);
|
|
465
|
-
|
|
466
|
-
expect(deviceWithAirQuality.hasFeature).toHaveBeenCalledWith('air_quality');
|
|
467
|
-
});
|
|
468
|
-
|
|
469
|
-
it('should handle devices without air quality support', () => {
|
|
470
|
-
const deviceWithoutAirQuality = createMockAirPurifier();
|
|
471
|
-
deviceWithoutAirQuality.hasFeature = jest.fn().mockReturnValue(false);
|
|
472
|
-
|
|
473
|
-
const accessory = {
|
|
474
|
-
getService: jest.fn(),
|
|
475
|
-
addService: jest.fn(),
|
|
476
|
-
};
|
|
477
|
-
|
|
478
|
-
new AirPurifierAccessory(platform, accessory as any, deviceWithoutAirQuality as any);
|
|
479
|
-
|
|
480
|
-
expect(accessory.addService).not.toHaveBeenCalledWith(platform.Service.AirQualitySensor);
|
|
481
|
-
});
|
|
482
|
-
});
|
|
483
|
-
});
|