@eohjsc/react-native-smart-city 0.5.5 → 0.5.7-rc1

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 (32) hide show
  1. package/package.json +2 -1
  2. package/src/commons/ActionGroup/OnOffTemplate/OnOffButtonTemplate.js +27 -3
  3. package/src/commons/ActionGroup/OnOffTemplate/index.js +47 -32
  4. package/src/commons/ActionGroup/__test__/index.test.js +40 -1
  5. package/src/commons/ActionTemplate/OnOffButtonAction.js +8 -2
  6. package/src/commons/ActionTemplate/OneButtonAction.js +5 -1
  7. package/src/configs/API.js +6 -0
  8. package/src/configs/AccessibilityLabel.js +7 -0
  9. package/src/configs/Constants.js +5 -0
  10. package/src/navigations/UnitStack.js +6 -0
  11. package/src/screens/Automate/AddNewAction/ChooseAction.js +1 -89
  12. package/src/screens/Automate/AddNewAction/NewActionWrapper.js +10 -2
  13. package/src/screens/Automate/AddNewAction/RenderActionItem.js +92 -0
  14. package/src/screens/Automate/AddNewAction/SetupConfigCondition.js +23 -11
  15. package/src/screens/Automate/AddNewAction/SetupScriptDelay.js +2 -2
  16. package/src/screens/Automate/AddNewAction/Styles/SetupSensorStyles.js +3 -3
  17. package/src/screens/Automate/AddNewAction/__test__/SetupConfigCondition.test.js +10 -17
  18. package/src/screens/Automate/EditActionsList/Styles/indexStyles.js +32 -6
  19. package/src/screens/Automate/EditActionsList/UpdateActionScript.js +141 -0
  20. package/src/screens/Automate/EditActionsList/UpdateDelayScript.js +94 -0
  21. package/src/screens/Automate/EditActionsList/UpdateNotifyScript.js +115 -0
  22. package/src/screens/Automate/EditActionsList/__tests__/UpdateActionScript.test.js +174 -0
  23. package/src/screens/Automate/EditActionsList/__tests__/UpdateDelayScript.test.js +119 -0
  24. package/src/screens/Automate/EditActionsList/__tests__/UpdateNotifyScript.test.js +138 -0
  25. package/src/screens/Automate/EditActionsList/__tests__/index.test.js +121 -50
  26. package/src/screens/Automate/EditActionsList/index.js +276 -167
  27. package/src/screens/Automate/ScriptDetail/index.js +11 -6
  28. package/src/screens/ChangePosition/index.js +1 -1
  29. package/src/screens/ChangePosition/styles.js +4 -0
  30. package/src/utils/I18n/translations/en.js +17 -4
  31. package/src/utils/I18n/translations/vi.js +17 -4
  32. package/src/utils/Route/index.js +2 -0
