@eohjsc/react-native-smart-city 0.7.41 → 0.7.42

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.
Files changed (29) hide show
  1. package/package.json +1 -1
  2. package/src/commons/Dashboard/MyDashboardDevice/index.js +14 -12
  3. package/src/commons/Dashboard/MyUnit/index.js +4 -3
  4. package/src/commons/DateTimeRangeChange/index.js +5 -5
  5. package/src/commons/Device/HorizontalBarChart.js +11 -24
  6. package/src/commons/Device/PowerConsumptionChart.js +195 -103
  7. package/src/commons/Form/CurrencyInput.js +9 -18
  8. package/src/commons/SubUnit/Favorites/index.js +35 -10
  9. package/src/commons/SubUnit/ShortDetail.js +17 -4
  10. package/src/commons/SubUnit/__test__/Favorites.test.js +90 -0
  11. package/src/commons/SubUnit/__test__/ShortDetail.test.js +45 -2
  12. package/src/hooks/IoT/__test__/useValueEvaluation.test.js +12 -12
  13. package/src/iot/UpdateStates.js +37 -16
  14. package/src/iot/mqtt.js +23 -0
  15. package/src/screens/Device/__test__/DeviceDetail-3rdparty.test.js +16 -5
  16. package/src/screens/Device/__test__/DeviceDetail-arduino.test.js +10 -0
  17. package/src/screens/Device/__test__/DeviceDetail-modbus.test.js +37 -8
  18. package/src/screens/Device/__test__/DeviceDetail-zigbee.test.js +16 -5
  19. package/src/screens/Device/__test__/DeviceDetail.test.js +17 -6
  20. package/src/screens/Device/__test__/sensorDisplayItem.test.js +47 -11
  21. package/src/screens/Device/components/SensorDisplayItem.js +23 -5
  22. package/src/screens/Device/styles.js +4 -0
  23. package/src/screens/UnitSummary/components/3PPowerConsumption/index.js +8 -49
  24. package/src/screens/UnitSummary/components/PowerConsumption/__test__/PowerConsumption.test.js +121 -6
  25. package/src/screens/UnitSummary/components/PowerConsumption/index.js +6 -47
  26. package/src/utils/I18n/translations/en.js +1 -0
  27. package/src/utils/I18n/translations/vi.js +1 -0
  28. package/src/utils/chartHelper/index.js +53 -0
  29. package/src/utils/chartHelper/getMaxValueIndex.js +0 -11
@@ -32,14 +32,17 @@ const ShortDetailSubUnit = ({ unit, station, isOwner }) => {
32
32
 
33
33
  useDevicesStatus(unit, station?.devices);
34
34
 
35
+ const stationChipIdsSet = useMemo(() => {
36
+ return new Set(station?.devices?.map((device) => device.chip_id));
37
+ }, [station?.devices]);
38
+
35
39
  const { chips, isFetching } = useChipJsonConfiguration({
36
40
  dashboardId: unit?.id,
37
41
  });
38
42
 
39
43
  const listChipsMqtt = useMemo(() => {
40
- const stationChipIds = station?.devices?.map((device) => device.chip_id);
41
- return chips?.filter((chip) => stationChipIds?.includes(chip.id));
42
- }, [chips, station?.devices]);
44
+ return chips.filter((chip) => stationChipIdsSet.has(chip.id));
45
+ }, [chips, stationChipIdsSet]);
43
46
 
44
47
  const { mqttConfigs } = useConnectChipMqtt(listChipsMqtt);
45
48
 
@@ -64,7 +67,17 @@ const ShortDetailSubUnit = ({ unit, station, isOwner }) => {
64
67
  }, [station, mqttConfigs]);
65
68
 
66
69
  useWatchConfigs(isFetching ? [] : configsNeedWatching);
67
- useWatchSharedChips({ dashboardId: unit?.id });
70
+
71
+ const listSharedChipIds = useMemo(() => {
72
+ const chipMqttIdsSet = new Set(listChipsMqtt.map((chip) => chip.id));
73
+ return [...stationChipIdsSet].filter((id) => !chipMqttIdsSet.has(id));
74
+ }, [listChipsMqtt, stationChipIdsSet]);
75
+
76
+ useWatchSharedChips({
77
+ dashboardId: unit?.id,
78
+ filterChipIds: listSharedChipIds,
79
+ ready: !!listSharedChipIds.length,
80
+ });
68
81
 
