@eohjsc/react-native-smart-city 0.7.8 → 0.7.9

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 (85) hide show
  1. package/assets/images/AddNewDevice/add-scan-device-icon.svg +13 -0
  2. package/assets/images/Email.svg +9 -0
  3. package/assets/images/lan.svg +3 -0
  4. package/assets/images/wifi-open.svg +3 -0
  5. package/package.json +2 -1
  6. package/src/commons/ActionGroup/StatesGridActionTemplate.js +7 -3
  7. package/src/commons/ActionGroup/__test__/StatesGridActionTemplate.test.js +7 -3
  8. package/src/commons/AlertAction/index.js +1 -0
  9. package/src/commons/Auth/AccountItem.js +17 -3
  10. package/src/commons/Auth/AccountList.js +3 -7
  11. package/src/commons/ConnectWifi/__test__/ConnectWifi.test.js +373 -0
  12. package/src/commons/ConnectWifi/index.js +201 -0
  13. package/src/commons/ConnectWifi/styles.js +69 -0
  14. package/src/commons/Form/TextInputPassword.js +1 -1
  15. package/src/commons/OneTapTemplate/StatesGridActionTemplate.js +6 -2
  16. package/src/configs/API.js +12 -0
  17. package/src/configs/AccessibilityLabel.js +7 -0
  18. package/src/configs/Constants.js +1 -0
  19. package/src/hooks/Common/index.js +2 -2
  20. package/src/hooks/Common/useBlockBack.js +36 -0
  21. package/src/hooks/useMqtt.js +10 -5
  22. package/src/navigations/AddGatewayStack.js +2 -0
  23. package/src/navigations/AllGatewayStack.js +4 -0
  24. package/src/navigations/Main.js +2 -2
  25. package/src/navigations/UnitStack.js +32 -0
  26. package/src/screens/AddNewGateway/ConnectingWifiDevice.js +7 -6
  27. package/src/screens/AddNewGateway/ScanDeviceLocal.js +267 -0
  28. package/src/screens/AddNewGateway/ScanDeviceLocalStyles.js +58 -0
  29. package/src/screens/AddNewGateway/SelectDeviceSubUnit.js +10 -2
  30. package/src/screens/AddNewGateway/SelectDeviceType.js +19 -2
  31. package/src/screens/AddNewGateway/__test__/ScanDeviceLocal.test.js +475 -0
  32. package/src/screens/AddNewGateway/__test__/SelectDeviceType.test.js +2 -2
  33. package/src/screens/AddNewGateway/configs/API.js +8 -0
  34. package/src/screens/AddNewGateway/hooks/useConnectDevice.js +59 -0
  35. package/src/screens/AllGateway/GatewayInfo/__test__/index.test.js +58 -1
  36. package/src/screens/AllGateway/GatewayInfo/index.js +8 -6
  37. package/src/screens/AllGateway/GatewayWifi/__test__/index.test.js +319 -0
  38. package/src/screens/AllGateway/GatewayWifi/index.js +107 -0
  39. package/src/screens/AllGateway/Successfully/__test__/index.test.js +77 -0
  40. package/src/screens/AllGateway/Successfully/index.js +66 -0
  41. package/src/screens/AllGateway/Successfully/styles.js +35 -0
  42. package/src/screens/AllGateway/components/Information/index.js +17 -1
  43. package/src/screens/AllGateway/components/RowItem/index.js +12 -1
  44. package/src/screens/AllGateway/hooks/__test__/index.test.js +18 -0
  45. package/src/screens/AllGateway/hooks/useGateway.js +13 -0
  46. package/src/screens/Automate/AddNewAction/SetupConfigCondition.js +3 -3
  47. package/src/screens/Automate/AddNewAction/SetupScriptEmail.js +79 -0
  48. package/src/screens/Automate/AddNewAction/SetupScriptReceiverEmail.js +166 -0
  49. package/src/screens/Automate/AddNewAction/Styles/SetupScriptEmailStyles.js +37 -0
  50. package/src/screens/Automate/AddNewAction/Styles/SetupScriptReceiverEmailStyles.js +79 -0
  51. package/src/screens/Automate/AddNewAction/__test__/ChooseAction.test.js +1 -1
  52. package/src/screens/Automate/AddNewAction/__test__/SetupConfigCondition.test.js +13 -5
  53. package/src/screens/Automate/AddNewAction/__test__/SetupScriptEmail.test.js +76 -0
  54. package/src/screens/Automate/AddNewAction/__test__/SetupScriptReceiverEmail.test.js +105 -0
  55. package/src/screens/Automate/EditActionsList/Styles/UpdateReceiverEmailScriptStyles.js +78 -0
  56. package/src/screens/Automate/EditActionsList/UpdateEmailScript.js +80 -0
  57. package/src/screens/Automate/EditActionsList/UpdateReceiverEmailScript.js +179 -0
  58. package/src/screens/Automate/EditActionsList/__tests__/UpdateEmailScript.test.js +81 -0
  59. package/src/screens/Automate/EditActionsList/__tests__/UpdateReceiverEmailScript.test.js +83 -0
  60. package/src/screens/Automate/EditActionsList/__tests__/index.test.js +38 -5
  61. package/src/screens/Automate/EditActionsList/index.js +59 -2
  62. package/src/screens/Automate/ScriptDetail/Components/AddActionScript.js +20 -0
  63. package/src/screens/Automate/ScriptDetail/Styles/indexStyles.js +5 -3
  64. package/src/screens/Automate/ScriptDetail/__test__/index.test.js +127 -21
  65. package/src/screens/Automate/ScriptDetail/index.js +57 -14
  66. package/src/screens/SharedUnit/index.js +2 -2
  67. package/src/screens/Sharing/SelectUser.js +47 -47
  68. package/src/screens/Sharing/__test__/SelectUser.test.js +57 -103
  69. package/src/screens/SubUnit/ManageSubUnit.js +94 -90
  70. package/src/screens/SubUnit/ManageSubUnitStyles.js +4 -6
  71. package/src/screens/SubUnit/RearrageSubUnit.js +90 -0
  72. package/src/screens/SubUnit/RearrrageSubUnitStyle.js +65 -0
  73. package/src/screens/SubUnit/__test__/ManageSubUnit.test.js +35 -19
  74. package/src/screens/SubUnit/__test__/RearrangeSubUnit.test.js +129 -0
  75. package/src/screens/SubUnit/hooks/__test__/useManageSubUnit.test.js +6 -7
  76. package/src/screens/SubUnit/hooks/useManageSubUnit.js +8 -16
  77. package/src/screens/Unit/Detail.js +2 -6
  78. package/src/screens/Unit/ManageUnit.js +1 -1
  79. package/src/utils/Functions/__test__/ShortEmail.test.js +5 -0
  80. package/src/utils/I18n/translations/en.js +46 -8
  81. package/src/utils/I18n/translations/vi.js +37 -4
  82. package/src/utils/Route/index.js +7 -0
  83. package/src/commons/Auth/__test__/AccountItem.test.js +0 -31
  84. package/src/hooks/Common/useBlockBackAndroid.js +0 -21
  85. package/src/screens/SubUnit/DetailStyles.js +0 -46