@@ -9,11 +9,12 @@ export default StyleSheet.create({
9
9
  conditionActive: {
10
10
  color: Colors.Black,
11
11
  },
12
+ inputValue: { marginBottom: 10 },
12
13
  numberInput: {
13
14
  borderRadius: 5,
14
15
  borderWidth: 1,
15
- borderColor: Colors.Black,
16
16
  height: 38,
17
+ marginTop: 10,
17
18
  },
18
19
  boxDevices: {
19
20
  flexWrap: 'wrap',
@@ -37,10 +38,9 @@ export default StyleSheet.create({
37
38
  },
38
39
  modalContent: {
39
40
  paddingHorizontal: 16,
40
- paddingTop: 16,
41
+ paddingVertical: 16,
41
42
  backgroundColor: Colors.White,
42
43
  width: '100%',
43
44
  borderRadius: 10,
44
- paddingBottom: 16,
45
45
  },
46
46
  });
@@ -121,15 +121,9 @@ describe('Test SetupConfigCondition', () => {
121
121
 
122
122
  const gridItems = instance.findAllByType(GridItem);
123
123
 
124
- expect(gridItems[0].findByType(Text).props.children).toEqual(
125
- 'Case 1 (2 >= "config name" < 1)'
126
- );
127
- expect(gridItems[1].findByType(Text).props.children).toEqual(
128
- 'Case 2 (2 >= "config name" < 1)'
129
- );
130
- expect(gridItems[2].findByType(Text).props.children).toEqual(
131
- 'Case 3 (2 >= "config name" < 1)'
132
- );
124
+ expect(gridItems[0].findByType(Text).props.children).toEqual('Case 1');
125
+ expect(gridItems[1].findByType(Text).props.children).toEqual('Case 2');
126
+ expect(gridItems[2].findByType(Text).props.children).toEqual('Case 3');
133
127
  });
134
128
 
135
129
  it('render boolean value evaluation', async () => {
@@ -152,12 +146,8 @@ describe('Test SetupConfigCondition', () => {
152
146
 
153
147
  const gridItems = instance.findAllByType(GridItem);
154
148
  expect(gridItems).toHaveLength(3);
155
- expect(gridItems[0].findByType(Text).props.children).toEqual(
156
- 'Case Off ("config name" = 0)'
157
- );
158
- expect(gridItems[1].findByType(Text).props.children).toEqual(
159
- 'Case On ("config name" = 1)'
160
- );
149
+ expect(gridItems[0].findByType(Text).props.children).toEqual('Case Off');
150
+ expect(gridItems[1].findByType(Text).props.children).toEqual('Case On');
161
151
  expect(gridItems[2].findByType(Text).props.children).toEqual(
162
152
  'Customize conditions'
163
153
  );
@@ -284,11 +274,14 @@ describe('Test SetupConfigCondition', () => {
284
274
  if (message === null) {
285
275
  expect(mockNavigate).toBeCalled();
286
276
  } else {
287
- expect(spyToastError).toBeCalledWith(message);
277
+ expect(spyToastError).toBeCalledWith(message, '', 3000);
288
278
  }
289
279
  };
290
280
 
291
281
  it('Test render when have input not number', async () => {
292
- await testConditionValue('abc', 'Please enter a number');
282
+ await testConditionValue(
283
+ 'abc',
284
+ 'Please enter a number and select a condition'
285
+ );
293
286
  });
294
287
  });
@@ -11,12 +11,12 @@ export default StyleSheet.create({
11
11
  },
12
12
  wrapContent: {
13
13
  flex: 1,
14
- paddingHorizontal: 16,
14
+ paddingHorizontal: 20,
15
15
  },
16
16
  wrapItem: {
17
17
  flexDirection: 'row',
18
18
  height: 100,
19
- marginBottom: 16,
19
+ marginBottom: 20,
20
20
  },
21
21
  isDragging: {
22
22
  borderBottomWidth: 1,
@@ -32,7 +32,6 @@ export default StyleSheet.create({
32
32
  borderColor: Colors.Gray4,
33
33
  },
34
34
  rightItem: {
35
- position: 'relative',
36
35
  flex: 1,
37
36
  marginLeft: 4,
38
37
  borderRadius: 4,
@@ -62,7 +61,7 @@ export default StyleSheet.create({
62
61
  flex: 1,
63
62
  },
64
63
  containerStyle: {
65
- marginVertical: 16,
64
+ marginVertical: 20,
66
65
  },
67
66
  wrapBottom: {
68
67
  height: 80,
@@ -96,7 +95,34 @@ export default StyleSheet.create({
96
95
  flexDirection: 'row',
97
96
  width: '45%',
98
97
  },
99
- paddingRight4: {
100
- paddingRight: 4,
98
+ popoverStyle: {
99
+ width: '100%',
100
+ backgroundColor: Colors.White,
101
+ borderRadius: 10,
102
+ },
103
+ modalHeader: {
104
+ paddingLeft: 16,
105
+ paddingRight: 16,
106
+ },
107
+ inputNumber: {
108
+ borderWidth: 1,
109
+ borderColor: Colors.Gray4,
110
+ borderStyle: 'solid',
111
+ borderRadius: 10,
112
+ marginBottom: 10,
113
+ },
114
+ textTitle: {
115
+ borderWidth: 1,
116
+ borderColor: Colors.Gray4,
117
+ borderStyle: 'solid',
118
+ borderRadius: 10,
119
+ },
120
+ textMessage: {
121
+ height: 200,
122
+ textAlignVertical: 'top',
123
+ borderWidth: 1,
124
+ borderColor: Colors.Gray4,
125
+ borderStyle: 'solid',
126
+ borderRadius: 10,
101
127
  },
102
128
  });
@@ -0,0 +1,141 @@
1
+ import React, { useCallback, useEffect, useMemo, useState } from 'react';
2
+ import { View } from 'react-native';
3
+ import { useNavigation } from '@react-navigation/native';
4
+
5
+ import NewActionWrapper from '../AddNewAction/NewActionWrapper';
6
+ import { useTranslations } from '../../../hooks/Common/useTranslations';
7
+ import { axiosGet, axiosPut } from '../../../utils/Apis/axios';
8
+ import { API } from '../../../configs';
9
+ import { ToastBottomHelper } from '../../../utils/Utils';
10
+ import Routes from '../../../utils/Route';
11
+ import RenderActionItem from '../AddNewAction/RenderActionItem';
12
+ import { useBackendPermission } from '../../../utils/Permission/backend';
13
+ import AccessibilityLabel from '../../../configs/AccessibilityLabel';
14
+
15
+ const UpdateActionScript = ({ route }) => {
16
+ const t = useTranslations();
17
+ const { navigate } = useNavigation();
18
+ const {
19
+ unitId,
20
+ device,
21
+ automateId,
22
+ numberActionAdded,
23
+ scriptItemId,
24
+ closeScreen,
25
+ } = route.params;
26
+ const permissions = useBackendPermission();
27
+ const { max_actions_per_automation } = permissions || {};
28
+ const [data, setData] = useState([]);
29
+ const [actions, setActions] = useState([]);
30
+ const [processing, setProcessing] = useState(false);
31
+
32
+ const numberActionCanAdd = useMemo(() => {
33
+ return max_actions_per_automation - numberActionAdded;
34
+ }, [max_actions_per_automation, numberActionAdded]);
35
+
36
+ const fetchData = useCallback(async () => {
37
+ const { success, data: automateData } = await axiosGet(
38
+ API.DEVICE.DISPLAY_ACTIONS(device.id)
39
+ );
40
+
41
+ success && setData(automateData);
42
+ }, [device.id]);
43
+
44
+ const onSave = useCallback(async () => {
45
+ if (actions.length > numberActionCanAdd) {
46
+ ToastBottomHelper.error(
47
+ `${t('you_can_only_add_more', { number: numberActionCanAdd })} ${t(
48
+ numberActionCanAdd > 1 ? 'actions' : 'action'
49
+ )}`,
50
+ null,
51
+ 3000
52
+ );
53
+ return;
54
+ }
55
+ setProcessing(true);
56
+ let list_action = [...actions];
57
+ list_action = list_action.map((item) => ({
58
+ action: item.action,
59
+ data: item.data,
60
+ }));
61
+ const { success } = await axiosPut(
62
+ API.AUTOMATE.UPDATE_SCRIPT_ACTION(automateId),
63
+ {
64
+ id: scriptItemId,
65
+ list_action,
66
+ unit: unitId,
67
+ }
68
+ );
69
+
70
+ if (success) {
71
+ const { success: success1, data: automateData } = await axiosGet(
72
+ API.AUTOMATE.SCRIPT_ITEMS(automateId)
73
+ );
74
+ setProcessing(false);
75
+ if (success1) {
76
+ ToastBottomHelper.success(t('update_successfully'));
77
+ navigate(Routes.EditActionsList, {
78
+ data: automateData.script_items,
79
+ id: automateId,
80
+ unitId: unitId,
81
+ });
82
+ }
83
+ } else {
84
+ setProcessing(false);
85
+ }
86
+ }, [
87
+ actions,
88
+ numberActionCanAdd,
89
+ automateId,
90
+ scriptItemId,
91
+ unitId,
92
+ t,
93
+ navigate,
94
+ ]);
95
+
96
+ const handleOnSelectAction = (action) => {
97
+ setActions((prevActions) => {
98
+ const index = prevActions.findIndex(
99
+ (item) => item.index === action.index
100
+ );
101
+ if (index !== -1) {
102
+ const newActions = [...prevActions];
103
+ newActions[index] = action;
104
+ return newActions;
105
+ } else {
106
+ return [...prevActions, action];
107
+ }
108
+ });
109
+ };
110
+
111
+ useEffect(() => {
112
+ fetchData();
113
+ }, [fetchData]);
114
+
115
+ return (
116
+ <NewActionWrapper
117
+ closeScreen={closeScreen}
118
+ canNext={actions.length}
119
+ onNext={onSave}
120
+ nextTitle={t('update_now')}
121
+ name={t('choose_action')}
122
+ accessibilityLabel={AccessibilityLabel.BUTTON_UPDATE_SCRIPT_ITEM}
123
+ showLoading={processing}
124
+ >
125
+ <View>
126
+ {!!data.length &&
127
+ data.map((item, index) => (
128
+ <RenderActionItem
129
+ key={`action_item_${index}`}
130
+ device={device}
131
+ item={item}
132
+ index={index}
133
+ handleOnSelectAction={handleOnSelectAction}
134
+ t={t}
135
+ />
136
+ ))}
137
+ </View>
138
+ </NewActionWrapper>
139
+ );
140
+ };
141
+ export default UpdateActionScript;
@@ -0,0 +1,94 @@
1
+ import React, { useCallback, useMemo, useState } from 'react';
2
+ import _TextInput from '../../../commons/Form/TextInput';
3
+ import styles from './Styles/indexStyles';
4
+ import AccessibilityLabel from '../../../configs/AccessibilityLabel';
5
+ import { View } from 'react-native';
6
+ import { axiosPut } from '../../../utils/Apis/axios';
7
+ import { API } from '../../../configs';
8
+ import { ToastBottomHelper } from '../../../utils/Utils';
9
+ import BottomButtonView from '../../../commons/BottomButtonView';
10
+
11
+ const UpdateDelayScript = ({
12
+ automateId,
13
+ scriptItemId,
14
+ delay_script,
15
+ t,
16
+ onClosePopup,
17
+ actionsList,
18
+ setActionList,
19
+ updateIndex,
20
+ setNeedRefresh,
21
+ }) => {
22
+ const { delay } = delay_script;
23
+ const [newValue, setNewValue] = useState(String(delay));
24
+
25
+ const onPressSave = useCallback(async () => {
26
+ const { success } = await axiosPut(
27
+ API.AUTOMATE.UPDATE_SCRIPT_DELAY(automateId),
28
+ {
29
+ id: scriptItemId,
30
+ delay: newValue,
31
+ }
32
+ );
33
+ if (success) {
34
+ actionsList[updateIndex].delay_script.delay = newValue;
35
+ setActionList(actionsList);
36
+ onClosePopup();
37
+ ToastBottomHelper.success(t('update_successfully'));
38
+ setNeedRefresh((prev) => !prev);
39
+ }
40
+ }, [
41
+ actionsList,
42
+ automateId,
43
+ newValue,
44
+ onClosePopup,
45
+ scriptItemId,
46
+ setActionList,
47
+ setNeedRefresh,
48
+ t,
49
+ updateIndex,
50
+ ]);
51
+
52
+ const onChangeDelay = (value) => {
53
+ setNewValue(value);
54
+ };
55
+ const canSave = useMemo(() => {
56
+ const value = parseInt(newValue, 10);
57
+ if (
58
+ !Number.isInteger(value) ||
59
+ value === delay ||
60
+ value <= 0 ||
61
+ value > 3600
62
+ ) {
63
+ return false;
64
+ }
65
+ return true;
66
+ }, [delay, newValue]);
67
+ return (
68
+ <>
69
+ <_TextInput
70
+ label={t('update_waiting_time')}
71
+ placeholder={t('maximum_3600_seconds')}
72
+ keyboardType="numeric"
73
+ textInputStyle={styles.inputNumber}
74
+ value={newValue}
75
+ onChange={onChangeDelay}
76
+ maxLength={4}
77
+ accessibilityLabel={AccessibilityLabel.AUTOMATE_INPUT_DELAY}
78
+ autoFocus
79
+ />
80
+
81
+ <View style={styles.wrapBottom}>
82
+ <BottomButtonView
83
+ disableKeyBoardAnimated
84
+ mainTitle={t('update_now')}
85
+ onPressMain={onPressSave}
86
+ typeMain={canSave ? 'primary' : 'disabled'}
87
+ accessibilityLabel={AccessibilityLabel.BUTTON_SAVE_EDIT_ACTION_LIST}
88
+ />
89
+ </View>
90
+ </>
91
+ );
92
+ };
93
+
94
+ export default UpdateDelayScript;
@@ -0,0 +1,115 @@
1
+ import React, { useCallback, useMemo, useState } from 'react';
2
+ import _TextInput from '../../../commons/Form/TextInput';
3
+ import styles from './Styles/indexStyles';
4
+ import AccessibilityLabel from '../../../configs/AccessibilityLabel';
5
+ import { Keyboard, TouchableWithoutFeedback, View } from 'react-native';
6
+ import { axiosPut } from '../../../utils/Apis/axios';
7
+ import { API } from '../../../configs';
8
+ import { ToastBottomHelper } from '../../../utils/Utils';
9
+ import BottomButtonView from '../../../commons/BottomButtonView';
10
+
11
+ const UpdateNotifyScript = ({
12
+ unitId,
13
+ automateId,
14
+ scriptItemId,
15
+ notify_script,
16
+ t,
17
+ onClosePopup,
18
+ actionsList,
19
+ setActionList,
20
+ updateIndex,
21
+ setNeedRefresh,
22
+ }) => {
23
+ const { title, message } = notify_script;
24
+ const [newValue, setNewValue] = useState({
25
+ newTitle: title,
26
+ newMessage: message,
27
+ });
28
+
29
+ const onPressSave = useCallback(async () => {
30
+ const { success } = await axiosPut(
31
+ API.AUTOMATE.UPDATE_SCRIPT_NOTIFY(automateId),
32
+ {
33
+ id: scriptItemId,
34
+ unit: unitId,
35
+ title: newValue.newTitle,
36
+ message: newValue.newMessage,
37
+ }
38
+ );
39
+ if (success) {
40
+ actionsList[updateIndex].notify_script = {
41
+ title: newValue.newTitle,
42
+ message: newValue.newMessage,
43
+ };
44
+ setActionList(actionsList);
45
+ onClosePopup();
46
+ ToastBottomHelper.success(t('update_successfully'));
47
+ setNeedRefresh((prev) => !prev);
48
+ }
49
+ }, [
50
+ actionsList,
51
+ automateId,
52
+ newValue.newMessage,
53
+ newValue.newTitle,
54
+ onClosePopup,
55
+ scriptItemId,
56
+ setActionList,
57
+ setNeedRefresh,
58
+ t,
59
+ unitId,
60
+ updateIndex,
61
+ ]);
62
+
63
+ const onChangeTitle = (value) => {
64
+ setNewValue((prev) => ({ ...prev, newTitle: value }));
65
+ };
66
+
67
+ const onChangeMessage = (value) => {
68
+ setNewValue((prev) => ({ ...prev, newMessage: value }));
69
+ };
70
+
71
+ const canSave = useMemo(() => {
72
+ const { newMessage, newTitle } = newValue;
73
+ if (newMessage === message && newTitle === title) {
74
+ return false;
75
+ }
76
+ return !!newMessage && !!newTitle;
77
+ }, [message, newValue, title]);
78
+
79
+ return (
80
+ <TouchableWithoutFeedback onPress={Keyboard.dismiss} accessible={false}>
81
+ <View>
82
+ <_TextInput
83
+ label={t('update_title_notification')}
84
+ placeholder={t('title_notification')}
85
+ onChange={onChangeTitle}
86
+ textInputStyle={styles.textTitle}
87
+ value={newValue.newTitle}
88
+ accessibilityLabel={AccessibilityLabel.AUTOMATE_TITLE_NOTIFY}
89
+ autoFocus
90
+ />
91
+ <_TextInput
92
+ label={t('update_message_notification')}
93
+ placeholder={t('message_notification')}
94
+ onChange={onChangeMessage}
95
+ textInputStyle={styles.textMessage}
96
+ value={newValue.newMessage}
97
+ accessibilityLabel={AccessibilityLabel.AUTOMATE_MESSAGE_NOTIFY}
98
+ multiline={true}
99
+ maxLength={255}
100
+ />
101
+ <View style={styles.wrapBottom}>
102
+ <BottomButtonView
103
+ mainTitle={t('update_now')}
104
+ onPressMain={onPressSave}
105
+ typeMain={canSave ? 'primary' : 'disabled'}
106
+ accessibilityLabel={AccessibilityLabel.BUTTON_SAVE_EDIT_ACTION_LIST}
107
+ disableKeyBoardAnimated
108
+ />
109
+ </View>
110
+ </View>
111
+ </TouchableWithoutFeedback>
112
+ );
113
+ };
114
+
115
+ export default UpdateNotifyScript;
@@ -0,0 +1,174 @@
1
+ import React from 'react';
2
+ import renderer, { act } from 'react-test-renderer';
3
+ import MockAdapter from 'axios-mock-adapter';
4
+
5
+ import { SCProvider } from '../../../../context';
6
+ import { mockSCStore } from '../../../../context/mockStore';
7
+ import API from '../../../../configs/API';
8
+ import { AccessibilityLabel } from '../../../../configs/Constants';
9
+
10
+ import api from '../../../../utils/Apis/axios';
11
+ import { ToastBottomHelper } from '../../../../utils/Utils';
12
+ import UpdateActionScript from '../UpdateActionScript';
13
+ import { TouchableOpacity } from 'react-native';
14
+ import { useRoute } from '@react-navigation/native';
15
+
16
+ const mock = new MockAdapter(api.axiosInstance);
17
+ const mockedNavigate = jest.fn();
18
+ const mockedDispatch = jest.fn();
19
+ const mockedGoBack = jest.fn();
20
+ const mockedPermission = jest.fn();
21
+
22
+ jest.mock('@react-navigation/native', () => {
23
+ return {
24
+ ...jest.requireActual('@react-navigation/native'),
25
+ useNavigation: () => ({
26
+ navigate: mockedNavigate,
27
+ dispatch: mockedDispatch,
28
+ goBack: mockedGoBack,
29
+ }),
30
+ useRoute: jest.fn(),
31
+ };
32
+ });
33
+ jest.mock('../../../../utils/Permission/backend', () => ({
34
+ useBackendPermission: () => ({
35
+ max_actions_per_automation: 1,
36
+ }),
37
+ }));
38
+
39
+ let response = [
40
+ {
41
+ template: 'on_off_button_action_template',
42
+ title: 'title',
43
+ configuration: {
44
+ text_on: 'text_on',
45
+ text_off: 'text_off',
46
+ action_on: 'action_on',
47
+ action_off: 'action_off',
48
+ },
49
+ },
50
+ {
51
+ template: 'one_button_action_template',
52
+ configuration: { text: 'text', action: 'action' },
53
+ },
54
+ ];
55
+ const wrapComponent = (route) => (
56
+ <SCProvider initState={mockSCStore({})}>
57
+ <UpdateActionScript route={route} />
58
+ </SCProvider>
59
+ );
60
+
61
+ describe('Test UpdateActionScript', () => {
62
+ let tree;
63
+ let route = {
64
+ params: {
65
+ unitId: 1,
66
+ automateId: 1,
67
+ scriptItemId: 1,
68
+ numberActionAdded: 0,
69
+ device: { id: 1 },
70
+ },
71
+ };
72
+ beforeEach(() => {
73
+ useRoute.mockReturnValue({
74
+ params: {},
75
+ });
76
+ mockedNavigate.mockClear();
77
+ mockedPermission.mockClear();
78
+ });
79
+
80
+ it('test update action script', async () => {
81
+ mock.onGet(API.DEVICE.DISPLAY_ACTIONS(1)).reply(200, response);
82
+ mock.onPut(API.AUTOMATE.UPDATE_SCRIPT_ACTION(1)).reply(200);
83
+ mock.onGet(API.AUTOMATE.SCRIPT_ITEMS(1)).reply(200, { script_items: [] });
84
+ await act(async () => {
85
+ tree = await renderer.create(wrapComponent(route));
86
+ });
87
+ const instance = tree.root;
88
+ const buttonOn = instance.findAll(
89
+ (el) =>
90
+ el.props.accessibilityLabel === AccessibilityLabel.ON_BUTTON &&
91
+ el.type === TouchableOpacity
92
+ );
93
+ await act(async () => {
94
+ buttonOn[0].props.onPress();
95
+ });
96
+ const buttonSave = instance.find(
97
+ (el) =>
98
+ el.props.accessibilityLabel ===
99
+ AccessibilityLabel.BUTTON_UPDATE_SCRIPT_ITEM
100
+ );
101
+ await act(async () => {
102
+ buttonSave.props.onNext();
103
+ });
104
+ expect(mockedNavigate).toHaveBeenCalled();
105
+ });
106
+
107
+ it('test update action script fail', async () => {
108
+ mock.onGet(API.DEVICE.DISPLAY_ACTIONS(1)).reply(200, response);
109
+ mock.onPut(API.AUTOMATE.UPDATE_SCRIPT_ACTION(1)).reply(400);
110
+ await act(async () => {
111
+ tree = await renderer.create(wrapComponent(route));
112
+ });
113
+ const instance = tree.root;
114
+ const buttonOn = instance.findAll(
115
+ (el) =>
116
+ el.props.accessibilityLabel === AccessibilityLabel.ON_BUTTON &&
117
+ el.type === TouchableOpacity
118
+ );
119
+ await act(async () => {
120
+ buttonOn[0].props.onPress();
121
+ });
122
+ const buttonSave = instance.find(
123
+ (el) =>
124
+ el.props.accessibilityLabel ===
125
+ AccessibilityLabel.BUTTON_UPDATE_SCRIPT_ITEM
126
+ );
127
+ await act(async () => {
128
+ buttonSave.props.onNext();
129
+ });
130
+ expect(mockedNavigate).not.toHaveBeenCalled();
131
+ });
132
+
133
+ it('test can not update because adding too many times allowed', async () => {
134
+ mock.onGet(API.DEVICE.DISPLAY_ACTIONS(1)).reply(200, response);
135
+ const spyToast = jest.spyOn(ToastBottomHelper, 'error');
136
+ await act(async () => {
137
+ tree = await renderer.create(wrapComponent(route));
138
+ });
139
+ const instance = tree.root;
140
+ const buttonOn = instance.findAll(
141
+ (el) =>
142
+ el.props.accessibilityLabel === AccessibilityLabel.ON_BUTTON &&
143
+ el.type === TouchableOpacity
144
+ );
145
+ await act(async () => {
146
+ buttonOn[0].props.onPress();
147
+ });
148
+ const buttonOff = instance.findAll(
149
+ (el) =>
150
+ el.props.accessibilityLabel === AccessibilityLabel.OFF_BUTTON &&
151
+ el.type === TouchableOpacity
152
+ );
153
+ await act(async () => {
154
+ buttonOff[0].props.onPress();
155
+ });
156
+ const buttonOne = instance.findAll(
157
+ (el) =>
158
+ el.props.accessibilityLabel === AccessibilityLabel.ONE_BUTTON &&
159
+ el.type === TouchableOpacity
160
+ );
161
+ await act(async () => {
162
+ buttonOne[0].props.onPress();
163
+ });
164
+ const buttonSave = instance.find(
165
+ (el) =>
166
+ el.props.accessibilityLabel ===
167
+ AccessibilityLabel.BUTTON_UPDATE_SCRIPT_ITEM
168
+ );
169
+ await act(async () => {
170
+ buttonSave.props.onNext();
171
+ });
172
+ expect(spyToast).toBeCalled();
173
+ });
174
+ });