@eohjsc/react-native-smart-city 0.3.32 → 0.3.35
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/assets/images/AddNewDevice/add-gateway-icon.svg +13 -0
- package/assets/images/AddNewDevice/add-modbus-device-icon.svg +8 -0
- package/assets/images/AddNewDevice/add-wifi-device-icon.svg +4 -0
- package/assets/images/AddNewDevice/add-zigbee-device-icon.svg +4 -0
- package/assets/images/AddNewDevice/interact-smartphone-icon.svg +14 -0
- package/index.js +2 -0
- package/package.json +2 -1
- package/src/Images/SmartAccount/DienQuang.png +0 -0
- package/src/Images/SmartAccount/DienQuang@2x.png +0 -0
- package/src/Images/SmartAccount/DienQuang@3x.png +0 -0
- package/src/Images/SmartAccount/LG.png +0 -0
- package/src/Images/SmartAccount/LG@2x.png +0 -0
- package/src/Images/SmartAccount/LG@3x.png +0 -0
- package/src/Images/SmartAccount/Samsung.png +0 -0
- package/src/Images/SmartAccount/Samsung@2x.png +0 -0
- package/src/Images/SmartAccount/Samsung@3x.png +0 -0
- package/src/commons/Action/ItemQuickAction.js +18 -1
- package/src/commons/Action/__test__/ItemQuickAction.test.js +18 -2
- package/src/commons/ActionGroup/NumberUpDownActionTemplate.js +5 -2
- package/src/commons/ActionGroup/OnOffTemplate/index.js +28 -10
- package/src/commons/ActionGroup/OptionsDropdownActionTemplate.js +15 -8
- package/src/commons/ActionGroup/StatesGridActionTemplate.js +19 -5
- package/src/commons/ActionTemplate/OnOffButtonAction.js +14 -5
- package/src/commons/ActionTemplate/__test__/OnOffButtonAction.test.js +23 -2
- package/src/commons/ActionTemplate/__test__/index.test.js +2 -0
- package/src/commons/ActionTemplate/index.js +1 -0
- package/src/commons/Automate/ItemAutomate.js +10 -1
- package/src/commons/OneTapTemplate/NumberUpDownActionTemplate.js +1 -1
- package/src/commons/SelectSubUnit/index.js +18 -18
- package/src/commons/SelectSubUnit/styles.js +0 -3
- package/src/commons/SelectUnit/index.js +2 -3
- package/src/commons/SelectUnit/styles.js +1 -2
- package/src/commons/Tabbar/__test__/index.test.js +97 -0
- package/src/configs/API.js +10 -0
- package/src/configs/AccessibilityLabel.js +21 -0
- package/src/configs/Images.js +2 -0
- package/src/context/actionType.ts +3 -0
- package/src/context/reducer.ts +22 -0
- package/src/hoc/__test__/withRemoteControl.test.js +24 -0
- package/src/hooks/Common/__test__/useAndroidTranslucentStatusBar.test.js +55 -0
- package/src/hooks/Common/useDevicesStatus.js +19 -15
- package/src/hooks/__test__/useInitDeepLink.test.js +28 -0
- package/src/hooks/useReceiveNotifications.js +2 -4
- package/src/navigations/AddGatewayStack.js +5 -0
- package/src/navigations/SmartAccountStack.js +52 -0
- package/src/screens/AddCommon/SelectSubUnit.js +17 -13
- package/src/screens/AddCommon/SelectUnit.js +14 -7
- package/src/screens/AddCommon/__test__/SelectSubUnit.test.js +18 -11
- package/src/screens/AddCommon/__test__/SelectUnit.test.js +13 -6
- package/src/screens/AddNewAction/SelectAction.js +10 -1
- package/src/screens/AddNewAction/SetupSensor.js +6 -0
- package/src/screens/AddNewGateway/ConnectingWifiGuide.js +167 -0
- package/src/screens/AddNewGateway/ConnectingWifiGuideStyles.js +58 -0
- package/src/screens/AddNewGateway/PlugAndPlay/FirstWarning.js +0 -5
- package/src/screens/AddNewGateway/PlugAndPlay/__test__/FirstWarning.test.js +1 -1
- package/src/screens/AddNewGateway/ScanGatewayQR.js +30 -7
- package/src/screens/AddNewGateway/SelectDeviceType.js +138 -43
- package/src/screens/AddNewGateway/SelectDeviceTypeStyles.js +51 -0
- package/src/screens/AddNewGateway/SelectDeviceUnit.js +1 -1
- package/src/screens/AddNewGateway/ShareWifiPassword.js +6 -110
- package/src/screens/AddNewGateway/__test__/ConnectingWifiGuide.test.js +224 -0
- package/src/screens/AddNewGateway/__test__/ScanGatewayQR.test.js +6 -7
- package/src/screens/AddNewGateway/__test__/SelectDeviceType.test.js +46 -11
- package/src/screens/AddNewGateway/__test__/ShareWifiPassword.test.js +4 -143
- package/src/screens/EditActionsList/__tests__/index.test.js +120 -0
- package/src/screens/EditActionsList/index.js +15 -5
- package/src/screens/ScriptDetail/__test__/index.test.js +35 -34
- package/src/screens/ScriptDetail/index.js +19 -10
- package/src/screens/SharedUnit/__test__/ShareUnit.test.js +25 -0
- package/src/screens/SharedUnit/index.js +2 -0
- package/src/screens/Sharing/Components/{SensorItem.js → DeviceItem.js} +38 -28
- package/src/screens/Sharing/Components/Styles/{SensorItemStyles.js → DeviceItemStyles.js} +0 -0
- package/src/screens/Sharing/Components/__test__/{SensorItem.test.js → DeviceItem.test.js} +6 -6
- package/src/screens/Sharing/Components/index.js +2 -2
- package/src/screens/Sharing/SelectPermission.js +130 -119
- package/src/screens/Sharing/Styles/SelectPermissionStyles.js +2 -2
- package/src/screens/Sharing/__test__/SelectPermission.test.js +67 -14
- package/src/screens/SmartAccount/Connecting/index.js +171 -0
- package/src/screens/SmartAccount/Connecting/style.js +50 -0
- package/src/screens/SmartAccount/ListDevice/DeviceItem.js +45 -0
- package/src/screens/SmartAccount/ListDevice/__test__/DeviceItem.test.js +34 -0
- package/src/screens/SmartAccount/ListDevice/__test__/ListDevice.test.js +139 -0
- package/src/screens/SmartAccount/ListDevice/index.js +186 -0
- package/src/screens/SmartAccount/ListDevice/styles/DeviceItemStyles.js +70 -0
- package/src/screens/SmartAccount/ListDevice/styles/index.js +85 -0
- package/src/screens/SmartAccount/SuccessfullyConnected/DeviceItem.js +37 -0
- package/src/screens/SmartAccount/SuccessfullyConnected/DeviceItemStyles.js +49 -0
- package/src/screens/SmartAccount/SuccessfullyConnected/__test__/DeviceItem.test.js +65 -0
- package/src/screens/SmartAccount/SuccessfullyConnected/__test__/SuccessfullyConnected.test.js +88 -0
- package/src/screens/SmartAccount/SuccessfullyConnected/index.js +101 -0
- package/src/screens/SmartAccount/SuccessfullyConnected/styles.js +42 -0
- package/src/screens/SmartAccount/__test__/Connecting.test.js +86 -0
- package/src/screens/SmartAccount/__test__/SmartAccount.test.js +249 -0
- package/src/screens/SmartAccount/index.js +172 -0
- package/src/screens/SmartAccount/style.js +70 -0
- package/src/screens/SyncLGDevice/__test__/AddLGDevice.test.js +37 -10
- package/src/screens/Unit/AddMenu.js +4 -5
- package/src/screens/Unit/SmartAccount.js +8 -5
- package/src/screens/Unit/__test__/SmartAccount.test.js +8 -5
- package/src/utils/I18n/translations/en.json +27 -2
- package/src/utils/I18n/translations/vi.json +28 -2
- package/src/utils/Route/index.js +3 -0
- package/src/utils/Utils.js +6 -7
- package/src/utils/Validation.js +4 -0
|
@@ -4,8 +4,10 @@ import { act, create } from 'react-test-renderer';
|
|
|
4
4
|
import SelectDeviceType from '../SelectDeviceType';
|
|
5
5
|
import { SCProvider } from '../../../context';
|
|
6
6
|
import { mockSCStore } from '../../../context/mockStore';
|
|
7
|
-
import Button from '../../../commons/Button';
|
|
8
7
|
import Routes from '../../../utils/Route';
|
|
8
|
+
import { TouchableOpacity } from 'react-native';
|
|
9
|
+
import AccessibilityLabel from '../../../configs/AccessibilityLabel';
|
|
10
|
+
import { ViewButtonBottom } from '../../../commons';
|
|
9
11
|
|
|
10
12
|
const wrapComponent = (route) => (
|
|
11
13
|
<SCProvider initState={mockSCStore({})}>
|
|
@@ -43,18 +45,42 @@ describe('Test select device type', () => {
|
|
|
43
45
|
route = {
|
|
44
46
|
params: {
|
|
45
47
|
unitId: 1,
|
|
46
|
-
|
|
48
|
+
unitName: 'Unit A',
|
|
47
49
|
},
|
|
48
50
|
};
|
|
49
51
|
});
|
|
50
52
|
|
|
51
|
-
test('render select type', async () => {
|
|
53
|
+
test('render select type without station', async () => {
|
|
54
|
+
await act(async () => {
|
|
55
|
+
tree = await create(wrapComponent(route));
|
|
56
|
+
});
|
|
57
|
+
const instance = tree.root;
|
|
58
|
+
const deviceTypeItems = instance.findAll(
|
|
59
|
+
(el) =>
|
|
60
|
+
el.type === TouchableOpacity &&
|
|
61
|
+
el.props.accessibilityLabel === AccessibilityLabel.ITEM_DEVICE_TYPE
|
|
62
|
+
);
|
|
63
|
+
expect(deviceTypeItems).toHaveLength(4);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
test('render select type with station', async () => {
|
|
67
|
+
route = {
|
|
68
|
+
params: {
|
|
69
|
+
unitId: 1,
|
|
70
|
+
unitName: 'Unit A',
|
|
71
|
+
stationId: 1,
|
|
72
|
+
},
|
|
73
|
+
};
|
|
52
74
|
await act(async () => {
|
|
53
75
|
tree = await create(wrapComponent(route));
|
|
54
76
|
});
|
|
55
77
|
const instance = tree.root;
|
|
56
|
-
const
|
|
57
|
-
|
|
78
|
+
const deviceTypeItems = instance.findAll(
|
|
79
|
+
(el) =>
|
|
80
|
+
el.type === TouchableOpacity &&
|
|
81
|
+
el.props.accessibilityLabel === AccessibilityLabel.ITEM_DEVICE_TYPE
|
|
82
|
+
);
|
|
83
|
+
expect(deviceTypeItems).toHaveLength(3);
|
|
58
84
|
});
|
|
59
85
|
|
|
60
86
|
const selectDeviceType = async (index) => {
|
|
@@ -62,9 +88,18 @@ describe('Test select device type', () => {
|
|
|
62
88
|
tree = await create(wrapComponent(route));
|
|
63
89
|
});
|
|
64
90
|
const instance = tree.root;
|
|
65
|
-
const
|
|
91
|
+
const deviceTypeItems = instance.findAll(
|
|
92
|
+
(el) =>
|
|
93
|
+
el.type === TouchableOpacity &&
|
|
94
|
+
el.props.accessibilityLabel === AccessibilityLabel.ITEM_DEVICE_TYPE
|
|
95
|
+
);
|
|
66
96
|
await act(async () => {
|
|
67
|
-
|
|
97
|
+
deviceTypeItems[index].props.onPress();
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
const submitButton = instance.findByType(ViewButtonBottom);
|
|
101
|
+
await act(async () => {
|
|
102
|
+
submitButton.props.onRightClick();
|
|
68
103
|
});
|
|
69
104
|
|
|
70
105
|
expect(mockedNavigate).toBeCalled();
|
|
@@ -72,18 +107,18 @@ describe('Test select device type', () => {
|
|
|
72
107
|
|
|
73
108
|
test('select modbus', async () => {
|
|
74
109
|
await selectDeviceType(0);
|
|
75
|
-
expect(mockedNavigate.mock.calls[0][0]).toEqual(Routes.
|
|
110
|
+
expect(mockedNavigate.mock.calls[0][0]).toEqual(Routes.ScanGatewayQR);
|
|
76
111
|
});
|
|
77
112
|
test('select zigbee', async () => {
|
|
78
113
|
await selectDeviceType(1);
|
|
79
|
-
expect(mockedNavigate.mock.calls[0][0]).toEqual(Routes.
|
|
114
|
+
expect(mockedNavigate.mock.calls[0][0]).toEqual(Routes.SelectDeviceSubUnit);
|
|
80
115
|
});
|
|
81
116
|
test('select gateway', async () => {
|
|
82
117
|
await selectDeviceType(2);
|
|
83
|
-
expect(mockedNavigate.mock.calls[0][0]).toEqual(Routes.
|
|
118
|
+
expect(mockedNavigate.mock.calls[0][0]).toEqual(Routes.SelectDeviceSubUnit);
|
|
84
119
|
});
|
|
85
120
|
test('select wifi', async () => {
|
|
86
121
|
await selectDeviceType(3);
|
|
87
|
-
expect(mockedNavigate.mock.calls[0][0]).toEqual(Routes.
|
|
122
|
+
expect(mockedNavigate.mock.calls[0][0]).toEqual(Routes.SelectDeviceSubUnit);
|
|
88
123
|
});
|
|
89
124
|
});
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import renderer, { act } from 'react-test-renderer';
|
|
3
|
+
import { Platform } from 'react-native';
|
|
4
|
+
import dgram from 'react-native-udp';
|
|
5
|
+
import Toast from 'react-native-toast-message';
|
|
6
|
+
import WifiManager from 'react-native-wifi-reborn';
|
|
3
7
|
|
|
4
8
|
import ShareWifiPassword from '../ShareWifiPassword';
|
|
5
9
|
import { SCProvider } from '../../../context';
|
|
6
10
|
import { mockSCStore } from '../../../context/mockStore';
|
|
7
11
|
import ButtonPopup from '../../../commons/ButtonPopup';
|
|
8
12
|
import TextInputPassword from '../../../commons/Form/TextInputPassword';
|
|
9
|
-
import { Platform, TouchableOpacity } from 'react-native';
|
|
10
|
-
import WifiManager from 'react-native-wifi-reborn';
|
|
11
|
-
import dgram from 'react-native-udp';
|
|
12
13
|
import Routes from '../../../utils/Route';
|
|
13
|
-
import Toast from 'react-native-toast-message';
|
|
14
14
|
|
|
15
15
|
const mockedGoBack = jest.fn();
|
|
16
16
|
const mockedNavigate = jest.fn();
|
|
@@ -55,145 +55,6 @@ describe('test share wifi password', () => {
|
|
|
55
55
|
expect(passwordFields).toHaveLength(1);
|
|
56
56
|
});
|
|
57
57
|
|
|
58
|
-
test('auto connect to wifi prefix on ios', async () => {
|
|
59
|
-
Platform.OS = 'ios';
|
|
60
|
-
const route = { params: { prefix: 'robot' } };
|
|
61
|
-
await act(async () => {
|
|
62
|
-
tree = await renderer.create(wrapComponent(route));
|
|
63
|
-
});
|
|
64
|
-
expect(WifiManager.connectToProtectedSSIDPrefix).toBeCalled();
|
|
65
|
-
expect(WifiManager.connectToProtectedSSIDPrefix.mock.calls[0][0]).toEqual(
|
|
66
|
-
'eoh.robot.'
|
|
67
|
-
);
|
|
68
|
-
const socket = dgram.createSocket();
|
|
69
|
-
expect(socket.bind).toBeCalled();
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
test('fail connect to wifi prefix on ios', async () => {
|
|
73
|
-
Platform.OS = 'ios';
|
|
74
|
-
const route = { params: { prefix: 'robot' } };
|
|
75
|
-
WifiManager.connectToProtectedSSIDPrefix.mockImplementationOnce(
|
|
76
|
-
async () => {
|
|
77
|
-
throw 'Cannot connect to protected prefix SSID';
|
|
78
|
-
}
|
|
79
|
-
);
|
|
80
|
-
await act(async () => {
|
|
81
|
-
tree = await renderer.create(wrapComponent(route));
|
|
82
|
-
});
|
|
83
|
-
const socket = dgram.createSocket();
|
|
84
|
-
expect(socket.bind).not.toBeCalled();
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
test('auto connect to wifi android', async () => {
|
|
88
|
-
Platform.OS = 'android';
|
|
89
|
-
const route = { params: { prefix: 'robot' } };
|
|
90
|
-
WifiManager.loadWifiList.mockImplementationOnce(async () => [
|
|
91
|
-
{ SSID: 'random-name' },
|
|
92
|
-
{ SSID: 'eoh.lite.xxx' },
|
|
93
|
-
{ SSID: 'eoh.robot.xxx' },
|
|
94
|
-
]);
|
|
95
|
-
await act(async () => {
|
|
96
|
-
tree = await renderer.create(wrapComponent(route));
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
expect(WifiManager.connectToProtectedSSID).toBeCalled();
|
|
100
|
-
expect(WifiManager.connectToProtectedSSID.mock.calls[0][0]).toEqual(
|
|
101
|
-
'eoh.robot.xxx'
|
|
102
|
-
);
|
|
103
|
-
const socket = dgram.createSocket();
|
|
104
|
-
expect(socket.bind).toBeCalled();
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
test('fail connect to wifi android', async () => {
|
|
108
|
-
Platform.OS = 'android';
|
|
109
|
-
const route = { params: { prefix: 'robot' } };
|
|
110
|
-
WifiManager.reScanAndLoadWifiList.mockImplementationOnce(async () => [
|
|
111
|
-
{ SSID: 'random-name' },
|
|
112
|
-
{ SSID: 'eoh.lite.xxx' },
|
|
113
|
-
{ SSID: 'eoh.robot.xxx' },
|
|
114
|
-
]);
|
|
115
|
-
WifiManager.connectToProtectedSSID.mockImplementationOnce(async () => {
|
|
116
|
-
throw 'Cannot connect to wifi';
|
|
117
|
-
});
|
|
118
|
-
await act(async () => {
|
|
119
|
-
tree = await renderer.create(wrapComponent(route));
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
const socket = dgram.createSocket();
|
|
123
|
-
expect(socket.bind).not.toBeCalled();
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
test('fail load wifi list android', async () => {
|
|
127
|
-
Platform.OS = 'android';
|
|
128
|
-
const route = { params: { prefix: 'robot' } };
|
|
129
|
-
WifiManager.reScanAndLoadWifiList.mockImplementationOnce(async () => {
|
|
130
|
-
throw 'Cannot load wifi list to wifi';
|
|
131
|
-
});
|
|
132
|
-
await act(async () => {
|
|
133
|
-
tree = await renderer.create(wrapComponent(route));
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
const socket = dgram.createSocket();
|
|
137
|
-
expect(socket.bind).not.toBeCalled();
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
test('request wifi list from device', async () => {
|
|
141
|
-
jest.useFakeTimers();
|
|
142
|
-
Platform.OS = 'android';
|
|
143
|
-
const route = { params: { prefix: 'robot' } };
|
|
144
|
-
await act(async () => {
|
|
145
|
-
tree = await renderer.create(wrapComponent(route));
|
|
146
|
-
});
|
|
147
|
-
jest.runOnlyPendingTimers();
|
|
148
|
-
const socket = dgram.createSocket({});
|
|
149
|
-
expect(socket.send).toBeCalled();
|
|
150
|
-
const data = JSON.parse(socket.send.mock.calls[0][0]);
|
|
151
|
-
expect(data.type).toEqual('scan');
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
test('got wifi list from device', async () => {
|
|
155
|
-
Platform.OS = 'android';
|
|
156
|
-
const route = { params: { prefix: 'robot' } };
|
|
157
|
-
await act(async () => {
|
|
158
|
-
tree = await renderer.create(wrapComponent(route));
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
const socket = dgram.createSocket({});
|
|
162
|
-
expect(socket.on).toBeCalled();
|
|
163
|
-
expect(socket.on.mock.calls[0][0]).toEqual('message');
|
|
164
|
-
|
|
165
|
-
expect(
|
|
166
|
-
tree.root.findAll((el) => el.type === TouchableOpacity)
|
|
167
|
-
).toHaveLength(4);
|
|
168
|
-
|
|
169
|
-
await act(async () => {
|
|
170
|
-
socket.on.mock.calls[0][1](
|
|
171
|
-
JSON.stringify({
|
|
172
|
-
wifi: [{ ssid: 'wifi 1' }, { ssid: 'wifi.2' }],
|
|
173
|
-
})
|
|
174
|
-
);
|
|
175
|
-
});
|
|
176
|
-
// todo Bang should test wifi display
|
|
177
|
-
expect(socket.close).toBeCalled();
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
test('got error while request wifi list from device', async () => {
|
|
181
|
-
Platform.OS = 'android';
|
|
182
|
-
const route = { params: { prefix: 'robot' } };
|
|
183
|
-
await act(async () => {
|
|
184
|
-
tree = await renderer.create(wrapComponent(route));
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
const socket = dgram.createSocket({});
|
|
188
|
-
expect(socket.on).toBeCalledTimes(2);
|
|
189
|
-
expect(socket.on.mock.calls[1][0]).toEqual('error');
|
|
190
|
-
|
|
191
|
-
await act(async () => {
|
|
192
|
-
socket.on.mock.calls[1][1]();
|
|
193
|
-
});
|
|
194
|
-
expect(Toast.show).toBeCalled();
|
|
195
|
-
});
|
|
196
|
-
|
|
197
58
|
const sendPasswordToGateway = async () => {
|
|
198
59
|
jest.useFakeTimers();
|
|
199
60
|
Platform.OS = 'android';
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import DraggableFlatList from 'react-native-draggable-flatlist';
|
|
3
|
+
import { create, act } from 'react-test-renderer';
|
|
4
|
+
import { SCProvider } from '../../../context';
|
|
5
|
+
import { mockSCStore } from '../../../context/mockStore';
|
|
6
|
+
import EditActionsList from '../index';
|
|
7
|
+
import { AccessibilityLabel } from '../../../configs/Constants';
|
|
8
|
+
import { TouchableOpacity } from 'react-native';
|
|
9
|
+
import api from '../../../utils/Apis/axios';
|
|
10
|
+
import MockAdapter from 'axios-mock-adapter';
|
|
11
|
+
import API from '../../../configs/API';
|
|
12
|
+
|
|
13
|
+
import { ModalBottom } from '../../../commons/Modal';
|
|
14
|
+
|
|
15
|
+
const mockSetdata = jest.fn();
|
|
16
|
+
const mockedNavigate = jest.fn();
|
|
17
|
+
const mockGoBack = jest.fn();
|
|
18
|
+
|
|
19
|
+
const wrapComponent = () => (
|
|
20
|
+
<SCProvider initState={mockSCStore({})}>
|
|
21
|
+
<EditActionsList />
|
|
22
|
+
</SCProvider>
|
|
23
|
+
);
|
|
24
|
+
const mock = new MockAdapter(api.axiosInstance);
|
|
25
|
+
|
|
26
|
+
jest.mock('@react-navigation/native', () => {
|
|
27
|
+
return {
|
|
28
|
+
...jest.requireActual('@react-navigation/native'),
|
|
29
|
+
useRoute: jest.fn().mockReturnValue({
|
|
30
|
+
params: {
|
|
31
|
+
data: [{ id: 1, sensor_name: 'abc', station_name: 'abc' }],
|
|
32
|
+
id: 1,
|
|
33
|
+
setData: mockSetdata,
|
|
34
|
+
unit: { id: 1, name: 'unit' },
|
|
35
|
+
},
|
|
36
|
+
}),
|
|
37
|
+
useNavigation: () => ({
|
|
38
|
+
navigate: mockedNavigate,
|
|
39
|
+
goBack: mockGoBack,
|
|
40
|
+
}),
|
|
41
|
+
useIsFocused: () => true,
|
|
42
|
+
};
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
jest.mock('react-native-parsed-text', () => () => []);
|
|
46
|
+
|
|
47
|
+
describe('EditActionsList', () => {
|
|
48
|
+
let tree;
|
|
49
|
+
|
|
50
|
+
beforeEach(() => {
|
|
51
|
+
mockGoBack.mockClear();
|
|
52
|
+
});
|
|
53
|
+
test('render EditActionsList', async () => {
|
|
54
|
+
await act(async () => {
|
|
55
|
+
tree = await create(wrapComponent());
|
|
56
|
+
});
|
|
57
|
+
const instance = tree.root;
|
|
58
|
+
const draggableFlatList = instance.findAllByType(DraggableFlatList);
|
|
59
|
+
const modalBottom = instance.findAllByType(ModalBottom);
|
|
60
|
+
expect(draggableFlatList).toHaveLength(1);
|
|
61
|
+
expect(modalBottom).toHaveLength(1);
|
|
62
|
+
});
|
|
63
|
+
test('EditActionsList onPress cancel', async () => {
|
|
64
|
+
await act(async () => {
|
|
65
|
+
tree = await create(wrapComponent());
|
|
66
|
+
});
|
|
67
|
+
const instance = tree.root;
|
|
68
|
+
const buttonCancel = instance.find(
|
|
69
|
+
(el) =>
|
|
70
|
+
el.props.accessibilityLabel ===
|
|
71
|
+
AccessibilityLabel.BUTTON_CANCEL_EDIT_ACTION_LIST &&
|
|
72
|
+
el.type === TouchableOpacity
|
|
73
|
+
);
|
|
74
|
+
expect(buttonCancel).toBeDefined();
|
|
75
|
+
buttonCancel.props.onPress();
|
|
76
|
+
expect(mockGoBack).toHaveBeenCalled();
|
|
77
|
+
});
|
|
78
|
+
test('EditActionsList onPress save', async () => {
|
|
79
|
+
mock.onPut(API.AUTOMATE.ORDER_SCRIPT_ACTION(1)).reply(200);
|
|
80
|
+
await act(async () => {
|
|
81
|
+
tree = await create(wrapComponent());
|
|
82
|
+
});
|
|
83
|
+
const instance = tree.root;
|
|
84
|
+
const buttonSave = instance.find(
|
|
85
|
+
(el) =>
|
|
86
|
+
el.props.accessibilityLabel ===
|
|
87
|
+
AccessibilityLabel.BUTTON_SAVE_EDIT_ACTION_LIST &&
|
|
88
|
+
el.type === TouchableOpacity
|
|
89
|
+
);
|
|
90
|
+
expect(buttonSave).toBeDefined();
|
|
91
|
+
buttonSave.props.onPress();
|
|
92
|
+
expect(mock.history.put).toHaveLength(1);
|
|
93
|
+
});
|
|
94
|
+
test('EditActionsList onPress remove', async () => {
|
|
95
|
+
await act(async () => {
|
|
96
|
+
tree = await create(wrapComponent());
|
|
97
|
+
});
|
|
98
|
+
const instance = tree.root;
|
|
99
|
+
const buttonRemove = instance.find(
|
|
100
|
+
(el) =>
|
|
101
|
+
el.props.accessibilityLabel ===
|
|
102
|
+
AccessibilityLabel.BUTTON_REMOVE_EDIT_ACTION_LIST &&
|
|
103
|
+
el.type === TouchableOpacity
|
|
104
|
+
);
|
|
105
|
+
expect(buttonRemove).toBeDefined();
|
|
106
|
+
buttonRemove.props.onPress();
|
|
107
|
+
});
|
|
108
|
+
test('EditActionsList modal onPress remove', async () => {
|
|
109
|
+
await act(async () => {
|
|
110
|
+
tree = await create(wrapComponent());
|
|
111
|
+
});
|
|
112
|
+
const instance = tree.root;
|
|
113
|
+
const modalBottom = instance.findAllByType(ModalBottom);
|
|
114
|
+
modalBottom[0].props.onRemove();
|
|
115
|
+
|
|
116
|
+
mock.onDelete(API.AUTOMATE.DELETE_SCRIPT_ACTION(1, 1)).reply(200);
|
|
117
|
+
expect(mock.history.delete).toHaveLength(1);
|
|
118
|
+
modalBottom[0].props.onClose();
|
|
119
|
+
});
|
|
120
|
+
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useState, useCallback } from 'react';
|
|
1
|
+
import React, { memo, useState, useCallback } from 'react';
|
|
2
2
|
import { View, TouchableOpacity } from 'react-native';
|
|
3
3
|
import DraggableFlatList from 'react-native-draggable-flatlist';
|
|
4
4
|
import { useNavigation, useRoute } from '@react-navigation/native';
|
|
@@ -15,8 +15,9 @@ import Close from '../../../assets/images/Close.svg';
|
|
|
15
15
|
import { axiosDelete, axiosPut } from '../../utils/Apis/axios';
|
|
16
16
|
import { ModalBottom } from '../../commons/Modal';
|
|
17
17
|
import { ToastBottomHelper } from '../../utils/Utils';
|
|
18
|
+
import { AccessibilityLabel } from '../../configs/Constants';
|
|
18
19
|
|
|
19
|
-
const EditActionsList = () => {
|
|
20
|
+
const EditActionsList = memo(() => {
|
|
20
21
|
const t = useTranslations();
|
|
21
22
|
const { goBack } = useNavigation();
|
|
22
23
|
const { params = {} } = useRoute() || {};
|
|
@@ -115,6 +116,9 @@ const EditActionsList = () => {
|
|
|
115
116
|
</Text>
|
|
116
117
|
</View>
|
|
117
118
|
<TouchableOpacity
|
|
119
|
+
accessibilityLabel={
|
|
120
|
+
AccessibilityLabel.BUTTON_REMOVE_EDIT_ACTION_LIST
|
|
121
|
+
}
|
|
118
122
|
onPress={onPressRemove({
|
|
119
123
|
id: item?.id,
|
|
120
124
|
actionName: item?.sensor_name,
|
|
@@ -148,12 +152,18 @@ const EditActionsList = () => {
|
|
|
148
152
|
/>
|
|
149
153
|
</View>
|
|
150
154
|
<View style={styles.wrapBottom}>
|
|
151
|
-
<TouchableOpacity
|
|
155
|
+
<TouchableOpacity
|
|
156
|
+
onPress={onPressCancel}
|
|
157
|
+
accessibilityLabel={AccessibilityLabel.BUTTON_CANCEL_EDIT_ACTION_LIST}
|
|
158
|
+
>
|
|
152
159
|
<Text type="H4" hilight semibold>
|
|
153
160
|
{t('cancel')}
|
|
154
161
|
</Text>
|
|
155
162
|
</TouchableOpacity>
|
|
156
|
-
<TouchableOpacity
|
|
163
|
+
<TouchableOpacity
|
|
164
|
+
onPress={onPressSave}
|
|
165
|
+
accessibilityLabel={AccessibilityLabel.BUTTON_SAVE_EDIT_ACTION_LIST}
|
|
166
|
+
>
|
|
157
167
|
<Text type="H4" hilight semibold>
|
|
158
168
|
{t('save')}
|
|
159
169
|
</Text>
|
|
@@ -189,6 +199,6 @@ const EditActionsList = () => {
|
|
|
189
199
|
</ModalBottom>
|
|
190
200
|
</View>
|
|
191
201
|
);
|
|
192
|
-
};
|
|
202
|
+
});
|
|
193
203
|
|
|
194
204
|
export default EditActionsList;
|
|
@@ -64,14 +64,16 @@ describe('Test ScriptDetail', () => {
|
|
|
64
64
|
havePermission: true,
|
|
65
65
|
automate: {
|
|
66
66
|
author: 'Le Minh Tam',
|
|
67
|
-
condition: '<',
|
|
68
|
-
config: 'PM2.5 (Mr.Son Office)',
|
|
69
|
-
config_id: 201,
|
|
70
|
-
config_name: 'PM2.5 (Mr.Son Office)',
|
|
71
67
|
id: 1009,
|
|
72
|
-
sensor_id: 73,
|
|
73
68
|
type: 'value_change',
|
|
74
|
-
|
|
69
|
+
value_change: {
|
|
70
|
+
condition: '<',
|
|
71
|
+
config: 'PM2.5 (Mr.Son Office)',
|
|
72
|
+
config_id: 201,
|
|
73
|
+
config_name: 'PM2.5 (Mr.Son Office)',
|
|
74
|
+
sensor_id: 73,
|
|
75
|
+
value: 35,
|
|
76
|
+
},
|
|
75
77
|
script: {
|
|
76
78
|
id: 1,
|
|
77
79
|
},
|
|
@@ -295,13 +297,11 @@ describe('Test ScriptDetail', () => {
|
|
|
295
297
|
...route.params,
|
|
296
298
|
type: AUTOMATE_TYPE.VALUE_CHANGE,
|
|
297
299
|
automate: {
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
value: 3,
|
|
304
|
-
condition: '>',
|
|
300
|
+
value_change: {
|
|
301
|
+
config_name: 'Light Value',
|
|
302
|
+
value: 3,
|
|
303
|
+
condition: '>',
|
|
304
|
+
},
|
|
305
305
|
},
|
|
306
306
|
};
|
|
307
307
|
await act(() => {
|
|
@@ -312,6 +312,11 @@ describe('Test ScriptDetail', () => {
|
|
|
312
312
|
expect(itemAutomate.props.textCondition).toEqual(
|
|
313
313
|
'Light Value higher than 3'
|
|
314
314
|
);
|
|
315
|
+
|
|
316
|
+
await act(async () => {
|
|
317
|
+
itemAutomate.findByType(TouchableOpacity).props.onPress();
|
|
318
|
+
});
|
|
319
|
+
expect(mockNavigate).toBeCalled();
|
|
315
320
|
});
|
|
316
321
|
|
|
317
322
|
test('Test render textCondition value change =', async () => {
|
|
@@ -319,13 +324,7 @@ describe('Test ScriptDetail', () => {
|
|
|
319
324
|
...route.params,
|
|
320
325
|
type: AUTOMATE_TYPE.VALUE_CHANGE,
|
|
321
326
|
automate: {
|
|
322
|
-
|
|
323
|
-
date_repeat: '2022-01-02',
|
|
324
|
-
time_repeat: '09:10:00',
|
|
325
|
-
weekday_repeat: ['1', '2', '4', '6'],
|
|
326
|
-
config_name: 'Light Value',
|
|
327
|
-
value: 3,
|
|
328
|
-
condition: '=',
|
|
327
|
+
value_change: { config_name: 'Light Value', value: 3, condition: '=' },
|
|
329
328
|
},
|
|
330
329
|
};
|
|
331
330
|
await act(() => {
|
|
@@ -341,13 +340,11 @@ describe('Test ScriptDetail', () => {
|
|
|
341
340
|
...route.params,
|
|
342
341
|
type: AUTOMATE_TYPE.VALUE_CHANGE,
|
|
343
342
|
automate: {
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
value: 3,
|
|
350
|
-
condition: '<',
|
|
343
|
+
value_change: {
|
|
344
|
+
config_name: 'Light Value',
|
|
345
|
+
value: 3,
|
|
346
|
+
condition: '<',
|
|
347
|
+
},
|
|
351
348
|
},
|
|
352
349
|
};
|
|
353
350
|
await act(() => {
|
|
@@ -365,9 +362,11 @@ describe('Test ScriptDetail', () => {
|
|
|
365
362
|
...route.params,
|
|
366
363
|
type: AUTOMATE_TYPE.SCHEDULE,
|
|
367
364
|
automate: {
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
365
|
+
schedule: {
|
|
366
|
+
repeat: 'every_day',
|
|
367
|
+
date_repeat: '2022-01-02',
|
|
368
|
+
time_repeat: '19:00:00',
|
|
369
|
+
},
|
|
371
370
|
},
|
|
372
371
|
};
|
|
373
372
|
await act(() => {
|
|
@@ -383,10 +382,12 @@ describe('Test ScriptDetail', () => {
|
|
|
383
382
|
...route.params,
|
|
384
383
|
type: AUTOMATE_TYPE.SCHEDULE,
|
|
385
384
|
automate: {
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
385
|
+
schedule: {
|
|
386
|
+
repeat: 'every_week',
|
|
387
|
+
date_repeat: '2022-01-02',
|
|
388
|
+
time_repeat: '19:00:00',
|
|
389
|
+
weekday_repeat: ['1', '2', '4', '6'],
|
|
390
|
+
},
|
|
390
391
|
},
|
|
391
392
|
};
|
|
392
393
|
await act(() => {
|
|
@@ -362,17 +362,9 @@ const ScriptDetail = ({ route }) => {
|
|
|
362
362
|
const isHaveScriptActions = data?.length > 0;
|
|
363
363
|
|
|
364
364
|
const textCondition = useMemo(() => {
|
|
365
|
-
const {
|
|
366
|
-
condition,
|
|
367
|
-
config_name,
|
|
368
|
-
value,
|
|
369
|
-
repeat,
|
|
370
|
-
date_repeat,
|
|
371
|
-
time_repeat,
|
|
372
|
-
weekday_repeat,
|
|
373
|
-
sensor_type,
|
|
374
|
-
} = automate;
|
|
375
365
|
if (type === AUTOMATE_TYPE.VALUE_CHANGE) {
|
|
366
|
+
const { condition, config_name, value, sensor_type } =
|
|
367
|
+
automate?.value_change;
|
|
376
368
|
const stateConditionData = STATE_VALUE_SENSOR_TYPES.find(
|
|
377
369
|
(i) => i.type === sensor_type
|
|
378
370
|
);
|
|
@@ -388,6 +380,8 @@ const ScriptDetail = ({ route }) => {
|
|
|
388
380
|
}
|
|
389
381
|
return `${config_name} ${t(text)} ${isNumberValue ? value : ''}`;
|
|
390
382
|
} else if (type === AUTOMATE_TYPE.SCHEDULE) {
|
|
383
|
+
const { repeat, time_repeat, date_repeat, weekday_repeat } =
|
|
384
|
+
automate?.schedule;
|
|
391
385
|
const time =
|
|
392
386
|
time_repeat?.length >= 8
|
|
393
387
|
? time_repeat.substring(0, time_repeat?.length - 3)
|
|
@@ -424,6 +418,21 @@ const ScriptDetail = ({ route }) => {
|
|
|
424
418
|
const textWeekday = sortWeekday.map((item) => weekday[item]).join(', ');
|
|
425
419
|
return `${textWeekday} ${t('at')} ${time}`;
|
|
426
420
|
}
|
|
421
|
+
} else if (type === AUTOMATE_TYPE.EVENT) {
|
|
422
|
+
const { action, end_device_name, config_name, sensor_type, value } =
|
|
423
|
+
automate?.event;
|
|
424
|
+
let textEvent = '';
|
|
425
|
+
if (config_name) {
|
|
426
|
+
const stateConditionData = STATE_VALUE_SENSOR_TYPES.find(
|
|
427
|
+
(i) => i.type === sensor_type
|
|
428
|
+
);
|
|
429
|
+
textEvent = `${config_name} - ${t(
|
|
430
|
+
stateConditionData.stateValue[value]
|
|
431
|
+
)}`;
|
|
432
|
+
} else {
|
|
433
|
+
textEvent = `${end_device_name} - ${action}`;
|
|
434
|
+
}
|
|
435
|
+
return textEvent;
|
|
427
436
|
}
|
|
428
437
|
return null;
|
|
429
438
|
}, [t, automate, type]);
|
|
@@ -4,6 +4,12 @@ import SharedUnit from '../index';
|
|
|
4
4
|
import Modal from 'react-native-modal';
|
|
5
5
|
import { SCProvider } from '../../../context';
|
|
6
6
|
import { mockSCStore } from '../../../context/mockStore';
|
|
7
|
+
import { AccessibilityLabel } from '../../../configs/Constants';
|
|
8
|
+
import MockAdapter from 'axios-mock-adapter';
|
|
9
|
+
import api from '../../../utils/Apis/axios';
|
|
10
|
+
import { API } from '../../../configs';
|
|
11
|
+
|
|
12
|
+
const mock = new MockAdapter(api.axiosInstance);
|
|
7
13
|
|
|
8
14
|
const wrapComponent = () => (
|
|
9
15
|
<SCProvider initState={mockSCStore({})}>
|
|
@@ -16,9 +22,11 @@ jest.mock('react-redux', () => ({
|
|
|
16
22
|
useSelector: jest.fn(),
|
|
17
23
|
}));
|
|
18
24
|
|
|
25
|
+
const mockSetSharedUnits = jest.fn();
|
|
19
26
|
jest.mock('react', () => ({
|
|
20
27
|
...jest.requireActual('react'),
|
|
21
28
|
useLayoutEffect: jest.fn(),
|
|
29
|
+
useState: jest.fn((init) => [init, mockSetSharedUnits]),
|
|
22
30
|
}));
|
|
23
31
|
|
|
24
32
|
jest.mock('react-native-onesignal', () => {
|
|
@@ -37,4 +45,21 @@ describe('test SharedUnit', () => {
|
|
|
37
45
|
const modalShareds = instance.findAllByType(Modal);
|
|
38
46
|
expect(modalShareds[0]).not.toBeUndefined();
|
|
39
47
|
});
|
|
48
|
+
|
|
49
|
+
test('render touch item filter', async () => {
|
|
50
|
+
mock.onGet(API.UNIT.FILTER_SHARED_UNITS()).reply(200, [{}]);
|
|
51
|
+
|
|
52
|
+
await act(async () => {
|
|
53
|
+
tree = await create(wrapComponent());
|
|
54
|
+
});
|
|
55
|
+
const instance = tree.root;
|
|
56
|
+
const item = instance.findAll(
|
|
57
|
+
(el) =>
|
|
58
|
+
el.props.accessibilityLabel === AccessibilityLabel.FILTER_SHARING_ITEM
|
|
59
|
+
);
|
|
60
|
+
await act(async () => {
|
|
61
|
+
item[0].props.onPress();
|
|
62
|
+
});
|
|
63
|
+
expect(mockSetSharedUnits).toBeCalled();
|
|
64
|
+
});
|
|
40
65
|
});
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
useBoolean,
|
|
13
13
|
useBlockBackAndroid,
|
|
14
14
|
} from '../../hooks/Common';
|
|
15
|
+
import { AccessibilityLabel } from '../../configs/Constants';
|
|
15
16
|
|
|
16
17
|
import styles from './styles';
|
|
17
18
|
import TabHeader from './TabHeader';
|
|
@@ -185,6 +186,7 @@ const Shared = () => {
|
|
|
185
186
|
style={styles.row}
|
|
186
187
|
onPress={() => onFilter(item.filter, item.textFilter)}
|
|
187
188
|
key={`filter-${index}`}
|
|
189
|
+
accessibilityLabel={`${AccessibilityLabel.FILTER_SHARING_ITEM}`}
|
|
188
190
|
>
|
|
189
191
|
<Text
|
|
190
192
|
style={
|