@@ -0,0 +1,475 @@
1
+ import React from 'react';
2
+ import MockAdapter from 'axios-mock-adapter';
3
+ import { FlatList, TouchableOpacity, ActivityIndicator } from 'react-native';
4
+ import renderer, { act } from 'react-test-renderer';
5
+ import { useNavigation } from '@react-navigation/native';
6
+ import Zeroconf from 'react-native-zeroconf';
7
+
8
+ import { ViewButtonBottom, HeaderCustom } from '../../../commons';
9
+ import { DEVICE_TYPE } from '../../../configs/Constants';
10
+ import { SCProvider } from '../../../context';
11
+ import { mockSCStore } from '../../../context/mockStore';
12
+ import ScanDeviceLocal from '../ScanDeviceLocal';
13
+ import { ToastBottomHelper } from '../../../utils/Utils';
14
+ import { getTranslate } from '../../../utils/I18n';
15
+ import Routes from '../../../utils/Route';
16
+
17
+ import { API as DEVICEAPI } from '../configs/API';
18
+ import { api as deviceApi } from '../hooks/useConnectDevice';
19
+
20
+ import { API } from '../../../configs';
21
+ import api from '../../../utils/Apis/axios';
22
+
23
+ jest.mock('react-native-zeroconf', () => jest.fn());
24
+
25
+ const wrapComponent = (route) => (
26
+ <SCProvider initState={mockSCStore({})}>
27
+ <ScanDeviceLocal route={route} />
28
+ </SCProvider>
29
+ );
30
+
31
+ const mock = new MockAdapter(api.axiosInstance);
32
+ const mockDeviceApi = new MockAdapter(deviceApi.axiosInstance);
33
+
34
+ describe('test ScanDeviceLocal', () => {
35
+ let tree;
36
+ const mockedNavigate = useNavigation().navigate;
37
+ const mockedGoBack = useNavigation().goBack;
38
+ const spyToastError = jest.spyOn(ToastBottomHelper, 'error');
39
+
40
+ const zeroconfMock = {
41
+ on: jest.fn(),
42
+ scan: jest.fn(),
43
+ stop: jest.fn(),
44
+ };
45
+
46
+ beforeEach(() => {
47
+ Zeroconf.mockImplementation(() => zeroconfMock);
48
+ });
49
+
50
+ afterEach(() => {
51
+ jest.clearAllMocks();
52
+ });
53
+
54
+ const resolveDeviceAndPress = async (instance, resolvedDevice) => {
55
+ mock.onGet(API.DEV_MODE.CHIP_QR_CODE.DETAIL_BY_SECRET()).reply(200, {
56
+ host: 'mqtt.example.com',
57
+ port: 1883,
58
+ secret: '123456',
59
+ });
60
+ mockDeviceApi.onGet(DEVICEAPI.BOARD.DETAIL()).reply(200, {
61
+ name: resolvedDevice.name,
62
+ type: resolvedDevice.type,
63
+ secret: '123456',
64
+ });
65
+ mockDeviceApi.onPost(DEVICEAPI.BOARD.CONFIG()).reply(200, {
66
+ status: 'success',
67
+ });
68
+
69
+ const resolvedCallback = zeroconfMock.on.mock.calls.find(
70
+ (call) => call[0] === 'resolved'
71
+ )[1];
72
+ await act(async () => {
73
+ await resolvedCallback(resolvedDevice);
74
+ });
75
+
76
+ const flatList = instance.findByType(FlatList);
77
+ expect(flatList.props.data).toEqual([resolvedDevice]);
78
+ await act(async () => {
79
+ await flatList.props.renderItem({ item: resolvedDevice });
80
+ });
81
+
82
+ // Select first device
83
+ const touchable = flatList.findAllByType(TouchableOpacity);
84
+ expect(touchable).toHaveLength(1);
85
+ await act(async () => {
86
+ await touchable[0].props.onPress();
87
+ });
88
+
89
+ // Click connect button
90
+ const viewButtonBottom = instance.findByType(ViewButtonBottom);
91
+ expect(viewButtonBottom.props.rightDisabled).toBeFalsy();
92
+ await act(async () => {
93
+ await viewButtonBottom.props.onRightClick();
94
+ });
95
+
96
+ expect(deviceApi.baseURL).toBe(`http://${resolvedDevice.host}/api`);
97
+
98
+ expect(zeroconfMock.on).toHaveBeenCalledWith(
99
+ 'resolved',
100
+ expect.any(Function)
101
+ );
102
+ expect(zeroconfMock.on).toHaveBeenCalledWith(
103
+ 'remove',
104
+ expect.any(Function)
105
+ );
106
+ expect(zeroconfMock.on).toHaveBeenCalledWith('error', expect.any(Function));
107
+ expect(zeroconfMock.scan).toHaveBeenCalledWith('plugandplay', 'tcp');
108
+ };
109
+
110
+ it('test connect gateway and navigate', async () => {
111
+ const route = { params: { unit: 1 } };
112
+ await act(async () => {
113
+ tree = await renderer.create(wrapComponent(route));
114
+ });
115
+ const instance = tree.root;
116
+
117
+ const resolvedDevice = {
118
+ host: 'host-1.lan',
119
+ name: 'Gateway 1',
120
+ type: 'gateway',
121
+ };
122
+
123
+ await resolveDeviceAndPress(instance, resolvedDevice);
124
+
125
+ expect(mockedNavigate).toHaveBeenCalledWith(Routes.ConnectingWifiDevice, {
126
+ unit: 1,
127
+ subUnit: undefined,
128
+ addDeviceType: 'gateway',
129
+ qrData: {
130
+ host: 'mqtt.example.com',
131
+ port: 1883,
132
+ secret: '123456',
133
+ },
134
+ gateway: {
135
+ name: 'Gateway 1',
136
+ type: 'gateway',
137
+ secret: '123456',
138
+ },
139
+ code: expect.any(String),
140
+ });
141
+ });
142
+
143
+ it('test connect device with subunit and navigate', async () => {
144
+ const route = { params: { unit: 1, subUnit: 1 } };
145
+ await act(async () => {
146
+ tree = await renderer.create(wrapComponent(route));
147
+ });
148
+ const instance = tree.root;
149
+
150
+ const resolvedDevice = {
151
+ host: 'host-1.lan',
152
+ name: 'Device 1',
153
+ type: 'end_device',
154
+ };
155
+
156
+ await resolveDeviceAndPress(instance, resolvedDevice);
157
+
158
+ expect(mockedNavigate).toHaveBeenCalledWith(Routes.ConnectingWifiDevice, {
159
+ unit: 1,
160
+ subUnit: 1,
161
+ addDeviceType: 'end_device',
162
+ qrData: {
163
+ host: 'mqtt.example.com',
164
+ port: 1883,
165
+ secret: '123456',
166
+ },
167
+ gateway: {
168
+ name: 'Device 1',
169
+ type: 'end_device',
170
+ secret: '123456',
171
+ },
172
+ code: expect.any(String),
173
+ });
174
+ });
175
+
176
+ it('test connect device without subunit and navigate', async () => {
177
+ const route = { params: { unit: 1 } };
178
+ await act(async () => {
179
+ tree = await renderer.create(wrapComponent(route));
180
+ });
181
+ const instance = tree.root;
182
+
183
+ const resolvedDevice = {
184
+ host: 'host-1.lan',
185
+ name: 'Device 1',
186
+ type: 'end_device',
187
+ };
188
+
189
+ await resolveDeviceAndPress(instance, resolvedDevice);
190
+
191
+ expect(mockedNavigate).toHaveBeenCalledWith(Routes.SelectDeviceSubUnit, {
192
+ unit: 1,
193
+ deviceType: DEVICE_TYPE.SCAN_DEVICE,
194
+ qrData: {
195
+ host: 'mqtt.example.com',
196
+ port: 1883,
197
+ secret: '123456',
198
+ },
199
+ gateway: {
200
+ name: 'Device 1',
201
+ type: 'end_device',
202
+ secret: '123456',
203
+ },
204
+ code: expect.any(String),
205
+ });
206
+ });
207
+
208
+ it('test handle go back', async () => {
209
+ const route = { params: { unit: 1 } };
210
+ await act(async () => {
211
+ tree = await renderer.create(wrapComponent(route));
212
+ });
213
+ const instance = tree.root;
214
+
215
+ const headerCustom = instance.findByType(HeaderCustom);
216
+ await act(async () => {
217
+ await headerCustom.props.onGoBack();
218
+ });
219
+ expect(mockedGoBack).toHaveBeenCalled();
220
+ });
221
+
222
+ it('test disable connect button when fetch device info error', async () => {
223
+ mockDeviceApi.onGet(DEVICEAPI.BOARD.DETAIL()).networkError();
224
+
225
+ const route = { params: { unit: 1 } };
226
+ await act(async () => {
227
+ tree = await renderer.create(wrapComponent(route));
228
+ });
229
+ const instance = tree.root;
230
+
231
+ const resolvedDevice = {
232
+ host: 'host-1.lan',
233
+ name: 'Device 1',
234
+ type: 'end_device',
235
+ };
236
+
237
+ const resolvedCallback = zeroconfMock.on.mock.calls.find(
238
+ (call) => call[0] === 'resolved'
239
+ )[1];
240
+ await act(async () => {
241
+ await resolvedCallback(resolvedDevice);
242
+ });
243
+
244
+ const flatList = instance.findByType(FlatList);
245
+ expect(flatList.props.data).toEqual([resolvedDevice]);
246
+ await act(async () => {
247
+ await flatList.props.renderItem({ item: resolvedDevice });
248
+ });
249
+
250
+ // Select first device
251
+ const touchable = flatList.findAllByType(TouchableOpacity);
252
+ expect(touchable).toHaveLength(1);
253
+ await act(async () => {
254
+ await touchable[0].props.onPress();
255
+ });
256
+
257
+ const viewButtonBottom = instance.findByType(ViewButtonBottom);
258
+ expect(viewButtonBottom.props.rightDisabled).toBeTruthy();
259
+ });
260
+
261
+ it('test handle connecting device error', async () => {
262
+ mockDeviceApi.onPost(DEVICEAPI.BOARD.CONFIG()).reply(400, {
263
+ status: 'error',
264
+ message: 'Invalid token',
265
+ });
266
+
267
+ const route = { params: { unit: 1 } };
268
+ await act(async () => {
269
+ tree = await renderer.create(wrapComponent(route));
270
+ });
271
+ const instance = tree.root;
272
+
273
+ const viewButtonBottom = instance.findByType(ViewButtonBottom);
274
+ await act(async () => {
275
+ await viewButtonBottom.props.onRightClick();
276
+ });
277
+ expect(spyToastError).toHaveBeenCalledWith(
278
+ getTranslate('en', 'error_sending_data_to_wifi_device')
279
+ );
280
+ });
281
+
282
+ it('test handle zeroconf.on error', async () => {
283
+ const route = { params: { unit: 1 } };
284
+ await act(async () => {
285
+ tree = await renderer.create(wrapComponent(route));
286
+ });
287
+
288
+ expect(zeroconfMock.scan).toHaveBeenCalledTimes(1);
289
+ expect(zeroconfMock.stop).not.toHaveBeenCalled();
290
+ const errorCallback = zeroconfMock.on.mock.calls.find(
291
+ (call) => call[0] === 'error'
292
+ )[1];
293
+ await act(async () => {
294
+ await errorCallback();
295
+ });
296
+ expect(zeroconfMock.scan).toHaveBeenCalledTimes(2);
297
+ expect(zeroconfMock.stop).toHaveBeenCalledTimes(1);
298
+ });
299
+
300
+ it('test call zeroconf.stop in cleanup function when unmount', async () => {
301
+ const route = { params: { unit: 1 } };
302
+ await act(async () => {
303
+ tree = await renderer.create(wrapComponent(route));
304
+ });
305
+
306
+ expect(zeroconfMock.scan).toHaveBeenCalledTimes(1);
307
+
308
+ await act(async () => {
309
+ tree.unmount();
310
+ });
311
+ expect(zeroconfMock.stop).toHaveBeenCalledTimes(1);
312
+ });
313
+
314
+ it('test handle zeroconf throw scan error', async () => {
315
+ Zeroconf.mockImplementation(() => {
316
+ throw new Error('Scan error');
317
+ });
318
+
319
+ const route = { params: { unit: 1 } };
320
+ await act(async () => {
321
+ tree = await renderer.create(wrapComponent(route));
322
+ });
323
+
324
+ expect(zeroconfMock.on).not.toHaveBeenCalled();
325
+ expect(zeroconfMock.scan).not.toHaveBeenCalled();
326
+ expect(zeroconfMock.stop).not.toHaveBeenCalled();
327
+ });
328
+
329
+ it('test handle zeroconf throw scan error and cleanup function when unmount', async () => {
330
+ Zeroconf.mockImplementation(() => {
331
+ throw new Error('Scan error');
332
+ });
333
+
334
+ const route = { params: { unit: 1 } };
335
+ await act(async () => {
336
+ tree = await renderer.create(wrapComponent(route));
337
+ });
338
+
339
+ expect(zeroconfMock.on).not.toHaveBeenCalled();
340
+ expect(zeroconfMock.scan).not.toHaveBeenCalled();
341
+ expect(zeroconfMock.stop).not.toHaveBeenCalled();
342
+
343
+ await act(async () => {
344
+ tree.unmount();
345
+ });
346
+ expect(zeroconfMock.stop).not.toHaveBeenCalled();
347
+ });
348
+
349
+ it('test handleGoBack stops zeroconf and navigates back', async () => {
350
+ const route = { params: { unit: 1 } };
351
+ await act(async () => {
352
+ tree = await renderer.create(wrapComponent(route));
353
+ });
354
+ const instance = tree.root;
355
+
356
+ const headerCustom = instance.findByType(HeaderCustom);
357
+ await act(async () => {
358
+ await headerCustom.props.onGoBack();
359
+ });
360
+
361
+ expect(zeroconfMock.stop).toHaveBeenCalledTimes(1);
362
+ expect(mockedGoBack).toHaveBeenCalled();
363
+ });
364
+
365
+ it('test handleGoBack when zeroconf throw scan error', async () => {
366
+ Zeroconf.mockImplementation(() => {
367
+ throw new Error('Scan error');
368
+ });
369
+
370
+ const route = { params: { unit: 1 } };
371
+ await act(async () => {
372
+ tree = await renderer.create(wrapComponent(route));
373
+ });
374
+ const instance = tree.root;
375
+
376
+ const headerCustom = instance.findByType(HeaderCustom);
377
+ await act(async () => {
378
+ await headerCustom.props.onGoBack();
379
+ });
380
+
381
+ expect(zeroconfMock.stop).not.toHaveBeenCalled();
382
+ expect(mockedGoBack).toHaveBeenCalled();
383
+ });
384
+
385
+ it('test renders loading indicator when device list is empty', async () => {
386
+ const route = { params: { unit: 1 } };
387
+ await act(async () => {
388
+ tree = await renderer.create(wrapComponent(route));
389
+ });
390
+ const instance = tree.root;
391
+
392
+ const activityIndicator = instance.findByType(ActivityIndicator);
393
+ expect(activityIndicator).toBeTruthy();
394
+ });
395
+
396
+ it('test renders device list when devices are available', async () => {
397
+ const route = { params: { unit: 1 } };
398
+ await act(async () => {
399
+ tree = await renderer.create(wrapComponent(route));
400
+ });
401
+ const instance = tree.root;
402
+
403
+ const resolvedDevice = {
404
+ host: 'host-1.lan',
405
+ name: 'Device 1',
406
+ type: 'end_device',
407
+ };
408
+
409
+ const resolvedCallback = zeroconfMock.on.mock.calls.find(
410
+ (call) => call[0] === 'resolved'
411
+ )[1];
412
+ await act(async () => {
413
+ await resolvedCallback(resolvedDevice);
414
+ });
415
+
416
+ await resolveDeviceAndPress(instance, resolvedDevice);
417
+
418
+ const flatList = instance.findByType(FlatList);
419
+ expect(flatList.props.data).toEqual([resolvedDevice]);
420
+ });
421
+
422
+ it('test renders device list when zeroconf.on remove', async () => {
423
+ const route = { params: { unit: 1 } };
424
+ await act(async () => {
425
+ tree = await renderer.create(wrapComponent(route));
426
+ });
427
+ const instance = tree.root;
428
+
429
+ const resolvedDevice = {
430
+ host: 'host-1.lan',
431
+ name: 'Device 1',
432
+ type: 'end_device',
433
+ };
434
+
435
+ await resolveDeviceAndPress(instance, resolvedDevice);
436
+
437
+ const removeCallback = zeroconfMock.on.mock.calls.find(
438
+ (call) => call[0] === 'remove'
439
+ )[1];
440
+
441
+ // Remove device not in the list
442
+ await act(async () => {
443
+ await removeCallback('Device 2');
444
+ });
445
+
446
+ const flatList = instance.findByType(FlatList);
447
+ expect(flatList.props.data).toEqual([resolvedDevice]);
448
+
449
+ // Remove device in the list
450
+ await act(async () => {
451
+ await removeCallback('Device 1');
452
+ });
453
+
454
+ const flatListAfter = instance.findAllByType(FlatList);
455
+ expect(flatListAfter.length).toBe(0);
456
+
457
+ const activityIndicator = instance.findByType(ActivityIndicator);
458
+ expect(activityIndicator).toBeTruthy();
459
+ });
460
+
461
+ it('test when params is null', async () => {
462
+ const route = {};
463
+ await act(async () => {
464
+ tree = await renderer.create(wrapComponent(route));
465
+ });
466
+
467
+ const instance = tree.root;
468
+
469
+ const headerCustom = instance.findByType(HeaderCustom);
470
+ expect(headerCustom).toBeTruthy();
471
+
472
+ const activityIndicator = instance.findByType(ActivityIndicator);
473
+ expect(activityIndicator).toBeTruthy();
474
+ });
475
+ });
@@ -51,7 +51,7 @@ describe('Test select device type', () => {
51
51
  el.type === TouchableOpacity &&
52
52
  el.props.accessibilityLabel === AccessibilityLabel.ITEM_DEVICE_TYPE
53
53
  );
54
- expect(deviceTypeItems).toHaveLength(4);
54
+ expect(deviceTypeItems).toHaveLength(5);
55
55
  });