69
82
  const goToPlayBack = useCallback(() => {
70
83
  navigate(Routes.PlaybackCamera, {
@@ -1,12 +1,21 @@
1
1
  import React from 'react';
2
+ import MockAdapter from 'axios-mock-adapter';
2
3
  import { act, create } from 'react-test-renderer';
4
+ import { API } from '../../../configs';
3
5
  import { SCProvider } from '../../../context';
4
6
  import { mockSCStore } from '../../../context/mockStore';
7
+ import { watchMultiDataChips, watchMultiConfigs } from '../../../iot/Monitor';
8
+ import api from '../../../utils/Apis/axios';
9
+ import { gatewayDataFactory } from '../../../utils/FactoryGateway';
5
10
  import ItemAddNew from '../../Device/ItemAddNew';
6
11
  import ItemDevice from '../../Device/ItemDevice';
7
12
  import SubUnitFavorites from '../Favorites';
8
13
  import ItemOneTap from '../OneTap/ItemOneTap';
9
14
 
15
+ const mockAxios = new MockAdapter(api.axiosInstance);
16
+
17
+ jest.mock('../../../iot/Monitor');
18
+
10
19
  const wrapComponent = (props) => (
11
20
  <SCProvider initState={mockSCStore({})}>
12
21
  <SubUnitFavorites {...props} />
@@ -18,6 +27,7 @@ describe('test ShortDetail Subunit', () => {
18
27
  let props;
19
28
 
20
29
  beforeEach(() => {
30
+ jest.useFakeTimers();
21
31
  props = {
22
32
  unit: {
23
33
  address: null,
@@ -78,6 +88,8 @@ describe('test ShortDetail Subunit', () => {
78
88
  ],
79
89
  isGGHomeConnected: true,
80
90
  };
91
+ watchMultiConfigs.mockClear();
92
+ watchMultiDataChips.mockClear();
81
93
  });
82
94
 
83
95
  it('render SubUnitFavorites', async () => {
@@ -96,4 +108,82 @@ describe('test ShortDetail Subunit', () => {
96
108
  await itemAddNew[0].props.onAddNew();
97
109
  });
98
110
  });
111
+
112
+ it('render using mqtt call watch config and data chips', async () => {
113
+ mockAxios
114
+ .onGet(API.CHIP.JSON_CONFIGURATION)
115
+ .reply(200, [gatewayDataFactory]);
116
+ mockAxios
117
+ .onGet(API.CHIP.SHARED_CONFIGURATION)
118
+ .reply(200, [gatewayDataFactory, { ...gatewayDataFactory, id: 7690 }]);
119
+ props.favoriteDevices = [
120
+ {
121
+ action: {
122
+ color: '#00979D',
123
+ icon: 'caretup',
124
+ id: 1,
125
+ key: '',
126
+ },
127
+ action2: null,
128
+ chip_id: 7690,
129
+ description: null,
130
+ icon: '',
131
+ id: 1,
132
+ name: 'People Counting',
133
+ quick_action: { config_id: 128283 },
134
+ remote_control_options: {},
135
+ station: {},
136
+ status: null,
137
+ status2: null,
138
+ is_managed_by_backend: true,
139
+ },
140
+ ];
141
+
142
+ await act(async () => {
143
+ tree = await create(wrapComponent(props));
144
+ });
145
+ await act(async () => {
146
+ jest.runOnlyPendingTimers();
147
+ });
148
+ expect(watchMultiConfigs).toHaveBeenCalledWith([128283]);
149
+ expect(watchMultiDataChips).toHaveBeenCalledWith([7690]);
150
+ });
151
+
152
+ it('render using mqtt not call watch config and data chips', async () => {
153
+ mockAxios
154
+ .onGet(API.CHIP.JSON_CONFIGURATION)
155
+ .reply(200, [gatewayDataFactory]);
156
+ mockAxios.onGet(API.CHIP.SHARED_CONFIGURATION).reply(200, []);
157
+ props.favoriteDevices = [
158
+ {
159
+ action: {
160
+ color: '#00979D',
161
+ icon: 'caretup',
162
+ id: 1,
163
+ key: '',
164
+ },
165
+ action2: null,
166
+ chip_id: 7689,
167
+ description: null,
168
+ icon: '',
169
+ id: 1,
170
+ name: 'People Counting',
171
+ quick_action: { config_id: 128282 },
172
+ remote_control_options: {},
173
+ station: {},
174
+ status: null,
175
+ status2: null,
176
+ is_managed_by_backend: true,
177
+ },
178
+ ];
179
+
180
+ await act(async () => {
181
+ tree = await create(wrapComponent(props));
182
+ });
183
+ await act(async () => {
184
+ jest.runOnlyPendingTimers();
185
+ });
186
+ expect(watchMultiConfigs).not.toHaveBeenCalled();
187
+ expect(watchMultiDataChips).not.toHaveBeenCalled();
188
+ });
99
189
  });
@@ -7,7 +7,7 @@ import { API } from '../../../configs';
7
7
  import { AccessibilityLabel } from '../../../configs/Constants';
8
8
  import { SCProvider } from '../../../context';
9
9
  import { mockSCStore } from '../../../context/mockStore';
10
- import { watchMultiConfigs } from '../../../iot/Monitor';
10
+ import { watchMultiDataChips, watchMultiConfigs } from '../../../iot/Monitor';
11
11
  import { keyPermission } from '../../../utils/Permission/common';
12
12
  import api from '../../../utils/Apis/axios';
13
13
  import Routes from '../../../utils/Route';
@@ -78,6 +78,7 @@ describe('test ShortDetail Subunit', () => {
78
78
  isGGHomeConnected: true,
79
79
  };
80
80
  watchMultiConfigs.mockClear();
81
+ watchMultiDataChips.mockClear();
81
82
  });
82
83
 
83
84
  it('render ShortDetail', async () => {
@@ -191,10 +192,51 @@ describe('test ShortDetail Subunit', () => {
191
192
  expect(watchMultiConfigs).toHaveBeenCalledWith([1]);
192
193
  });
193
194
 
194
- it('render using mqtt not call watch config', async () => {
195
+ it('render using mqtt call watch config and data chips', async () => {
195
196
  mockAxios
196
197
  .onGet(API.CHIP.JSON_CONFIGURATION)
197
198
  .reply(200, [gatewayDataFactory]);
199
+ mockAxios
200
+ .onGet(API.CHIP.SHARED_CONFIGURATION)
201
+ .reply(200, [gatewayDataFactory, { ...gatewayDataFactory, id: 7690 }]);
202
+ props.station.devices = [
203
+ {
204
+ action: {
205
+ color: '#00979D',
206
+ icon: 'caretup',
207
+ id: 1,
208
+ key: '',
209
+ },
210
+ action2: null,
211
+ chip_id: 7690,
212
+ description: null,
213
+ icon: '',
214
+ id: 1,
215
+ name: 'People Counting',
216
+ quick_action: { config_id: 128283 },
217
+ remote_control_options: {},
218
+ station: {},
219
+ status: null,
220
+ status2: null,
221
+ is_managed_by_backend: true,
222
+ },
223
+ ];
224
+
225
+ await act(async () => {
226
+ tree = await create(wrapComponent(props));
227
+ });
228
+ await act(async () => {
229
+ jest.runOnlyPendingTimers();
230
+ });
231
+ expect(watchMultiConfigs).toHaveBeenCalledWith([128283]);
232
+ expect(watchMultiDataChips).toHaveBeenCalledWith([7690]);
233
+ });
234
+
235
+ it('render using mqtt not call watch config and data chips', async () => {
236
+ mockAxios
237
+ .onGet(API.CHIP.JSON_CONFIGURATION)
238
+ .reply(200, [gatewayDataFactory]);
239
+ mockAxios.onGet(API.CHIP.SHARED_CONFIGURATION).reply(200, []);
198
240
  props.station.devices = [
199
241
  {
200
242
  action: {
@@ -225,6 +267,7 @@ describe('test ShortDetail Subunit', () => {
225
267
  jest.runOnlyPendingTimers();
226
268
  });
227
269
  expect(watchMultiConfigs).not.toHaveBeenCalled();
270
+ expect(watchMultiDataChips).not.toHaveBeenCalled();
228
271
  });
229
272
 
230
273
  ['ConfigAndEvaluation', 'ConfigValue', 'EvaluationOverConfig'].forEach(
@@ -1,11 +1,11 @@
1
- import React from 'react';
2
- import { renderHook } from '@testing-library/react-hooks';
1
+ import { act, renderHook } from '@testing-library/react-hooks';
3
2
  import MockAdapter from 'axios-mock-adapter';
3
+ import React from 'react';
4
+ import { API } from '../../../configs';
4
5
  import { SCProvider } from '../../../context';
5
6
  import { mockSCStore } from '../../../context/mockStore';
6
- import { useValueEvaluations } from '../index';
7
7
  import api from '../../../utils/Apis/axios';
8
- import { API } from '../../../configs';
8
+ import { useValueEvaluations } from '../index';
9
9
 
10
10
  const mock = new MockAdapter(api.axiosInstance);
11
11
 
@@ -35,13 +35,11 @@ describe('Test useValueEvaluation', () => {
35
35
  it('test unitId not null request success', async () => {
36
36
  mock.onGet(API.VALUE_EVALUATIONS()).replyOnce(200, {
37
37
  results: [],
38
- next: 'link',
39
38
  });
40
- mock.onGet(API.VALUE_EVALUATIONS()).replyOnce(200, {
41
- results: [],
42
- });
43
- renderHook(() => useValueEvaluations(1), {
44
- wrapper,
39
+ await act(async () => {
40
+ renderHook(() => useValueEvaluations(1), {
41
+ wrapper,
42
+ });
45
43
  });
46
44
  expect(mock.history.get.length).toBe(1);
47
45
  });
@@ -50,8 +48,10 @@ describe('Test useValueEvaluation', () => {
50
48
  mock.onGet(API.VALUE_EVALUATIONS()).replyOnce(400, {
51
49
  results: [],
52
50
  });
53
- renderHook(() => useValueEvaluations(1), {
54
- wrapper,
51
+ await act(async () => {
52
+ renderHook(() => useValueEvaluations(1), {
53
+ wrapper,
54
+ });
55
55
  });
56
56
  expect(mock.history.get.length).toBe(1);
57
57
  });
@@ -1,6 +1,6 @@
1
1
  import moment from 'moment';
2
2
 
3
- import { getConfigGlobalState, setConfigGlobalState } from './states';
3
+ import { setConfigGlobalState } from './states';
4
4
 
5
5
  const isNewer = (valueTime, valueMicro, currentTime, currentMicro) => {
6
6
  if (valueTime?.isAfter(currentTime)) {
@@ -40,21 +40,42 @@ export const updateGlobalValues = (data) => {
40
40
  });
41
41
  };
42
42
 
43
+ let pending = {};
44
+ let scheduled = false;
45
+
43
46
  export const updateGlobalValue = (configId, value) => {
44
- const configValues = getConfigGlobalState('configValues');
45
- const currentValue = configValues[configId];
46
- if (
47
- !isNewer(
48
- value.last_updated,
49
- value.last_updated_micro,
50
- currentValue?.last_updated || moment(0),
51
- currentValue?.last_updated_micro || 0
52
- )
53
- ) {
54
- return;
47
+ pending[configId] = value;
48
+
49
+ if (!scheduled) {
50
+ scheduled = true;
51
+
52
+ requestAnimationFrame(() => {
53
+ setConfigGlobalState('configValues', (prev) => {
54
+ let changed = false;
55
+ const next = { ...prev };
56
+
57
+ Object.keys(pending).forEach((id) => {
58
+ const val = pending[id];
59
+ const cur = prev[id];
60
+
61
+ if (
62
+ isNewer(
63
+ val.last_updated,
64
+ val.last_updated_micro,
65
+ cur?.last_updated || moment(0),
66
+ cur?.last_updated_micro || 0
67
+ )
68
+ ) {
69
+ next[id] = val;
70
+ changed = true;
71
+ }
72
+ });
73
+
74
+ pending = {};
75
+ scheduled = false;
76
+
77
+ return changed ? next : prev;
78
+ });
79
+ });
55
80
  }
56
- setConfigGlobalState('configValues', {
57
- ...configValues,
58
- [configId]: value,
59
- });
60
81
  };
package/src/iot/mqtt.js CHANGED
@@ -193,6 +193,19 @@ const convert_ai = (bytes_str, config_data = null) => {
193
193
  );
194
194
  };
195
195
 
196
+ const power_factor_4q_fp_pf = (value) => {
197
+ let pfVal;
198
+ if (value > 1) {
199
+ pfVal = 2 - value;
200
+ } else if (value < -1) {
201
+ pfVal = -2 - value;
202
+ } else {
203
+ pfVal = value;
204
+ }
205
+
206
+ return pfVal;
207
+ };
208
+
196
209
  const mappingTransformer = {
197
210
  int_all: int_all,
198
211
  float_abcd: float_abcd,
@@ -224,6 +237,10 @@ const mappingTransformer = {
224
237
  int_64_cdab: int_64_cdab,
225
238
  };
226
239
 
240
+ const mappingValueConverter = {
241
+ power_factor_4q_fp_pf: power_factor_4q_fp_pf,
242
+ };
243
+
227
244
  const extract_config_value = (register, value_bytes) => {
228
245
  const transformer = mappingTransformer[register?.transformer];
229
246
  if (!transformer) {
@@ -303,6 +320,11 @@ const get_offset_sample_value = async (value, config) => {
303
320
  return value;
304
321
  };
305
322
 
323
+ const getValueConverter = (value, config) => {
324
+ const converter = mappingValueConverter[config?.value_converter];
325
+ return converter ? converter(value) : value;
326
+ };
327
+
306
328
  const check_filter = (value, config) => {
307
329
  if (!config?.active_filter) {
308
330
  return false;
@@ -333,6 +355,7 @@ const updateGlobalValueMqtt = async (config, value, time) => {
333
355
 
334
356
  value = get_scale_value(value, config);
335
357
  value = await get_offset_sample_value(value, config);
358
+ value = getValueConverter(value, config);
336
359
 
337
360
  if (check_filter(value, config)) {
338
361
  return;
@@ -120,6 +120,12 @@ describe('test DeviceDetail', () => {
120
120
  mock.onGet(API.CHIP.SHARED_CONFIGURATION).reply(200, []);
121
121
  });
122
122
 
123
+ afterEach(() => {
124
+ act(() => {
125
+ jest.runOnlyPendingTimers();
126
+ });
127
+ });
128
+
123
129
  const _receiveDataOnDeviceDetail = async (widgetConfigs, topic, message) => {
124
130
  mock.onGet(API.CHIP.JSON_CONFIGURATION).reply(200, [gatewayData]);
125
131
 
@@ -168,6 +174,10 @@ describe('test DeviceDetail', () => {
168
174
  await client.trigger('message', topic, JSON.stringify(message), 'packet');
169
175
  });
170
176
 
177
+ await act(async () => {
178
+ jest.runOnlyPendingTimers();
179
+ });
180
+
171
181
  const valueBox = instance.findAllByType(QualityIndicatorItem);
172
182
  return valueBox;
173
183
  };
@@ -370,11 +380,6 @@ describe('test DeviceDetail', () => {
370
380
  );
371
381
  });
372
382
 
373
- const instance = tree.root;
374
- const valueBoxs = instance.findAllByType(QualityIndicatorItem);
375
- expect(valueBoxs[0].props.value).toEqual(expect1);
376
- expect(valueBoxs[1].props.value).toEqual(expect2);
377
-
378
383
  expect(
379
384
  mock.history.post.filter(
380
385
  (req) => req.url === API.IOT.CHIP_MANAGER.WATCH_DATA_CHIPS()
@@ -384,6 +389,7 @@ describe('test DeviceDetail', () => {
384
389
  await act(async () => {
385
390
  jest.runOnlyPendingTimers();
386
391
  });
392
+
387
393
  expect(
388
394
  mock.history.post.filter(
389
395
  (req) => req.url === API.IOT.CHIP_MANAGER.WATCH_DATA_CHIPS()
@@ -391,6 +397,11 @@ describe('test DeviceDetail', () => {
391
397
  ).toHaveLength(2);
392
398
  expect(unwatchMultiDataChips).not.toHaveBeenCalled();
393
399
 
400
+ const instance = tree.root;
401
+ const valueBoxs = instance.findAllByType(QualityIndicatorItem);
402
+ expect(valueBoxs[0].props.value).toEqual(expect1);
403
+ expect(valueBoxs[1].props.value).toEqual(expect2);
404
+
394
405
  await act(async () => {
395
406
  await tree.unmount();
396
407
  });
@@ -120,6 +120,12 @@ describe('test DeviceDetail', () => {
120
120
  mock.onGet(API.CHIP.SHARED_CONFIGURATION).reply(200, []);
121
121
  });
122
122
 
123
+ afterEach(() => {
124
+ act(() => {
125
+ jest.runOnlyPendingTimers();
126
+ });
127
+ });
128
+
123
129
  const _receiveDataOnDeviceDetail = async (widgetConfigs, topic, message) => {
124
130
  mock.onGet(API.CHIP.JSON_CONFIGURATION).reply(200, [gatewayData]);
125
131
 
@@ -168,6 +174,10 @@ describe('test DeviceDetail', () => {
168
174
  await client.trigger('message', topic, JSON.stringify(message), 'packet');
169
175
  });
170
176
 
177
+ await act(async () => {
178
+ jest.runOnlyPendingTimers();
179
+ });
180
+
171
181
  const valueBox = instance.findAllByType(QualityIndicatorItem);
172
182
  return valueBox;
173
183
  };
@@ -1,9 +1,8 @@
1
- import { NavigationContext } from '@react-navigation/native';
2
1
  import AsyncStorage from '@react-native-async-storage/async-storage';
2
+ import { NavigationContext } from '@react-navigation/native';
3
3
  import MockAdapter from 'axios-mock-adapter';
4
4
  import moment from 'moment';
5
5
  import mqtt from 'precompiled-mqtt/dist/mqtt.browser';
6
- import React from 'react';
7
6
  import { Alert } from 'react-native';
8
7
  import { act, create } from 'react-test-renderer';
9
8
 
@@ -120,6 +119,12 @@ describe('test DeviceDetail', () => {
120
119
  mock.onGet(API.CHIP.SHARED_CONFIGURATION).reply(200, []);
121
120
  });
122
121
 
122
+ afterEach(() => {
123
+ act(() => {
124
+ jest.runOnlyPendingTimers();
125
+ });
126
+ });
127
+
123
128
  const _receiveDataOnDeviceDetail = async (widgetConfigs, topic, message) => {
124
129
  mock.onGet(API.CHIP.JSON_CONFIGURATION).reply(200, [gatewayData]);
125
130
 
@@ -168,6 +173,10 @@ describe('test DeviceDetail', () => {
168
173
  await client.trigger('message', topic, JSON.stringify(message), 'packet');
169
174
  });
170
175
 
176
+ await act(async () => {
177
+ jest.runOnlyPendingTimers();
178
+ });
179
+
171
180
  const valueBox = instance.findAllByType(QualityIndicatorItem);
172
181
  return valueBox;
173
182
  };
@@ -500,6 +509,25 @@ describe('test DeviceDetail', () => {
500
509
  await testModbus('00012', 0.1, '--');
501
510
  });
502
511
 
512
+ it('should render device detail, modbus call updateGlobalValue, power_factor_4q_fp_pf > 1', async () => {
513
+ gatewayData.sensors[1].configs[1].scale = 0.1;
514
+ gatewayData.sensors[1].configs[1].decimal_behind = 1;
515
+ gatewayData.sensors[1].configs[1].value_converter = 'power_factor_4q_fp_pf';
516
+ await testModbus('0001000F', 0.1, 0.5);
517
+ });
518
+ it('should render device detail, modbus call updateGlobalValue, power_factor_4q_fp_pf < -1', async () => {
519
+ gatewayData.sensors[1].configs[1].scale = 0.1;
520
+ gatewayData.sensors[1].configs[1].decimal_behind = 1;
521
+ gatewayData.sensors[1].configs[1].value_converter = 'power_factor_4q_fp_pf';
522
+ await testModbus('0001FFF1', 0.1, -0.5);
523
+ });
524
+ it('should render device detail, modbus call updateGlobalValue, power_factor_4q_fp_pf in range [-1, 1]', async () => {
525
+ gatewayData.sensors[1].configs[1].scale = 0.1;
526
+ gatewayData.sensors[1].configs[1].decimal_behind = 1;
527
+ gatewayData.sensors[1].configs[1].value_converter = 'power_factor_4q_fp_pf';
528
+ await testModbus('00010005', 0.1, 0.5);
529
+ });
530
+
503
531
  const dataConverterWrongData64 = async (transformer) => {
504
532
  gatewayData.mqtt_server.is_wss = false;
505
533
  gatewayData.modbus_gateway.sensors[0].configs[1].transformer = transformer;
@@ -688,11 +716,6 @@ describe('test DeviceDetail', () => {
688
716
  );
689
717
  });
690
718
 
691
- const instance = tree.root;
692
- const valueBoxs = instance.findAllByType(QualityIndicatorItem);
693
- expect(valueBoxs[0].props.value).toEqual(expect1);
694
- expect(valueBoxs[1].props.value).toEqual(expect2);
695
-
696
719
  expect(
697
720
  mock.history.post.filter(
698
721
  (req) => req.url === API.IOT.CHIP_MANAGER.WATCH_DATA_CHIPS()
@@ -702,6 +725,7 @@ describe('test DeviceDetail', () => {
702
725
  await act(async () => {
703
726
  jest.runOnlyPendingTimers();
704
727
  });
728
+
705
729
  expect(
706
730
  mock.history.post.filter(
707
731
  (req) => req.url === API.IOT.CHIP_MANAGER.WATCH_DATA_CHIPS()
@@ -709,6 +733,11 @@ describe('test DeviceDetail', () => {
709
733
  ).toHaveLength(2);
710
734
  expect(unwatchMultiDataChips).not.toHaveBeenCalled();
711
735
 
736
+ const instance = tree.root;
737
+ const valueBoxs = instance.findAllByType(QualityIndicatorItem);
738
+ expect(valueBoxs[0].props.value).toEqual(expect1);
739
+ expect(valueBoxs[1].props.value).toEqual(expect2);
740
+
712
741
  await act(async () => {
713
742
  await tree.unmount();
714
743
  });
@@ -783,5 +812,5 @@ describe('test DeviceDetail', () => {
783
812
  0.2,
784
813
  '2025-09-09T12:00:00.123456Z'
785
814
  );
786
- });
815
+ }, 10000);
787
816
  });
@@ -120,6 +120,12 @@ describe('test DeviceDetail', () => {
120
120
  mock.onGet(API.CHIP.SHARED_CONFIGURATION).reply(200, []);
121
121
  });
122
122
 
123
+ afterEach(() => {
124
+ act(() => {
125
+ jest.runOnlyPendingTimers();
126
+ });
127
+ });
128
+
123
129
  const _receiveDataOnDeviceDetail = async (widgetConfigs, topic, message) => {
124
130
  mock.onGet(API.CHIP.JSON_CONFIGURATION).reply(200, [gatewayData]);
125
131
 
@@ -168,6 +174,10 @@ describe('test DeviceDetail', () => {
168
174
  await client.trigger('message', topic, JSON.stringify(message), 'packet');
169
175
  });
170
176
 
177
+ await act(async () => {
178
+ jest.runOnlyPendingTimers();
179
+ });
180
+
171
181
  const valueBox = instance.findAllByType(QualityIndicatorItem);
172
182
  return valueBox;
173
183
  };
@@ -374,11 +384,6 @@ describe('test DeviceDetail', () => {
374
384
  );
375
385
  });
376
386
 
377
- const instance = tree.root;
378
- const valueBoxs = instance.findAllByType(QualityIndicatorItem);
379
- expect(valueBoxs[0].props.value).toEqual(expect1);
380
- expect(valueBoxs[1].props.value).toEqual(expect2);
381
-
382
387
  expect(
383
388
  mock.history.post.filter(
384
389
  (req) => req.url === API.IOT.CHIP_MANAGER.WATCH_DATA_CHIPS()
@@ -388,6 +393,7 @@ describe('test DeviceDetail', () => {
388
393
  await act(async () => {
389
394
  jest.runOnlyPendingTimers();
390
395
  });
396
+
391
397
  expect(
392
398
  mock.history.post.filter(
393
399
  (req) => req.url === API.IOT.CHIP_MANAGER.WATCH_DATA_CHIPS()
@@ -395,6 +401,11 @@ describe('test DeviceDetail', () => {
395
401
  ).toHaveLength(2);
396
402
  expect(unwatchMultiDataChips).not.toHaveBeenCalled();
397
403
 
404
+ const instance = tree.root;
405
+ const valueBoxs = instance.findAllByType(QualityIndicatorItem);
406
+ expect(valueBoxs[0].props.value).toEqual(expect1);
407
+ expect(valueBoxs[1].props.value).toEqual(expect2);
408
+
398
409
  await act(async () => {
399
410
  await tree.unmount();
400
411
  });
@@ -117,6 +117,12 @@ describe('test DeviceDetail', () => {
117
117
  mock.onGet(API.CHIP.SHARED_CONFIGURATION).reply(200, []);
118
118
  });
119
119
 
120
+ afterEach(() => {
121
+ act(() => {
122
+ jest.runOnlyPendingTimers();
123
+ });
124
+ });
125
+
120
126
  it('should render device detail, connect will call subscribe', async () => {
121
127
  mock.onGet(API.CHIP.JSON_CONFIGURATION).reply(200, [gatewayData]);
122
128
  const client = mqtt.connect();
@@ -328,6 +334,10 @@ describe('test DeviceDetail', () => {
328
334
  await client.trigger('message', topic, JSON.stringify(message), 'packet');
329
335
  });
330
336
 
337
+ await act(async () => {
338
+ jest.runOnlyPendingTimers();
339
+ });
340
+
331
341
  const valueBox = instance.findAllByType(QualityIndicatorItem);
332
342
  expect(valueBox.length).toBe(widgetConfigs.length);
333
343
  return valueBox;
@@ -442,12 +452,6 @@ describe('test DeviceDetail', () => {
442
452
  );
443
453
  });
444
454
 
445
- const instance = tree.root;
446
- const valueBoxs = instance.findAllByType(QualityIndicatorItem);
447
- for (let i = 0; i < widgetConfigs.length; i++) {
448
- expect(valueBoxs[i].props.value).toEqual(expects[i]);
449
- }
450
-
451
455
  expect(
452
456
  mock.history.post.filter(
453
457
  (req) => req.url === API.IOT.CHIP_MANAGER.WATCH_DATA_CHIPS()
@@ -457,6 +461,7 @@ describe('test DeviceDetail', () => {
457
461
  await act(async () => {
458
462
  jest.runOnlyPendingTimers();
459
463
  });
464
+
460
465
  expect(
461
466
  mock.history.post.filter(
462
467
  (req) => req.url === API.IOT.CHIP_MANAGER.WATCH_DATA_CHIPS()
@@ -464,6 +469,12 @@ describe('test DeviceDetail', () => {
464
469
  ).toHaveLength(2);
465
470
  expect(unwatchMultiDataChips).not.toHaveBeenCalled();
466
471
 
472
+ const instance = tree.root;
473
+ const valueBoxs = instance.findAllByType(QualityIndicatorItem);
474
+ for (let i = 0; i < widgetConfigs.length; i++) {
475
+ expect(valueBoxs[i].props.value).toEqual(expects[i]);
476
+ }
477
+
467
478
  await act(async () => {
468
479
  await tree.unmount();
469
480
  });