@eohjsc/react-native-smart-city 0.7.27 → 0.7.30
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/index.js +2 -0
- package/package.json +2 -1
- package/src/commons/Dashboard/MyDashboardDevice/__test__/index.test.js +68 -0
- package/src/commons/Dashboard/MyDashboardDevice/index.js +46 -11
- package/src/commons/Dashboard/MyUnit/__test__/MyUnit.test.js +43 -11
- package/src/commons/Dashboard/MyUnit/index.js +40 -32
- package/src/commons/ModalAlert/index.js +51 -0
- package/src/commons/ModalAlert/styles.js +54 -0
- package/src/commons/SubUnit/ShortDetail.js +20 -4
- package/src/commons/SubUnit/__test__/ShortDetail.test.js +46 -1
- package/src/configs/API.js +6 -0
- package/src/configs/AccessibilityLabel.js +1 -0
- package/src/configs/Constants.js +7 -0
- package/src/configs/SCConfig.js +6 -0
- package/src/context/SCContext.tsx +12 -1
- package/src/context/SCStore.ts +14 -0
- package/src/context/actionType.ts +10 -0
- package/src/context/mockStore.ts +30 -1
- package/src/context/reducer.ts +35 -0
- package/src/hooks/IoT/useRemoteControl.js +4 -1
- package/src/hooks/IoT/useWatchSharedChips.js +130 -0
- package/src/hooks/Review/__test__/useInAppReview.test.js +99 -0
- package/src/hooks/Review/useInAppReview.js +70 -0
- package/src/hooks/useMqtt.js +78 -27
- package/src/iot/Monitor.js +149 -26
- package/src/iot/UpdateStates.js +60 -0
- package/src/iot/mqtt.js +177 -22
- package/src/navigations/UnitStack.js +16 -0
- package/src/screens/ActivityLog/ItemLog.js +1 -0
- package/src/screens/AddNewGateway/RenameNewDevices.js +5 -0
- package/src/screens/AddNewGateway/__test__/RenameNewDevices.test.js +18 -0
- package/src/screens/Automate/AddNewAction/ReceiverSelect.js +208 -0
- package/src/screens/Automate/AddNewAction/SetupScriptEmail.js +1 -1
- package/src/screens/Automate/AddNewAction/SetupScriptNotify.js +18 -28
- package/src/screens/Automate/AddNewAction/SetupScriptReceiverEmail.js +22 -129
- package/src/screens/Automate/AddNewAction/SetupScriptReceiverNotify.js +59 -0
- package/src/screens/Automate/AddNewAction/SetupScriptReceiverSms.js +22 -129
- package/src/screens/Automate/AddNewAction/SetupScriptSms.js +1 -1
- package/src/screens/Automate/AddNewAction/Styles/{SetupScriptReceiverEmailStyles.js → ReceiverSelectStyles.js} +18 -1
- package/src/screens/Automate/AddNewAction/__test__/SetupScriptNotify.test.js +16 -33
- package/src/screens/Automate/AddNewAction/__test__/SetupScriptReceiverEmail.test.js +10 -8
- package/src/screens/Automate/AddNewAction/__test__/SetupScriptReceiverNotify.test.js +217 -0
- package/src/screens/Automate/AddNewAction/__test__/SetupScriptReceiverSms.test.js +10 -8
- package/src/screens/Automate/Components/InputName.js +5 -1
- package/src/screens/Automate/OneTap/__test__/AddNewOneTap.test.js +18 -0
- package/src/screens/Automate/ScriptDetail/index.js +6 -6
- package/src/screens/CreatePassword/__test__/index.test.js +133 -0
- package/src/screens/CreatePassword/index.js +134 -0
- package/src/screens/CreatePassword/styles.js +45 -0
- package/src/screens/Device/__test__/DeviceDetail-3rdparty.test.js +447 -0
- package/src/screens/Device/__test__/DeviceDetail-arduino.test.js +344 -0
- package/src/screens/Device/__test__/{mqttDetail.test.js → DeviceDetail-modbus.test.js} +287 -320
- package/src/screens/Device/__test__/DeviceDetail-zigbee.test.js +451 -0
- package/src/screens/Device/__test__/DeviceDetail.test.js +502 -0
- package/src/screens/Device/__test__/detail.test.js +61 -3
- package/src/screens/Device/__test__/sensorDisplayItem.test.js +28 -3
- package/src/screens/Device/detail.js +14 -6
- package/src/screens/Device/hooks/useDeviceWatchConfigControl.js +3 -2
- package/src/screens/EnterPassword/__test__/EnterPassword.test.js +76 -1
- package/src/screens/EnterPassword/index.js +34 -4
- package/src/screens/EnterPassword/styles.js +1 -1
- package/src/utils/FactoryGateway.js +597 -0
- package/src/utils/I18n/translations/en.js +10 -0
- package/src/utils/I18n/translations/vi.js +10 -0
- package/src/utils/Route/index.js +3 -1
- package/src/utils/Validation.js +5 -0
- package/src/utils/store.js +5 -0
|
@@ -0,0 +1,502 @@
|
|
|
1
|
+
import { NavigationContext } from '@react-navigation/native';
|
|
2
|
+
import AsyncStorage from '@react-native-async-storage/async-storage';
|
|
3
|
+
import MockAdapter from 'axios-mock-adapter';
|
|
4
|
+
import moment from 'moment';
|
|
5
|
+
import mqtt from 'precompiled-mqtt/dist/mqtt.browser';
|
|
6
|
+
import React from 'react';
|
|
7
|
+
import { Alert } from 'react-native';
|
|
8
|
+
import { act, create } from 'react-test-renderer';
|
|
9
|
+
|
|
10
|
+
import QualityIndicatorItem from '../../../commons/Device/WaterQualitySensor/QualityIndicatorsItem';
|
|
11
|
+
import { API } from '../../../configs';
|
|
12
|
+
import { SCProvider } from '../../../context';
|
|
13
|
+
import { mockSCStore } from '../../../context/mockStore';
|
|
14
|
+
import { mqttClientsPool } from '../../../hooks/useMqtt';
|
|
15
|
+
import { unwatchMultiDataChips, watchMultiConfigs } from '../../../iot/Monitor';
|
|
16
|
+
import { setConfigGlobalState } from '../../../iot/states';
|
|
17
|
+
import api from '../../../utils/Apis/axios';
|
|
18
|
+
import { gatewayDataFactory } from '../../../utils/FactoryGateway';
|
|
19
|
+
import DeviceDetail from '../detail';
|
|
20
|
+
|
|
21
|
+
const mock = new MockAdapter(api.axiosInstance);
|
|
22
|
+
|
|
23
|
+
jest.mock('../../../iot/Monitor', () => {
|
|
24
|
+
return {
|
|
25
|
+
...jest.requireActual('../../../iot/Monitor'),
|
|
26
|
+
watchMultiConfigs: jest.fn(),
|
|
27
|
+
unwatchMultiDataChips: jest.fn(),
|
|
28
|
+
};
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
let store = mockSCStore({});
|
|
32
|
+
|
|
33
|
+
const mockAxios = (
|
|
34
|
+
responseDisplay,
|
|
35
|
+
responseDisplayValueV2,
|
|
36
|
+
responseRemoteControl = {}
|
|
37
|
+
) => {
|
|
38
|
+
mock.onGet(API.DEVICE.DISPLAY(1)).reply(200, responseDisplay);
|
|
39
|
+
mock
|
|
40
|
+
.onGet(API.DEVICE.REMOTE_CONTROL_OPTIONS(1))
|
|
41
|
+
.reply(200, responseRemoteControl);
|
|
42
|
+
mock
|
|
43
|
+
.onGet(API.DEVICE.DISPLAY_VALUES_V2(1))
|
|
44
|
+
.reply(200, responseDisplayValueV2);
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const navContextValue = {
|
|
48
|
+
isFocused: () => false,
|
|
49
|
+
addListener: jest.fn(() => jest.fn()),
|
|
50
|
+
};
|
|
51
|
+
const wrapComponent = (state, account, route) => (
|
|
52
|
+
<SCProvider initState={state}>
|
|
53
|
+
<NavigationContext.Provider
|
|
54
|
+
value={{
|
|
55
|
+
...navContextValue,
|
|
56
|
+
isFocused: () => true,
|
|
57
|
+
}}
|
|
58
|
+
>
|
|
59
|
+
<DeviceDetail account={account} route={route} />
|
|
60
|
+
</NavigationContext.Provider>
|
|
61
|
+
</SCProvider>
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
const mockAlertShow = jest.fn();
|
|
65
|
+
Alert.alert = mockAlertShow;
|
|
66
|
+
|
|
67
|
+
describe('test DeviceDetail', () => {
|
|
68
|
+
let tree;
|
|
69
|
+
let route;
|
|
70
|
+
let account;
|
|
71
|
+
let gatewayData;
|
|
72
|
+
|
|
73
|
+
beforeEach(() => {
|
|
74
|
+
route = {
|
|
75
|
+
params: {
|
|
76
|
+
unitData: {
|
|
77
|
+
id: 1,
|
|
78
|
+
name: 'Unit name',
|
|
79
|
+
address: '298 Dien Bien Phu',
|
|
80
|
+
remote_control_options: {
|
|
81
|
+
googlehome: [
|
|
82
|
+
{
|
|
83
|
+
config_maps: [],
|
|
84
|
+
auth: {},
|
|
85
|
+
chip_id: 1,
|
|
86
|
+
},
|
|
87
|
+
],
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
station: {
|
|
91
|
+
id: 2,
|
|
92
|
+
name: 'Station name',
|
|
93
|
+
},
|
|
94
|
+
sensorData: {
|
|
95
|
+
id: 1,
|
|
96
|
+
is_managed_by_backend: true,
|
|
97
|
+
station: { id: 2, name: 'Station name' },
|
|
98
|
+
name: 'Sensor name',
|
|
99
|
+
chip_id: 7689,
|
|
100
|
+
},
|
|
101
|
+
title: 'Button',
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
account = {
|
|
105
|
+
token: 'abc',
|
|
106
|
+
};
|
|
107
|
+
jest.useFakeTimers();
|
|
108
|
+
mock.reset();
|
|
109
|
+
watchMultiConfigs.mockClear();
|
|
110
|
+
unwatchMultiDataChips.mockClear();
|
|
111
|
+
AsyncStorage.clear();
|
|
112
|
+
mqttClientsPool.clear();
|
|
113
|
+
act(() => {
|
|
114
|
+
setConfigGlobalState('configValues', {});
|
|
115
|
+
});
|
|
116
|
+
gatewayData = JSON.parse(JSON.stringify(gatewayDataFactory));
|
|
117
|
+
mock.onGet(API.CHIP.SHARED_CONFIGURATION).reply(200, []);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it('should render device detail, connect will call subscribe', async () => {
|
|
121
|
+
mock.onGet(API.CHIP.JSON_CONFIGURATION).reply(200, [gatewayData]);
|
|
122
|
+
const client = mqtt.connect();
|
|
123
|
+
await act(async () => {
|
|
124
|
+
await create(
|
|
125
|
+
wrapComponent(store, account, {
|
|
126
|
+
...route,
|
|
127
|
+
params: { ...route.params },
|
|
128
|
+
})
|
|
129
|
+
);
|
|
130
|
+
});
|
|
131
|
+
await act(async () => {
|
|
132
|
+
client.trigger('connect');
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
expect(client.subscribe).toHaveBeenCalledWith(
|
|
136
|
+
`eoh/chip/${gatewayData.code}/#`
|
|
137
|
+
);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it('should render device detail, mqtt_server will not call mqtt connect', async () => {
|
|
141
|
+
gatewayData.mqtt_server = null;
|
|
142
|
+
mock.onGet(API.CHIP.JSON_CONFIGURATION).reply(200, [gatewayData]);
|
|
143
|
+
const mockMqttConnect = jest.spyOn(mqtt, 'connect');
|
|
144
|
+
await act(async () => {
|
|
145
|
+
await create(
|
|
146
|
+
wrapComponent(store, account, {
|
|
147
|
+
...route,
|
|
148
|
+
params: { ...route.params },
|
|
149
|
+
})
|
|
150
|
+
);
|
|
151
|
+
});
|
|
152
|
+
expect(mockMqttConnect).not.toHaveBeenCalled();
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it('should render device detail, allow_frontend_connect is false will not call mqtt connect', async () => {
|
|
156
|
+
gatewayData.mqtt_server = {
|
|
157
|
+
host: 'example.cloudmqtt.com',
|
|
158
|
+
allow_frontend_connect: false,
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
mock.onGet(API.CHIP.JSON_CONFIGURATION).reply(200, [gatewayData]);
|
|
162
|
+
const mockMqttConnect = jest.spyOn(mqtt, 'connect');
|
|
163
|
+
|
|
164
|
+
await act(async () => {
|
|
165
|
+
await create(
|
|
166
|
+
wrapComponent(store, account, {
|
|
167
|
+
...route,
|
|
168
|
+
params: { ...route.params },
|
|
169
|
+
})
|
|
170
|
+
);
|
|
171
|
+
});
|
|
172
|
+
expect(mockMqttConnect).not.toHaveBeenCalled();
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it('should render device detail, call mqtt connect', async () => {
|
|
176
|
+
mock.onGet(API.CHIP.JSON_CONFIGURATION).reply(200, [gatewayData]);
|
|
177
|
+
const mockMqttConnect = jest.spyOn(mqtt, 'connect');
|
|
178
|
+
await act(async () => {
|
|
179
|
+
await create(
|
|
180
|
+
wrapComponent(store, account, {
|
|
181
|
+
...route,
|
|
182
|
+
params: { ...route.params },
|
|
183
|
+
})
|
|
184
|
+
);
|
|
185
|
+
});
|
|
186
|
+
expect(mockMqttConnect).toHaveBeenCalledTimes(1);
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
it('should render device detail, unmount will call mqtt end', async () => {
|
|
190
|
+
mock.onGet(API.CHIP.JSON_CONFIGURATION).reply(200, [gatewayData]);
|
|
191
|
+
await act(async () => {
|
|
192
|
+
tree = await create(
|
|
193
|
+
wrapComponent(store, account, {
|
|
194
|
+
...route,
|
|
195
|
+
params: { ...route.params, unitId: 1 },
|
|
196
|
+
})
|
|
197
|
+
);
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
const client = mqtt.connect();
|
|
201
|
+
await act(async () => {
|
|
202
|
+
tree.unmount();
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
await act(async () => {
|
|
206
|
+
jest.runOnlyPendingTimers();
|
|
207
|
+
});
|
|
208
|
+
expect(client.end).toHaveBeenCalled();
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
it('test back and render device detail again, unmount call mqtt end', async () => {
|
|
212
|
+
mock.onGet(API.CHIP.JSON_CONFIGURATION).reply(200, [gatewayData]);
|
|
213
|
+
await act(async () => {
|
|
214
|
+
tree = await create(
|
|
215
|
+
wrapComponent(store, account, {
|
|
216
|
+
...route,
|
|
217
|
+
params: { ...route.params, unitId: 1 },
|
|
218
|
+
})
|
|
219
|
+
);
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
const client = mqtt.connect();
|
|
223
|
+
await act(async () => {
|
|
224
|
+
tree.unmount();
|
|
225
|
+
});
|
|
226
|
+
expect(client.end).not.toHaveBeenCalled();
|
|
227
|
+
|
|
228
|
+
await act(async () => {
|
|
229
|
+
tree = await create(
|
|
230
|
+
wrapComponent(store, account, {
|
|
231
|
+
...route,
|
|
232
|
+
params: { ...route.params, unitId: 1 },
|
|
233
|
+
})
|
|
234
|
+
);
|
|
235
|
+
});
|
|
236
|
+
await act(async () => {
|
|
237
|
+
tree.unmount();
|
|
238
|
+
});
|
|
239
|
+
expect(client.end).not.toHaveBeenCalled();
|
|
240
|
+
|
|
241
|
+
await act(async () => {
|
|
242
|
+
jest.runOnlyPendingTimers();
|
|
243
|
+
});
|
|
244
|
+
expect(client.end).toHaveBeenCalled();
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
it('test render multi, unmount call mqtt end', async () => {
|
|
248
|
+
mock.onGet(API.CHIP.JSON_CONFIGURATION).reply(200, [gatewayData]);
|
|
249
|
+
const tree1 = await act(async () => {
|
|
250
|
+
return await create(
|
|
251
|
+
wrapComponent(store, account, {
|
|
252
|
+
...route,
|
|
253
|
+
params: { ...route.params, unitId: 1 },
|
|
254
|
+
})
|
|
255
|
+
);
|
|
256
|
+
});
|
|
257
|
+
const tree2 = await act(async () => {
|
|
258
|
+
return await create(
|
|
259
|
+
wrapComponent(store, account, {
|
|
260
|
+
...route,
|
|
261
|
+
params: { ...route.params, unitId: 1 },
|
|
262
|
+
})
|
|
263
|
+
);
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
const client = mqtt.connect();
|
|
267
|
+
await act(async () => {
|
|
268
|
+
tree1.unmount();
|
|
269
|
+
});
|
|
270
|
+
expect(client.end).not.toHaveBeenCalled();
|
|
271
|
+
|
|
272
|
+
await act(async () => {
|
|
273
|
+
tree2.unmount();
|
|
274
|
+
});
|
|
275
|
+
expect(client.end).not.toHaveBeenCalled();
|
|
276
|
+
|
|
277
|
+
await act(async () => {
|
|
278
|
+
jest.runOnlyPendingTimers();
|
|
279
|
+
});
|
|
280
|
+
expect(client.end).toHaveBeenCalled();
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
const _receiveDataMqtt = async (widgetConfigs, topic, message) => {
|
|
284
|
+
mock.onGet(API.CHIP.JSON_CONFIGURATION).reply(200, [gatewayData]);
|
|
285
|
+
|
|
286
|
+
const responseDisplay = {
|
|
287
|
+
items: [
|
|
288
|
+
{
|
|
289
|
+
id: 1,
|
|
290
|
+
order: 0,
|
|
291
|
+
template: 'value',
|
|
292
|
+
type: 'value',
|
|
293
|
+
configuration: {
|
|
294
|
+
template: 'simple_list',
|
|
295
|
+
configs: widgetConfigs,
|
|
296
|
+
},
|
|
297
|
+
},
|
|
298
|
+
],
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
const responseRemoteControl = {
|
|
302
|
+
bluetooth: {
|
|
303
|
+
address: 'JUvfa06PMDU8Cqlo',
|
|
304
|
+
password: 'MYcNoskxspWTPsnh',
|
|
305
|
+
},
|
|
306
|
+
internet: {},
|
|
307
|
+
};
|
|
308
|
+
|
|
309
|
+
const responseDisplayValueV2 = {
|
|
310
|
+
configs: [],
|
|
311
|
+
is_connected: true,
|
|
312
|
+
last_updated: '2021-01-24T12:00:00.000Z',
|
|
313
|
+
};
|
|
314
|
+
|
|
315
|
+
mockAxios(responseDisplay, responseDisplayValueV2, responseRemoteControl);
|
|
316
|
+
|
|
317
|
+
await act(async () => {
|
|
318
|
+
tree = await create(
|
|
319
|
+
wrapComponent(store, account, {
|
|
320
|
+
...route,
|
|
321
|
+
params: { ...route.params },
|
|
322
|
+
})
|
|
323
|
+
);
|
|
324
|
+
});
|
|
325
|
+
const instance = tree.root;
|
|
326
|
+
const client = mqtt.connect();
|
|
327
|
+
await act(async () => {
|
|
328
|
+
await client.trigger('message', topic, JSON.stringify(message), 'packet');
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
const valueBox = instance.findAllByType(QualityIndicatorItem);
|
|
332
|
+
expect(valueBox.length).toBe(widgetConfigs.length);
|
|
333
|
+
return valueBox;
|
|
334
|
+
};
|
|
335
|
+
|
|
336
|
+
test('should render device detail, receive is_online message', async () => {
|
|
337
|
+
const valueBoxs = await _receiveDataMqtt(
|
|
338
|
+
[{ id: 2547 }],
|
|
339
|
+
`eoh/chip/${gatewayData.code}/is_online`,
|
|
340
|
+
{
|
|
341
|
+
ol: 1,
|
|
342
|
+
}
|
|
343
|
+
);
|
|
344
|
+
expect(valueBoxs[0].props.value).toEqual(1);
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
test('should render device detail, receive self_sensor message', async () => {
|
|
348
|
+
const valueBoxs = await _receiveDataMqtt(
|
|
349
|
+
[
|
|
350
|
+
{ id: 2540 },
|
|
351
|
+
{ id: 2541 },
|
|
352
|
+
{ id: 2542 },
|
|
353
|
+
{ id: 2543 },
|
|
354
|
+
{ id: 2544 },
|
|
355
|
+
{ id: 2545 },
|
|
356
|
+
{ id: 2546 },
|
|
357
|
+
],
|
|
358
|
+
`eoh/chip/${gatewayData.code}/self_sensor`,
|
|
359
|
+
{
|
|
360
|
+
temperature: 27.6,
|
|
361
|
+
volt: 3.3,
|
|
362
|
+
signal: 100,
|
|
363
|
+
modbus_fail: 0,
|
|
364
|
+
modbus_total: 100,
|
|
365
|
+
internal_temperature: 45,
|
|
366
|
+
is_battery: 0,
|
|
367
|
+
}
|
|
368
|
+
);
|
|
369
|
+
expect(valueBoxs[0].props.value).toEqual(27.6);
|
|
370
|
+
expect(valueBoxs[1].props.value).toEqual(3.3);
|
|
371
|
+
expect(valueBoxs[2].props.value).toEqual(100);
|
|
372
|
+
expect(valueBoxs[3].props.value).toEqual(0);
|
|
373
|
+
expect(valueBoxs[4].props.value).toEqual(100);
|
|
374
|
+
expect(valueBoxs[5].props.value).toEqual(45);
|
|
375
|
+
expect(valueBoxs[6].props.value).toEqual(0);
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
const _watchDataChipsOnDeviceDetail = async (expects) => {
|
|
379
|
+
const widgetConfigs = [
|
|
380
|
+
{ id: 2540 },
|
|
381
|
+
{ id: 2541 },
|
|
382
|
+
{ id: 2542 },
|
|
383
|
+
{ id: 2543 },
|
|
384
|
+
{ id: 2544 },
|
|
385
|
+
{ id: 2545 },
|
|
386
|
+
{ id: 2546 },
|
|
387
|
+
];
|
|
388
|
+
mock.onGet(API.CHIP.JSON_CONFIGURATION).reply(200, []);
|
|
389
|
+
mock.onPost(API.IOT.CHIP_MANAGER.WATCH_DATA_CHIPS()).reply(200, {
|
|
390
|
+
7689: {
|
|
391
|
+
last_self_data: {
|
|
392
|
+
temperature: 27.6,
|
|
393
|
+
volt: 3.3,
|
|
394
|
+
signal: 100,
|
|
395
|
+
modbus_fail: 0,
|
|
396
|
+
modbus_total: 100,
|
|
397
|
+
internal_temperature: 45,
|
|
398
|
+
is_battery: 0,
|
|
399
|
+
last_updated: '2025-09-09T12:00:00Z',
|
|
400
|
+
},
|
|
401
|
+
},
|
|
402
|
+
});
|
|
403
|
+
mock.onGet(API.CHIP.SHARED_CONFIGURATION).reply(200, [gatewayData]);
|
|
404
|
+
|
|
405
|
+
const responseDisplay = {
|
|
406
|
+
items: [
|
|
407
|
+
{
|
|
408
|
+
id: 1,
|
|
409
|
+
order: 0,
|
|
410
|
+
template: 'value',
|
|
411
|
+
type: 'value',
|
|
412
|
+
configuration: {
|
|
413
|
+
template: 'simple_list',
|
|
414
|
+
configs: widgetConfigs,
|
|
415
|
+
},
|
|
416
|
+
},
|
|
417
|
+
],
|
|
418
|
+
};
|
|
419
|
+
|
|
420
|
+
const responseRemoteControl = {
|
|
421
|
+
bluetooth: {
|
|
422
|
+
address: 'JUvfa06PMDU8Cqlo',
|
|
423
|
+
password: 'MYcNoskxspWTPsnh',
|
|
424
|
+
},
|
|
425
|
+
internet: {},
|
|
426
|
+
};
|
|
427
|
+
|
|
428
|
+
const responseDisplayValueV2 = {
|
|
429
|
+
configs: [],
|
|
430
|
+
is_connected: true,
|
|
431
|
+
last_updated: '2021-01-24T12:00:00.000Z',
|
|
432
|
+
};
|
|
433
|
+
|
|
434
|
+
mockAxios(responseDisplay, responseDisplayValueV2, responseRemoteControl);
|
|
435
|
+
|
|
436
|
+
await act(async () => {
|
|
437
|
+
tree = await create(
|
|
438
|
+
wrapComponent(store, account, {
|
|
439
|
+
...route,
|
|
440
|
+
params: { ...route.params },
|
|
441
|
+
})
|
|
442
|
+
);
|
|
443
|
+
});
|
|
444
|
+
|
|
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
|
+
expect(
|
|
452
|
+
mock.history.post.filter(
|
|
453
|
+
(req) => req.url === API.IOT.CHIP_MANAGER.WATCH_DATA_CHIPS()
|
|
454
|
+
)
|
|
455
|
+
).toHaveLength(1);
|
|
456
|
+
|
|
457
|
+
await act(async () => {
|
|
458
|
+
jest.runOnlyPendingTimers();
|
|
459
|
+
});
|
|
460
|
+
expect(
|
|
461
|
+
mock.history.post.filter(
|
|
462
|
+
(req) => req.url === API.IOT.CHIP_MANAGER.WATCH_DATA_CHIPS()
|
|
463
|
+
)
|
|
464
|
+
).toHaveLength(2);
|
|
465
|
+
expect(unwatchMultiDataChips).not.toHaveBeenCalled();
|
|
466
|
+
|
|
467
|
+
await act(async () => {
|
|
468
|
+
await tree.unmount();
|
|
469
|
+
});
|
|
470
|
+
expect(unwatchMultiDataChips).toHaveBeenCalledWith([gatewayData.id]);
|
|
471
|
+
};
|
|
472
|
+
|
|
473
|
+
test('should render device detail, watch data chips self sensorr', async () => {
|
|
474
|
+
await _watchDataChipsOnDeviceDetail([27.6, 3.3, 100, 0, 100, 45, 0]);
|
|
475
|
+
});
|
|
476
|
+
|
|
477
|
+
test('should render device detail, watch data chips self sensorr with past last_updated', async () => {
|
|
478
|
+
setConfigGlobalState('configValues', {
|
|
479
|
+
2540: { value: 0, last_updated: moment('2025-09-09T12:00:01Z') },
|
|
480
|
+
2541: { value: 0, last_updated: moment('2025-09-09T12:00:01Z') },
|
|
481
|
+
2542: { value: 0, last_updated: moment('2025-09-09T12:00:01Z') },
|
|
482
|
+
2543: { value: 0, last_updated: moment('2025-09-09T12:00:01Z') },
|
|
483
|
+
2544: { value: 0, last_updated: moment('2025-09-09T12:00:01Z') },
|
|
484
|
+
2545: { value: 0, last_updated: moment('2025-09-09T12:00:01Z') },
|
|
485
|
+
2546: { value: 0, last_updated: moment('2025-09-09T12:00:01Z') },
|
|
486
|
+
});
|
|
487
|
+
await _watchDataChipsOnDeviceDetail([0, 0, 0, 0, 0, 0, 0]);
|
|
488
|
+
});
|
|
489
|
+
|
|
490
|
+
test('should render device detail, watch data chips self sensorr with future last_updated', async () => {
|
|
491
|
+
setConfigGlobalState('configValues', {
|
|
492
|
+
2540: { value: 0, last_updated: moment('2025-09-09T11:59:59Z') },
|
|
493
|
+
2541: { value: 0, last_updated: moment('2025-09-09T11:59:59Z') },
|
|
494
|
+
2542: { value: 0, last_updated: moment('2025-09-09T11:59:59Z') },
|
|
495
|
+
2543: { value: 0, last_updated: moment('2025-09-09T11:59:59Z') },
|
|
496
|
+
2544: { value: 0, last_updated: moment('2025-09-09T11:59:59Z') },
|
|
497
|
+
2545: { value: 0, last_updated: moment('2025-09-09T11:59:59Z') },
|
|
498
|
+
2546: { value: 0, last_updated: moment('2025-09-09T11:59:59Z') },
|
|
499
|
+
});
|
|
500
|
+
await _watchDataChipsOnDeviceDetail([27.6, 3.3, 100, 0, 100, 45, 0]);
|
|
501
|
+
});
|
|
502
|
+
});
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { NavigationContext, useNavigation } from '@react-navigation/native';
|
|
2
2
|
import MockAdapter from 'axios-mock-adapter';
|
|
3
|
+
import mqtt from 'precompiled-mqtt/dist/mqtt.browser';
|
|
3
4
|
import React from 'react';
|
|
4
5
|
import { Alert, ScrollView } from 'react-native';
|
|
5
6
|
import { act, create } from 'react-test-renderer';
|
|
@@ -14,6 +15,8 @@ import { AccessibilityLabel } from '../../../configs/Constants';
|
|
|
14
15
|
import { SCProvider } from '../../../context';
|
|
15
16
|
import { mockSCStore } from '../../../context/mockStore';
|
|
16
17
|
import { useWatchConfigs } from '../../../hooks/IoT';
|
|
18
|
+
import { gatewayDataFactory } from '../../../utils/FactoryGateway';
|
|
19
|
+
import { watchMultiDataChips } from '../../../iot/Monitor';
|
|
17
20
|
import api from '../../../utils/Apis/axios';
|
|
18
21
|
import { getTranslate } from '../../../utils/I18n';
|
|
19
22
|
import Routes from '../../../utils/Route';
|
|
@@ -29,6 +32,13 @@ jest.mock('../../../hooks/IoT', () => {
|
|
|
29
32
|
};
|
|
30
33
|
});
|
|
31
34
|
|
|
35
|
+
jest.mock('../../../iot/Monitor', () => {
|
|
36
|
+
return {
|
|
37
|
+
...jest.requireActual('../../../iot/Monitor'),
|
|
38
|
+
watchMultiDataChips: jest.fn(),
|
|
39
|
+
};
|
|
40
|
+
});
|
|
41
|
+
|
|
32
42
|
jest.mock('../../../hooks/Common', () => {
|
|
33
43
|
return {
|
|
34
44
|
...jest.requireActual('../../../hooks/Common'),
|
|
@@ -198,6 +208,10 @@ describe('test DeviceDetail', () => {
|
|
|
198
208
|
useWatchConfigs.mockReset();
|
|
199
209
|
});
|
|
200
210
|
|
|
211
|
+
afterEach(() => {
|
|
212
|
+
jest.useRealTimers();
|
|
213
|
+
});
|
|
214
|
+
|
|
201
215
|
it('render DeviceDetail render SensorDisplayItem', async () => {
|
|
202
216
|
const responseDisplay = data_sensor_display;
|
|
203
217
|
|
|
@@ -898,7 +912,7 @@ describe('test DeviceDetail', () => {
|
|
|
898
912
|
el.props.accessibilityLabel === AccessibilityLabel.SENSOR_DISPLAY_ITEM
|
|
899
913
|
);
|
|
900
914
|
expect(sensorDisplayItem.length).toEqual(1);
|
|
901
|
-
expect(useWatchConfigs).
|
|
915
|
+
expect(useWatchConfigs).toHaveBeenLastCalledWith([1]);
|
|
902
916
|
});
|
|
903
917
|
|
|
904
918
|
it('watch action config', async () => {
|
|
@@ -926,7 +940,7 @@ describe('test DeviceDetail', () => {
|
|
|
926
940
|
tree = await create(wrapComponent(store, account, route));
|
|
927
941
|
});
|
|
928
942
|
|
|
929
|
-
expect(useWatchConfigs).
|
|
943
|
+
expect(useWatchConfigs).toHaveBeenLastCalledWith([2]);
|
|
930
944
|
});
|
|
931
945
|
|
|
932
946
|
it('watch stages grid action config', async () => {
|
|
@@ -957,6 +971,50 @@ describe('test DeviceDetail', () => {
|
|
|
957
971
|
tree = await create(wrapComponent(store, account, route));
|
|
958
972
|
});
|
|
959
973
|
|
|
960
|
-
expect(useWatchConfigs).
|
|
974
|
+
expect(useWatchConfigs).toHaveBeenLastCalledWith([3]);
|
|
975
|
+
});
|
|
976
|
+
|
|
977
|
+
it('test connect mqtt, watch data chips and config', async () => {
|
|
978
|
+
mock.onGet(API.CHIP.JSON_CONFIGURATION).reply(200, [
|
|
979
|
+
{ ...gatewayDataFactory, id: 1 },
|
|
980
|
+
{ ...gatewayDataFactory, code: 'xxx' },
|
|
981
|
+
]);
|
|
982
|
+
mock.onGet(API.CHIP.SHARED_CONFIGURATION).reply(200, [
|
|
983
|
+
{ ...gatewayDataFactory, id: 1 },
|
|
984
|
+
{ ...gatewayDataFactory, code: 'yyy' },
|
|
985
|
+
]);
|
|
986
|
+
const responseDisplay = {
|
|
987
|
+
items: [
|
|
988
|
+
{
|
|
989
|
+
id: 1,
|
|
990
|
+
order: 0,
|
|
991
|
+
template: 'on_off_button_action_template',
|
|
992
|
+
type: 'on_off_button_action_template',
|
|
993
|
+
configuration: {
|
|
994
|
+
config: 2,
|
|
995
|
+
},
|
|
996
|
+
},
|
|
997
|
+
],
|
|
998
|
+
};
|
|
999
|
+
const responseDisplayValueV2 = {
|
|
1000
|
+
configs: [{ id: 2 }],
|
|
1001
|
+
is_connected: true,
|
|
1002
|
+
last_updated: '2021-01-24T12:00:00.000Z',
|
|
1003
|
+
};
|
|
1004
|
+
mockAxios(responseDisplay, responseDisplayValueV2);
|
|
1005
|
+
await act(async () => {
|
|
1006
|
+
tree = await create(wrapComponent(store, account, route));
|
|
1007
|
+
});
|
|
1008
|
+
|
|
1009
|
+
const client = mqtt.connect();
|
|
1010
|
+
await act(async () => {
|
|
1011
|
+
client.trigger('connect');
|
|
1012
|
+
});
|
|
1013
|
+
expect(client.subscribe).toHaveBeenCalledWith(
|
|
1014
|
+
`eoh/chip/${gatewayDataFactory.code}/#`
|
|
1015
|
+
);
|
|
1016
|
+
|
|
1017
|
+
expect(useWatchConfigs).toHaveBeenLastCalledWith([2]);
|
|
1018
|
+
expect(watchMultiDataChips).toHaveBeenCalledWith([1]);
|
|
961
1019
|
});
|
|
962
1020
|
});
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import MockAdapter from 'axios-mock-adapter';
|
|
1
2
|
import React from 'react';
|
|
2
3
|
import renderer, { act } from 'react-test-renderer';
|
|
3
4
|
|
|
@@ -8,17 +9,28 @@ import ActionGroup from '../../../commons/ActionGroup';
|
|
|
8
9
|
import MediaPlayerDetail from '../../../commons/MediaPlayerDetail';
|
|
9
10
|
import FlatListItems from '../../../commons/Device/FlatListItems';
|
|
10
11
|
import VisualChart from '../components/VisualChart';
|
|
11
|
-
import SmartIr from '../../SmartIr';
|
|
12
12
|
import FooterInfo from '../../../commons/Device/FooterInfo';
|
|
13
13
|
import Anemometer from '../../../commons/Device/WindSpeed/Anemometer';
|
|
14
14
|
import ProgressBar from '../../../commons/Device/ProgressBar';
|
|
15
15
|
import Compass from '../../../commons/Device/WindDirection/Compass';
|
|
16
16
|
import DeviceAlertStatus from '../../../commons/Device/DeviceAlertStatus';
|
|
17
|
-
import MockAdapter from 'axios-mock-adapter';
|
|
18
|
-
import api from '../../../utils/Apis/axios';
|
|
19
17
|
import CurrentRainSensor from '../../../commons/Device/RainningSensor/CurrentRainSensor';
|
|
20
18
|
import LabelValue from '../../../commons/Device/LabelValue';
|
|
21
19
|
import Text from '../../../commons/Text';
|
|
20
|
+
import SmartIr from '../../SmartIr';
|
|
21
|
+
import api from '../../../utils/Apis/axios';
|
|
22
|
+
|
|
23
|
+
const mockIncrementReviewTrigger = jest.fn();
|
|
24
|
+
const mockAskReview = jest.fn();
|
|
25
|
+
jest.mock('../../../hooks/Review/useInAppReview', () => {
|
|
26
|
+
return {
|
|
27
|
+
__esModule: true,
|
|
28
|
+
default: jest.fn(() => ({
|
|
29
|
+
askReview: mockAskReview,
|
|
30
|
+
incrementReviewTrigger: mockIncrementReviewTrigger,
|
|
31
|
+
})),
|
|
32
|
+
};
|
|
33
|
+
});
|
|
22
34
|
|
|
23
35
|
jest.mock('../../../iot/states', () => ({
|
|
24
36
|
useConfigGlobalState: () => [{}, null],
|
|
@@ -35,6 +47,11 @@ const wrapComponent = ({ ...rest }) => (
|
|
|
35
47
|
|
|
36
48
|
describe('Test SensorDisplayItem', () => {
|
|
37
49
|
let tree;
|
|
50
|
+
|
|
51
|
+
beforeEach(() => {
|
|
52
|
+
mockIncrementReviewTrigger.mockClear();
|
|
53
|
+
});
|
|
54
|
+
|
|
38
55
|
it('render visualChart', async () => {
|
|
39
56
|
const item = {
|
|
40
57
|
id: 10452,
|
|
@@ -103,6 +120,14 @@ describe('Test SensorDisplayItem', () => {
|
|
|
103
120
|
expect(actionGroup).toHaveLength(1);
|
|
104
121
|
const labels = instance.findAllByType(Text);
|
|
105
122
|
expect(labels[0].props.children).toEqual('LED');
|
|
123
|
+
|
|
124
|
+
await act(async () => {
|
|
125
|
+
actionGroup[0].props.doAction(
|
|
126
|
+
{ id: 1, name: 'sensor name' },
|
|
127
|
+
{ key: 'action key' }
|
|
128
|
+
);
|
|
129
|
+
});
|
|
130
|
+
expect(mockIncrementReviewTrigger).toHaveBeenCalled();
|
|
106
131
|
});
|
|
107
132
|
|
|
108
133
|
it('render camera', async () => {
|