56
56
 
57
57
  it('render select type with station', async () => {
@@ -73,7 +73,7 @@ describe('Test select device type', () => {
73
73
  el.type === TouchableOpacity &&
74
74
  el.props.accessibilityLabel === AccessibilityLabel.ITEM_DEVICE_TYPE
75
75
  );
76
- expect(deviceTypeItems).toHaveLength(3);
76
+ expect(deviceTypeItems).toHaveLength(4);
77
77
  });
78
78
 
79
79
  const selectDeviceType = async (index, storeData = {}) => {
@@ -0,0 +1,8 @@
1
+ // API endpoint for interfacing with the chip
2
+ export const API = {
3
+ BOARD: {
4
+ DETAIL: () => '/board_info.json',
5
+ SCAN_WIFI: () => '/wifi_scan.json',
6
+ CONFIG: () => '/config',
7
+ },
8
+ };
@@ -0,0 +1,59 @@
1
+ import { create } from 'apisauce';
2
+ import { useState, useCallback, useEffect } from 'react';
3
+
4
+ import { API } from '../configs/API';
5
+
6
+ export const api = create({
7
+ timeout: 10000,
8
+ headers: {
9
+ 'Content-Type': 'application/json',
10
+ },
11
+ });
12
+
13
+ export const useConnectDevice = (host) => {
14
+ const [deviceInfo, setDeviceInfo] = useState();
15
+ const [listWiFiDevice, setListWiFiDevice] = useState([]);
16
+ const [lastError, setLastError] = useState();
17
+
18
+ useEffect(() => {
19
+ api.baseURL = `http://${host}/api`;
20
+ }, [host]);
21
+
22
+ const parseResponse = (response, setInfo) => {
23
+ if (response.data?.status === 'error') {
24
+ setLastError(response.data?.message);
25
+ return false;
26
+ }
27
+ if (!response.ok) {
28
+ setLastError(response.problem);
29
+ return false;
30
+ }
31
+ setInfo && setInfo(response.data);
32
+ return true;
33
+ };
34
+
35
+ const fetchDeviceInfo = useCallback(async () => {
36
+ const response = await api.get(API.BOARD.DETAIL());
37
+ return parseResponse(response, setDeviceInfo);
38
+ }, []);
39
+
40
+ const fetchListWiFiDevice = useCallback(async () => {
41
+ const response = await api.get(API.BOARD.SCAN_WIFI());
42
+ return parseResponse(response, setListWiFiDevice);
43
+ }, []);
44
+
45
+ const sendConfigToDevice = useCallback(async (config) => {
46
+ const response = await api.post(API.BOARD.CONFIG(), config);
47
+ return parseResponse(response);
48
+ }, []);
49
+
50
+ return {
51
+ deviceInfo,
52
+ listWiFiDevice,
53
+ lastError,
54
+
55
+ fetchDeviceInfo,
56
+ fetchListWiFiDevice,
57
+ sendConfigToDevice,
58
+ };
59
+ };
@@ -1,7 +1,7 @@
1
1
  import { useRoute } from '@react-navigation/native';
2
2
  import MockAdapter from 'axios-mock-adapter';
3
3
  import React from 'react';
4
- import { FlatList } from 'react-native';
4
+ import { FlatList, TouchableOpacity } from 'react-native';
5
5
  import { act, create } from 'react-test-renderer';
6
6
 
7
7
  import GatewayInfo from '..';
@@ -12,6 +12,8 @@ import API from '../../../../configs/API';
12
12
  import { AccessibilityLabel } from '../../../../configs/Constants';
13
13
  import { SCProvider } from '../../../../context';
14
14
  import { mockSCStore } from '../../../../context/mockStore';
15
+ import { ToastBottomHelper } from '../../../../utils/Utils';
16
+ import { getTranslate } from '../../../../utils/I18n';
15
17
  import t from '../../../../hooks/Common/useTranslations';
16
18
  import api from '../../../../utils/Apis/axios';
17
19
  import Routes from '../../../../utils/Route';
@@ -37,6 +39,9 @@ const buttonDelete = (instance) => {
37
39
 
38
40
  describe('Test GatewayInfo', () => {
39
41
  let tree;
42
+
43
+ const spyToastError = jest.spyOn(ToastBottomHelper, 'error');
44
+
40
45
  beforeEach(() => {
41
46
  useRoute.mockReturnValue({
42
47
  params: {
@@ -47,6 +52,7 @@ describe('Test GatewayInfo', () => {
47
52
 
48
53
  afterEach(() => {
49
54
  mock.reset();
55
+ spyToastError.mockClear();
50
56
  });
51
57
 
52
58
  it('test render GatewayInfo', async () => {
@@ -134,4 +140,55 @@ describe('Test GatewayInfo', () => {
134
140
  });
135
141
  expect(modal.props.isVisible).toBeFalsy();
136
142
  });
143
+
144
+ it('test press change wifi when gateway connected', async () => {
145
+ const mockResponse = {
146
+ id: 1,
147
+ name: 'device 1',
148
+ arduino_gateway: 1,
149
+ modbus_gateway: 1,
150
+ zigbee_gateway: 1,
151
+ is_connected: true,
152
+ };
153
+ mock.onGet(API.DEV_MODE.GATEWAY.DETAIL(1)).reply(200, mockResponse);
154
+
155
+ await act(async () => {
156
+ tree = await create(wrapComponent());
157
+ });
158
+
159
+ const instance = tree.root;
160
+ const connectWifi = instance.find(
161
+ (el) =>
162
+ el.props.accessibilityLabel === AccessibilityLabel.CHANGE_WIFI &&
163
+ el.type === TouchableOpacity
164
+ );
165
+
166
+ await act(async () => {
167
+ await connectWifi.props.onPress();
168
+ });
169
+
170
+ expect(global.mockedNavigate).toHaveBeenCalledWith(Routes.GatewayWifi, {
171
+ gateway: mockResponse,
172
+ });
173
+ });
174
+
175
+ it('test press change wifi when gateway not connected', async () => {
176
+ await act(async () => {
177
+ tree = await create(wrapComponent());
178
+ });
179
+
180
+ const instance = tree.root;
181
+ const connectWifi = instance.find(
182
+ (el) =>
183
+ el.props.accessibilityLabel === AccessibilityLabel.CHANGE_WIFI &&
184
+ el.type === TouchableOpacity
185
+ );
186
+
187
+ await act(async () => {
188
+ await connectWifi.props.onPress();
189
+ });
190
+ expect(spyToastError).toHaveBeenCalledWith(
191
+ getTranslate('en', 'gateway_need_to_be_connected')
192
+ );
193
+ });
137
194
  });
@@ -35,7 +35,8 @@ const GatewayInfo = () => {
35
35
  id,
36
36
  date_install = '',
37
37
  expired_at = '',
38
- firmware = {},
38
+ info = {},
39
+ board = '',
39
40
  code = '',
40
41
  arduino_gateway = undefined,
41
42
  modbus_gateway = undefined,
@@ -60,8 +61,8 @@ const GatewayInfo = () => {
60
61
  () => [
61
62
  {
62
63
  id: 1,
63
- title: 'system',
64
- data: firmware?.board || '--',
64
+ title: 'board',
65
+ data: board || '--',
65
66
  },
66
67
  {
67
68
  id: 2,
@@ -96,14 +97,15 @@ const GatewayInfo = () => {
96
97
  {
97
98
  id: 9,
98
99
  title: 'firmware_version',
99
- data: firmware?.board || '--',
100
+ data: info?.firmware_version || '--',
100
101
  },
101
102
  ],
102
103
  [
104
+ board,
103
105
  connection_time,
104
106
  date_install,
105
107
  expired_at,
106
- firmware?.board,
108
+ info,
107
109
  id,
108
110
  code,
109
111
  wifi_ssid,
@@ -145,7 +147,7 @@ const GatewayInfo = () => {
145
147
  <View style={styles.wrap}>
146
148
  <Information
147
149
  buttonBackStyles={styles.buttonBack}
148
- data={gatewayDetail}
150
+ gatewayDetail={gatewayDetail}
149
151
  methodsConnection={methodsConnection}
150
152
  listInformation={gatewayInformation}
151
153
  handleDeleteGateway={handleDeleteGateway}