tsvesync 1.0.89 → 1.0.91

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.
@@ -0,0 +1,283 @@
1
+ "use strict";
2
+ /**
3
+ * Unit tests for VeSyncAirBaseV2 air quality data parsing
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const airBaseV2_1 = require("../../lib/fans/airBaseV2");
7
+ // Mock VeSync manager
8
+ const mockManager = {
9
+ username: 'test@example.com',
10
+ password: 'testpass',
11
+ token: 'testtoken',
12
+ accountID: 'testaccount',
13
+ apiKey: 'testapikey',
14
+ apiBase: 'testbase',
15
+ timezone: 'UTC'
16
+ };
17
+ describe('VeSyncAirBaseV2 Air Quality Features', () => {
18
+ let device;
19
+ beforeEach(() => {
20
+ const deviceDetails = {
21
+ deviceName: 'LAP-V102S Test',
22
+ deviceType: 'LAP-V102S-AASR',
23
+ cid: 'test-cid',
24
+ uuid: 'test-uuid',
25
+ deviceStatus: 'on',
26
+ deviceRegion: 'US',
27
+ configModule: 'VeSyncAirBaseV2',
28
+ macId: '00:11:22:33:44:55',
29
+ deviceCategory: 'fan',
30
+ connectionStatus: 'online'
31
+ };
32
+ device = new airBaseV2_1.VeSyncAirBaseV2(deviceDetails, mockManager);
33
+ });
34
+ describe('Air Quality Data Parsing', () => {
35
+ it('should parse comprehensive air quality data', () => {
36
+ const mockResponse = {
37
+ result: {
38
+ code: 0,
39
+ result: {
40
+ enabled: true,
41
+ mode: 'auto',
42
+ level: 2,
43
+ speed: 2,
44
+ display: 'on',
45
+ child_lock: false,
46
+ night_light: 'off',
47
+ air_quality: 'Good',
48
+ air_quality_value: 18,
49
+ pm1: 12,
50
+ pm10: 22,
51
+ aq_percent: 85,
52
+ filter_life: 78,
53
+ timer_remain: 3600
54
+ }
55
+ }
56
+ };
57
+ device.details = mockResponse.result.result;
58
+ expect(device.airQualityLevel).toBe('Good');
59
+ expect(device.airQualityValue).toBe(18);
60
+ expect(device.pm1).toBe(12);
61
+ expect(device.pm10).toBe(22);
62
+ expect(device.aqPercent).toBe(85);
63
+ expect(device.filterLife).toBe(78);
64
+ });
65
+ it('should handle numeric air quality levels', () => {
66
+ device.details = {
67
+ air_quality: 3,
68
+ air_quality_value: 45,
69
+ pm1: 25,
70
+ pm10: 65,
71
+ filter_life: 45
72
+ };
73
+ expect(device.airQualityLevel).toBe(3);
74
+ expect(device.airQualityValue).toBe(45);
75
+ expect(device.pm1).toBe(25);
76
+ expect(device.pm10).toBe(65);
77
+ });
78
+ it('should handle string air quality levels', () => {
79
+ const qualityLevels = ['Excellent', 'Good', 'Fair', 'Poor', 'Very Poor'];
80
+ qualityLevels.forEach((level, index) => {
81
+ device.details = {
82
+ air_quality: level,
83
+ air_quality_value: (index + 1) * 20
84
+ };
85
+ expect(device.airQualityLevel).toBe(level);
86
+ expect(device.airQualityValue).toBe((index + 1) * 20);
87
+ });
88
+ });
89
+ it('should handle missing PM data gracefully', () => {
90
+ device.details = {
91
+ air_quality: 'Good',
92
+ air_quality_value: 20,
93
+ filter_life: 60
94
+ // pm1 and pm10 missing
95
+ };
96
+ expect(device.airQualityLevel).toBe('Good');
97
+ expect(device.airQualityValue).toBe(20);
98
+ expect(device.pm1).toBe(0);
99
+ expect(device.pm10).toBe(0);
100
+ expect(device.aqPercent).toBe(0);
101
+ });
102
+ it('should handle all PM values at zero', () => {
103
+ device.details = {
104
+ air_quality: 'Excellent',
105
+ air_quality_value: 0,
106
+ pm1: 0,
107
+ pm10: 0,
108
+ aq_percent: 100
109
+ };
110
+ expect(device.airQualityValue).toBe(0);
111
+ expect(device.pm1).toBe(0);
112
+ expect(device.pm10).toBe(0);
113
+ expect(device.aqPercent).toBe(100);
114
+ });
115
+ it('should handle extreme air quality values', () => {
116
+ device.details = {
117
+ air_quality: 'Hazardous',
118
+ air_quality_value: 300,
119
+ pm1: 200,
120
+ pm10: 400,
121
+ aq_percent: 5,
122
+ filter_life: 15
123
+ };
124
+ expect(device.airQualityLevel).toBe('Hazardous');
125
+ expect(device.airQualityValue).toBe(300);
126
+ expect(device.pm1).toBe(200);
127
+ expect(device.pm10).toBe(400);
128
+ expect(device.aqPercent).toBe(5);
129
+ });
130
+ });
131
+ describe('Filter Life Management', () => {
132
+ it('should handle normal filter life values', () => {
133
+ const testValues = [0, 25, 50, 75, 100];
134
+ testValues.forEach(value => {
135
+ device.details = { filter_life: value };
136
+ expect(device.filterLife).toBe(value);
137
+ });
138
+ });
139
+ it('should handle low filter life warning threshold', () => {
140
+ device.details = { filter_life: 5 };
141
+ expect(device.filterLife).toBe(5);
142
+ });
143
+ it('should handle filter replacement needed (0%)', () => {
144
+ device.details = { filter_life: 0 };
145
+ expect(device.filterLife).toBe(0);
146
+ });
147
+ it('should handle new filter (100%)', () => {
148
+ device.details = { filter_life: 100 };
149
+ expect(device.filterLife).toBe(100);
150
+ });
151
+ });
152
+ describe('Device Configuration', () => {
153
+ it('should support air quality features for LAP-V102S', () => {
154
+ expect(device.hasFeature('air_quality')).toBe(true);
155
+ expect(device.hasFeature('display')).toBe(true);
156
+ expect(device.hasFeature('child_lock')).toBe(true);
157
+ expect(device.hasFeature('night_light')).toBe(true);
158
+ expect(device.hasFeature('timer')).toBe(true);
159
+ expect(device.hasFeature('fan_speed')).toBe(true);
160
+ expect(device.hasFeature('auto_mode')).toBe(true);
161
+ });
162
+ it('should return correct maximum speed', () => {
163
+ expect(device.getMaxFanSpeed()).toBe(4); // LAP-V102S has 4 speeds
164
+ });
165
+ it('should support air quality in all modes', () => {
166
+ const modes = ['auto', 'manual', 'sleep', 'turbo'];
167
+ modes.forEach(mode => {
168
+ device.details.mode = mode;
169
+ expect(device.isFeatureSupportedInCurrentMode('air_quality')).toBe(true);
170
+ });
171
+ });
172
+ });
173
+ describe('Real-time Data Updates', () => {
174
+ it('should handle real-time air quality updates', () => {
175
+ // Initial state
176
+ device.details = {
177
+ air_quality: 'Good',
178
+ air_quality_value: 25,
179
+ pm1: 15,
180
+ pm10: 35
181
+ };
182
+ expect(device.airQualityValue).toBe(25);
183
+ // Simulate air quality change
184
+ device.details.air_quality = 'Fair';
185
+ device.details.air_quality_value = 40;
186
+ device.details.pm1 = 28;
187
+ device.details.pm10 = 55;
188
+ expect(device.airQualityLevel).toBe('Fair');
189
+ expect(device.airQualityValue).toBe(40);
190
+ expect(device.pm1).toBe(28);
191
+ expect(device.pm10).toBe(55);
192
+ });
193
+ it('should handle rapid air quality fluctuations', () => {
194
+ const rapidUpdates = [
195
+ { quality: 'Good', value: 20 },
196
+ { quality: 'Fair', value: 35 },
197
+ { quality: 'Good', value: 22 },
198
+ { quality: 'Poor', value: 75 },
199
+ { quality: 'Fair', value: 38 }
200
+ ];
201
+ rapidUpdates.forEach(update => {
202
+ device.details.air_quality = update.quality;
203
+ device.details.air_quality_value = update.value;
204
+ expect(device.airQualityLevel).toBe(update.quality);
205
+ expect(device.airQualityValue).toBe(update.value);
206
+ });
207
+ });
208
+ });
209
+ describe('Device State Synchronization', () => {
210
+ it('should maintain consistent state across updates', () => {
211
+ device.details = {
212
+ enabled: true,
213
+ mode: 'auto',
214
+ level: 3,
215
+ speed: 3,
216
+ display: 'on',
217
+ child_lock: true,
218
+ air_quality: 'Good',
219
+ air_quality_value: 22,
220
+ filter_life: 65
221
+ };
222
+ expect(device.deviceStatus).toBe('on');
223
+ expect(device.mode).toBe('auto');
224
+ expect(device.speed).toBe(3);
225
+ expect(device.screenStatus).toBe('on');
226
+ expect(device.childLock).toBe(true);
227
+ expect(device.airQualityLevel).toBe('Good');
228
+ expect(device.filterLife).toBe(65);
229
+ });
230
+ it('should handle partial state updates', () => {
231
+ // Initial state
232
+ device.details = {
233
+ mode: 'auto',
234
+ speed: 2,
235
+ air_quality_value: 30,
236
+ filter_life: 70
237
+ };
238
+ // Partial update (only some fields changed)
239
+ device.details.air_quality_value = 35;
240
+ device.details.speed = 3;
241
+ expect(device.mode).toBe('auto'); // Unchanged
242
+ expect(device.speed).toBe(3); // Changed
243
+ expect(device.airQualityValue).toBe(35); // Changed
244
+ expect(device.filterLife).toBe(70); // Unchanged
245
+ });
246
+ });
247
+ describe('Error Conditions', () => {
248
+ it('should handle API errors gracefully', () => {
249
+ device.details = undefined;
250
+ expect(device.airQualityValue).toBe(0);
251
+ expect(device.pm1).toBe(0);
252
+ expect(device.pm10).toBe(0);
253
+ expect(device.aqPercent).toBe(0);
254
+ expect(device.filterLife).toBe(0);
255
+ });
256
+ it('should handle corrupted data fields', () => {
257
+ device.details = {
258
+ air_quality: { invalid: 'object' },
259
+ air_quality_value: 'not_a_number',
260
+ pm1: null,
261
+ pm10: undefined,
262
+ filter_life: []
263
+ };
264
+ expect(device.airQualityLevel).toEqual({ invalid: 'object' });
265
+ expect(device.airQualityValue).toBe(0);
266
+ expect(device.pm1).toBe(0);
267
+ expect(device.pm10).toBe(0);
268
+ expect(device.filterLife).toBe(0);
269
+ });
270
+ it('should handle network timeout scenarios', () => {
271
+ // Simulate stale data from last successful update
272
+ device.details = {
273
+ air_quality: 'Good',
274
+ air_quality_value: 25,
275
+ filter_life: 60
276
+ };
277
+ // Values should remain from last update
278
+ expect(device.airQualityLevel).toBe('Good');
279
+ expect(device.airQualityValue).toBe(25);
280
+ expect(device.filterLife).toBe(60);
281
+ });
282
+ });
283
+ });
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Unit tests for VeSyncAirBypass air quality data parsing
3
+ */
4
+ export {};
@@ -0,0 +1,257 @@
1
+ "use strict";
2
+ /**
3
+ * Unit tests for VeSyncAirBypass air quality data parsing
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const airBypass_1 = require("../../lib/fans/airBypass");
7
+ // Mock VeSync manager
8
+ const mockManager = {
9
+ username: 'test@example.com',
10
+ password: 'testpass',
11
+ token: 'testtoken',
12
+ accountID: 'testaccount',
13
+ apiKey: 'testapikey',
14
+ apiBase: 'testbase',
15
+ timezone: 'UTC'
16
+ };
17
+ describe('VeSyncAirBypass Air Quality Features', () => {
18
+ let device;
19
+ beforeEach(() => {
20
+ const deviceDetails = {
21
+ deviceName: 'Core300S Test',
22
+ deviceType: 'Core300S',
23
+ cid: 'test-cid',
24
+ uuid: 'test-uuid',
25
+ deviceStatus: 'on',
26
+ deviceRegion: 'US',
27
+ configModule: 'VeSyncAirBypass',
28
+ macId: '00:11:22:33:44:55',
29
+ deviceCategory: 'fan',
30
+ connectionStatus: 'online'
31
+ };
32
+ device = new airBypass_1.VeSyncAirBypass(deviceDetails, mockManager);
33
+ });
34
+ describe('Air Quality Data Parsing', () => {
35
+ it('should parse air quality data from device response', () => {
36
+ const mockResponse = {
37
+ result: {
38
+ code: 0,
39
+ result: {
40
+ enabled: true,
41
+ mode: 'auto',
42
+ level: 3,
43
+ speed: 3,
44
+ display: 'on',
45
+ child_lock: false,
46
+ night_light: 'dim',
47
+ air_quality: 2,
48
+ air_quality_value: 15,
49
+ filter_life: 85,
50
+ timer_remain: 0
51
+ }
52
+ }
53
+ };
54
+ // Simulate API response parsing
55
+ device.details = mockResponse.result.result;
56
+ expect(device.airQualityLevel).toBe(2);
57
+ expect(device.airQualityValue).toBe(15);
58
+ expect(device.filterLife).toBe(85);
59
+ });
60
+ it('should handle missing air quality data gracefully', () => {
61
+ const mockResponse = {
62
+ result: {
63
+ code: 0,
64
+ result: {
65
+ enabled: true,
66
+ mode: 'auto',
67
+ level: 3,
68
+ speed: 3,
69
+ display: 'on',
70
+ child_lock: false,
71
+ filter_life: 85
72
+ // air_quality and air_quality_value missing
73
+ }
74
+ }
75
+ };
76
+ device.details = mockResponse.result.result;
77
+ expect(device.airQualityLevel).toBe('');
78
+ expect(device.airQualityValue).toBe(0);
79
+ expect(device.filterLife).toBe(85);
80
+ });
81
+ it('should handle various air quality value ranges', () => {
82
+ const testCases = [
83
+ { value: 0, level: 1, expected: 'Excellent' },
84
+ { value: 12, level: 1, expected: 'Good' },
85
+ { value: 25, level: 2, expected: 'Fair' },
86
+ { value: 55, level: 3, expected: 'Inferior' },
87
+ { value: 150, level: 4, expected: 'Poor' },
88
+ { value: 500, level: 5, expected: 'Poor' }
89
+ ];
90
+ testCases.forEach(testCase => {
91
+ device.details = {
92
+ air_quality: testCase.level,
93
+ air_quality_value: testCase.value,
94
+ filter_life: 50
95
+ };
96
+ expect(device.airQualityValue).toBe(testCase.value);
97
+ expect(device.airQualityLevel).toBe(testCase.level);
98
+ });
99
+ });
100
+ it('should handle extended air quality data with PM1 and PM10', () => {
101
+ device.details = {
102
+ air_quality: 2,
103
+ air_quality_value: 20,
104
+ pm1: 15,
105
+ pm10: 35,
106
+ aq_percent: 75,
107
+ filter_life: 60
108
+ };
109
+ expect(device.airQualityValue).toBe(20);
110
+ expect(device.pm1).toBe(15);
111
+ expect(device.pm10).toBe(35);
112
+ expect(device.aqPercent).toBe(75);
113
+ });
114
+ it('should handle zero PM values correctly', () => {
115
+ device.details = {
116
+ air_quality: 1,
117
+ air_quality_value: 0,
118
+ pm1: 0,
119
+ pm10: 0,
120
+ aq_percent: 100,
121
+ filter_life: 100
122
+ };
123
+ expect(device.airQualityValue).toBe(0);
124
+ expect(device.pm1).toBe(0);
125
+ expect(device.pm10).toBe(0);
126
+ expect(device.aqPercent).toBe(100);
127
+ });
128
+ });
129
+ describe('Filter Life Parsing', () => {
130
+ it('should parse filter life as number', () => {
131
+ device.details = { filter_life: 75 };
132
+ expect(device.filterLife).toBe(75);
133
+ });
134
+ it('should handle zero filter life', () => {
135
+ device.details = { filter_life: 0 };
136
+ expect(device.filterLife).toBe(0);
137
+ });
138
+ it('should handle 100% filter life', () => {
139
+ device.details = { filter_life: 100 };
140
+ expect(device.filterLife).toBe(100);
141
+ });
142
+ it('should handle missing filter life data', () => {
143
+ device.details = { mode: 'auto', speed: 3 };
144
+ expect(device.filterLife).toBe(0);
145
+ });
146
+ it('should handle invalid filter life data types', () => {
147
+ device.details = { filter_life: 'invalid' };
148
+ expect(device.filterLife).toBe(0);
149
+ });
150
+ });
151
+ describe('Feature Support', () => {
152
+ it('should support air quality features for Core300S', () => {
153
+ expect(device.hasFeature('air_quality')).toBe(true);
154
+ expect(device.hasFeature('auto_mode')).toBe(true);
155
+ expect(device.hasFeature('display')).toBe(true);
156
+ expect(device.hasFeature('child_lock')).toBe(true);
157
+ expect(device.hasFeature('night_light')).toBe(true);
158
+ });
159
+ it('should not support air quality for Core200S', () => {
160
+ const core200s = new airBypass_1.VeSyncAirBypass({
161
+ deviceName: 'Core200S Test',
162
+ deviceType: 'Core200S',
163
+ cid: 'test-cid',
164
+ uuid: 'test-uuid'
165
+ }, mockManager);
166
+ expect(core200s.hasFeature('air_quality')).toBe(false);
167
+ expect(core200s.hasFeature('auto_mode')).toBe(false);
168
+ });
169
+ it('should return correct max speed for different models', () => {
170
+ expect(device.getMaxFanSpeed()).toBe(4); // Core300S has 4 speeds
171
+ const core200s = new airBypass_1.VeSyncAirBypass({
172
+ deviceName: 'Core200S Test',
173
+ deviceType: 'Core200S',
174
+ cid: 'test-cid',
175
+ uuid: 'test-uuid'
176
+ }, mockManager);
177
+ expect(core200s.getMaxFanSpeed()).toBe(3); // Core200S has 3 speeds
178
+ });
179
+ });
180
+ describe('Device State Management', () => {
181
+ it('should track device state correctly', () => {
182
+ device.details = {
183
+ enabled: true,
184
+ mode: 'auto',
185
+ level: 3,
186
+ speed: 3,
187
+ display: 'on',
188
+ child_lock: false,
189
+ air_quality: 2,
190
+ air_quality_value: 25,
191
+ filter_life: 65
192
+ };
193
+ expect(device.deviceStatus).toBe('on');
194
+ expect(device.mode).toBe('auto');
195
+ expect(device.speed).toBe(3);
196
+ expect(device.screenStatus).toBe('on');
197
+ expect(device.childLock).toBe(false);
198
+ });
199
+ it('should handle device off state', () => {
200
+ device.deviceStatus = 'off';
201
+ device.details = {
202
+ enabled: false,
203
+ mode: 'manual',
204
+ level: 0,
205
+ speed: 0,
206
+ air_quality_value: 0
207
+ };
208
+ expect(device.deviceStatus).toBe('off');
209
+ expect(device.speed).toBe(0);
210
+ });
211
+ });
212
+ describe('Error Handling', () => {
213
+ it('should handle malformed API responses', () => {
214
+ device.details = null;
215
+ expect(device.airQualityValue).toBe(0);
216
+ expect(device.filterLife).toBe(0);
217
+ expect(device.mode).toBe('');
218
+ expect(device.speed).toBe(0);
219
+ });
220
+ it('should handle partial API responses', () => {
221
+ device.details = {
222
+ mode: 'auto'
223
+ // Other fields missing
224
+ };
225
+ expect(device.airQualityValue).toBe(0);
226
+ expect(device.filterLife).toBe(0);
227
+ expect(device.mode).toBe('auto');
228
+ expect(device.speed).toBe(0);
229
+ });
230
+ it('should handle negative values gracefully', () => {
231
+ device.details = {
232
+ air_quality_value: -10,
233
+ pm1: -5,
234
+ pm10: -15,
235
+ filter_life: -20
236
+ };
237
+ expect(device.airQualityValue).toBe(-10); // Allow negative for error detection
238
+ expect(device.pm1).toBe(-5);
239
+ expect(device.pm10).toBe(-15);
240
+ expect(device.filterLife).toBe(-20);
241
+ });
242
+ it('should handle extremely high values', () => {
243
+ device.details = {
244
+ air_quality_value: 9999,
245
+ pm1: 5000,
246
+ pm10: 8000,
247
+ filter_life: 200,
248
+ aq_percent: 150
249
+ };
250
+ expect(device.airQualityValue).toBe(9999);
251
+ expect(device.pm1).toBe(5000);
252
+ expect(device.pm10).toBe(8000);
253
+ expect(device.filterLife).toBe(200);
254
+ expect(device.aqPercent).toBe(150);
255
+ });
256
+ });
257
+ });
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Unit tests for VeSyncFan base class and air quality features
3
+ */
4
+ export {};