@sap-ux/control-property-editor 0.2.0

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 (112) hide show
  1. package/.eslintignore +1 -0
  2. package/.eslintrc.js +16 -0
  3. package/CHANGELOG.md +7 -0
  4. package/LICENSE +201 -0
  5. package/README.md +16 -0
  6. package/dist/app.css +2 -0
  7. package/dist/app.css.map +7 -0
  8. package/dist/app.js +347 -0
  9. package/dist/app.js.map +7 -0
  10. package/esbuild.js +25 -0
  11. package/jest.config.js +20 -0
  12. package/package.json +68 -0
  13. package/src/App.scss +57 -0
  14. package/src/App.tsx +136 -0
  15. package/src/Workarounds.scss +79 -0
  16. package/src/actions.ts +3 -0
  17. package/src/components/AppLogo.module.scss +8 -0
  18. package/src/components/AppLogo.tsx +75 -0
  19. package/src/components/ChangeIndicator.tsx +80 -0
  20. package/src/components/Separator.tsx +32 -0
  21. package/src/components/ThemeSelectorCallout.scss +48 -0
  22. package/src/components/ThemeSelectorCallout.tsx +125 -0
  23. package/src/components/ToolBar.scss +39 -0
  24. package/src/components/ToolBar.tsx +26 -0
  25. package/src/components/index.ts +4 -0
  26. package/src/devices.ts +18 -0
  27. package/src/global.d.ts +4 -0
  28. package/src/i18n/i18n.json +68 -0
  29. package/src/i18n.ts +25 -0
  30. package/src/icons.tsx +198 -0
  31. package/src/index.css +1288 -0
  32. package/src/index.tsx +47 -0
  33. package/src/middleware.ts +54 -0
  34. package/src/panels/LeftPanel.scss +17 -0
  35. package/src/panels/LeftPanel.tsx +48 -0
  36. package/src/panels/changes/ChangeStack.module.scss +3 -0
  37. package/src/panels/changes/ChangeStack.tsx +219 -0
  38. package/src/panels/changes/ChangeStackHeader.tsx +43 -0
  39. package/src/panels/changes/ChangesPanel.module.scss +18 -0
  40. package/src/panels/changes/ChangesPanel.tsx +90 -0
  41. package/src/panels/changes/ControlGroup.module.scss +17 -0
  42. package/src/panels/changes/ControlGroup.tsx +61 -0
  43. package/src/panels/changes/PropertyChange.module.scss +24 -0
  44. package/src/panels/changes/PropertyChange.tsx +159 -0
  45. package/src/panels/changes/UnknownChange.module.scss +46 -0
  46. package/src/panels/changes/UnknownChange.tsx +96 -0
  47. package/src/panels/changes/index.tsx +3 -0
  48. package/src/panels/changes/utils.ts +36 -0
  49. package/src/panels/index.ts +2 -0
  50. package/src/panels/outline/Funnel.tsx +64 -0
  51. package/src/panels/outline/NoControlFound.tsx +45 -0
  52. package/src/panels/outline/OutlinePanel.scss +98 -0
  53. package/src/panels/outline/OutlinePanel.tsx +38 -0
  54. package/src/panels/outline/Tree.tsx +393 -0
  55. package/src/panels/outline/index.ts +1 -0
  56. package/src/panels/outline/utils.ts +154 -0
  57. package/src/panels/properties/Clipboard.tsx +44 -0
  58. package/src/panels/properties/DeviceSelector.tsx +40 -0
  59. package/src/panels/properties/DeviceToggle.tsx +39 -0
  60. package/src/panels/properties/DropdownEditor.tsx +80 -0
  61. package/src/panels/properties/Funnel.tsx +64 -0
  62. package/src/panels/properties/HeaderField.tsx +150 -0
  63. package/src/panels/properties/IconValueHelp.tsx +203 -0
  64. package/src/panels/properties/InputTypeSelector.tsx +20 -0
  65. package/src/panels/properties/InputTypeToggle.module.scss +4 -0
  66. package/src/panels/properties/InputTypeToggle.tsx +79 -0
  67. package/src/panels/properties/InputTypeWrapper.tsx +259 -0
  68. package/src/panels/properties/NoControlSelected.tsx +38 -0
  69. package/src/panels/properties/Properties.scss +102 -0
  70. package/src/panels/properties/PropertiesList.tsx +162 -0
  71. package/src/panels/properties/PropertiesPanel.tsx +30 -0
  72. package/src/panels/properties/PropertyDocumentation.module.scss +81 -0
  73. package/src/panels/properties/PropertyDocumentation.tsx +174 -0
  74. package/src/panels/properties/SapUiIcon.scss +109 -0
  75. package/src/panels/properties/StringEditor.tsx +122 -0
  76. package/src/panels/properties/ViewChanger.module.scss +5 -0
  77. package/src/panels/properties/ViewChanger.tsx +143 -0
  78. package/src/panels/properties/constants.ts +2 -0
  79. package/src/panels/properties/index.tsx +1 -0
  80. package/src/panels/properties/propertyValuesCache.ts +39 -0
  81. package/src/panels/properties/types.ts +49 -0
  82. package/src/slice.ts +216 -0
  83. package/src/store.ts +19 -0
  84. package/src/use-local-storage.ts +40 -0
  85. package/src/use-window-size.ts +39 -0
  86. package/src/variables.scss +2 -0
  87. package/test/unit/App.test.tsx +207 -0
  88. package/test/unit/appIndex.test.ts +23 -0
  89. package/test/unit/components/ChangeIndicator.test.tsx +120 -0
  90. package/test/unit/components/ThemeSelector.test.tsx +41 -0
  91. package/test/unit/middleware.test.ts +116 -0
  92. package/test/unit/panels/changes/ChangesPanel.test.tsx +261 -0
  93. package/test/unit/panels/changes/utils.test.ts +40 -0
  94. package/test/unit/panels/outline/OutlinePanel.test.tsx +353 -0
  95. package/test/unit/panels/outline/__snapshots__/utils.test.ts.snap +36 -0
  96. package/test/unit/panels/outline/utils.test.ts +83 -0
  97. package/test/unit/panels/properties/Clipboard.test.tsx +18 -0
  98. package/test/unit/panels/properties/DropdownEditor.test.tsx +62 -0
  99. package/test/unit/panels/properties/Funnel.test.tsx +34 -0
  100. package/test/unit/panels/properties/HeaderField.test.tsx +36 -0
  101. package/test/unit/panels/properties/IconValueHelp.test.tsx +60 -0
  102. package/test/unit/panels/properties/InputTypeToggle.test.tsx +126 -0
  103. package/test/unit/panels/properties/InputTypeWrapper.test.tsx +430 -0
  104. package/test/unit/panels/properties/PropertyDocumentation.test.tsx +131 -0
  105. package/test/unit/panels/properties/StringEditor.test.tsx +107 -0
  106. package/test/unit/panels/properties/ViewChanger.test.tsx +190 -0
  107. package/test/unit/panels/properties/propertyValuesCache.test.ts +23 -0
  108. package/test/unit/slice.test.ts +268 -0
  109. package/test/unit/utils.tsx +67 -0
  110. package/test/utils/utils.tsx +25 -0
  111. package/tsconfig.eslint.json +4 -0
  112. package/tsconfig.json +39 -0
@@ -0,0 +1,60 @@
1
+ import { screen, fireEvent } from '@testing-library/react';
2
+ import { render } from '../../utils';
3
+ import React from 'react';
4
+ import { initI18n } from '../../../../src/i18n';
5
+ import type { IconValueHelpProps } from '../../../../src/panels/properties/IconValueHelp';
6
+ import { IconValueHelp } from '../../../../src/panels/properties/IconValueHelp';
7
+
8
+ describe('IconValueHelp', () => {
9
+ const iconValueHelpProps: IconValueHelpProps = {
10
+ controlId: 'testControlId',
11
+ icons: [
12
+ {
13
+ content: 'testData1',
14
+ fontFamily: 'SAP-fontFamily',
15
+ name: 'testName1'
16
+ },
17
+ {
18
+ content: 'testData2',
19
+ fontFamily: 'SAP-fontFamily',
20
+ name: 'testName2'
21
+ },
22
+ {
23
+ content: 'testData3',
24
+ fontFamily: 'SAP-fontFamily',
25
+ name: 'testName3'
26
+ }
27
+ ],
28
+ isIcon: true,
29
+ propertyName: 'testProperty',
30
+ value: 'testValue',
31
+ disabled: false
32
+ };
33
+ beforeAll(() => {
34
+ initI18n();
35
+ });
36
+ test('initial load', () => {
37
+ render(<IconValueHelp {...iconValueHelpProps} />);
38
+ const button = screen.getByRole('button');
39
+ fireEvent.click(button);
40
+ const title = screen.getByRole('heading', { name: /select icon/i });
41
+ const searchBox = screen.getByRole('searchbox');
42
+ const okButton = screen.getByRole('button', { name: /ok/i });
43
+
44
+ expect(title).toBeInTheDocument();
45
+ expect(searchBox).toBeInTheDocument();
46
+ expect(screen.getAllByRole('row').length).toEqual(5);
47
+ fireEvent.change(screen.getByRole('searchbox'), { target: { value: 'testName1' } });
48
+ expect(screen.getAllByRole('row').length).toEqual(3);
49
+ fireEvent.change(screen.getByRole('searchbox'), { target: { value: '' } });
50
+ expect(okButton).toBeInTheDocument();
51
+
52
+ screen.getByText(/testname2/i).click();
53
+ okButton.click();
54
+
55
+ fireEvent.click(button);
56
+ const cancelButton = screen.getByRole('button', { name: /cancel/i });
57
+ expect(cancelButton).toBeInTheDocument();
58
+ cancelButton.click();
59
+ });
60
+ });
@@ -0,0 +1,126 @@
1
+ import { cleanup, fireEvent, screen } from '@testing-library/react';
2
+ import React from 'react';
3
+ import type {
4
+ BooleanControlProperty,
5
+ StringControlProperty,
6
+ StringControlPropertyWithOptions
7
+ } from '@sap-ux-private/control-property-editor-common';
8
+ import {
9
+ BOOLEAN_VALUE_TYPE,
10
+ CHECKBOX_EDITOR_TYPE,
11
+ DROPDOWN_EDITOR_TYPE,
12
+ INPUT_EDITOR_TYPE,
13
+ STRING_VALUE_TYPE
14
+ } from '@sap-ux-private/control-property-editor-common';
15
+ import { IconName, registerAppIcons } from '../../../../src/icons';
16
+ import { getValueForInputType, InputTypeToggle } from '../../../../src/panels/properties/InputTypeToggle';
17
+ import type { InputTypeToggleOptionProps } from '../../../../src/panels/properties/types';
18
+ import { InputType } from '../../../../src/panels/properties/types';
19
+ import { render } from '../../utils';
20
+ import * as slice from '../../../../src/slice';
21
+
22
+ describe('InputTypeToggle', () => {
23
+ const controlId = 'testControlId';
24
+
25
+ test('getValueForInputType', () => {
26
+ // Checkbox with value true, press on false and expression
27
+ const propCheckbox: BooleanControlProperty = {
28
+ editor: CHECKBOX_EDITOR_TYPE,
29
+ type: BOOLEAN_VALUE_TYPE,
30
+ value: true,
31
+ isEnabled: false,
32
+ name: 'testPropNameCheckbox',
33
+ readableName: 'testName'
34
+ };
35
+
36
+ let value = getValueForInputType(controlId, { ...propCheckbox }, InputType.booleanFalse);
37
+ expect(value).toMatchInlineSnapshot(`false`);
38
+
39
+ value = getValueForInputType(controlId, { ...propCheckbox }, InputType.expression);
40
+ expect(value).toMatchInlineSnapshot(`"{expression}"`);
41
+
42
+ // Dropdown Box
43
+ const propDropDown: StringControlPropertyWithOptions = {
44
+ editor: DROPDOWN_EDITOR_TYPE,
45
+ type: STRING_VALUE_TYPE,
46
+ value: 'option2',
47
+ isEnabled: true,
48
+ name: 'testPropNameDropDown',
49
+ options: [
50
+ { key: 'option1', text: 'option1' },
51
+ { key: 'option2', text: 'option2' }
52
+ ],
53
+ readableName: 'testName'
54
+ };
55
+
56
+ value = getValueForInputType(controlId, { ...propDropDown }, InputType.expression);
57
+ expect(value).toMatchInlineSnapshot(`"{expression}"`);
58
+
59
+ value = getValueForInputType(controlId, { ...propDropDown, value: '{expr}' }, InputType.enumMember);
60
+ expect(value).toMatchInlineSnapshot(`"option1"`);
61
+
62
+ // String Input
63
+ const propString: StringControlProperty = {
64
+ editor: INPUT_EDITOR_TYPE,
65
+ type: STRING_VALUE_TYPE,
66
+ value: 'myString',
67
+ isEnabled: true,
68
+ name: 'testPropNameString',
69
+ readableName: 'testName'
70
+ };
71
+
72
+ value = getValueForInputType(controlId, { ...propString }, InputType.expression);
73
+ expect(value).toMatchInlineSnapshot(`"{expression}"`);
74
+
75
+ value = getValueForInputType(controlId, { ...propString, value: '{expr}' }, InputType.string);
76
+ expect(value).toMatchInlineSnapshot(`""`);
77
+ });
78
+
79
+ test('render & click (for boolean value)', () => {
80
+ // arrange
81
+ const propertyName = 'testProperty';
82
+ const value = false;
83
+ const property: BooleanControlProperty = {
84
+ type: BOOLEAN_VALUE_TYPE,
85
+ editor: CHECKBOX_EDITOR_TYPE,
86
+ isEnabled: true,
87
+ name: propertyName,
88
+ value,
89
+ readableName: 'testName'
90
+ };
91
+ const inputTypeProps: InputTypeToggleOptionProps = {
92
+ inputType: InputType.booleanTrue,
93
+ tooltip: 'DummyTooltip',
94
+ iconName: IconName.boolTrue,
95
+ selected: typeof value === 'boolean' && value
96
+ };
97
+ const testId = `${propertyName}--InputTypeToggle--${InputType.booleanTrue}`;
98
+
99
+ registerAppIcons();
100
+ const spyGetChangePropertyAction = jest.spyOn(slice, 'changeProperty');
101
+
102
+ // act
103
+ render(
104
+ <InputTypeToggle
105
+ inputTypeProps={inputTypeProps}
106
+ property={property}
107
+ controlId={controlId}
108
+ toggleOptions={[]}
109
+ key={propertyName}
110
+ controlName="controlName"
111
+ />
112
+ );
113
+ fireEvent.click(screen.getByTestId(testId));
114
+ cleanup();
115
+
116
+ // assert
117
+ expect(spyGetChangePropertyAction).toHaveBeenCalledTimes(1);
118
+ expect(spyGetChangePropertyAction).toHaveBeenCalledWith(
119
+ expect.objectContaining({
120
+ controlId,
121
+ propertyName,
122
+ value: true
123
+ })
124
+ );
125
+ });
126
+ });
@@ -0,0 +1,430 @@
1
+ import { fireEvent, screen } from '@testing-library/react';
2
+ import React from 'react';
3
+ import type {
4
+ BooleanControlProperty,
5
+ StringControlProperty,
6
+ StringControlPropertyWithOptions
7
+ } from '@sap-ux-private/control-property-editor-common';
8
+ import {
9
+ BOOLEAN_VALUE_TYPE,
10
+ CHECKBOX_EDITOR_TYPE,
11
+ DROPDOWN_EDITOR_TYPE,
12
+ FLOAT_VALUE_TYPE,
13
+ INPUT_EDITOR_TYPE,
14
+ INTEGER_VALUE_TYPE,
15
+ STRING_VALUE_TYPE
16
+ } from '@sap-ux-private/control-property-editor-common';
17
+ import { initI18n } from '../../../../src/i18n';
18
+ import {
19
+ getInputTypeToggleOptions,
20
+ getDefaultInputType,
21
+ InputTypeWrapper
22
+ } from '../../../../src/panels/properties/InputTypeWrapper';
23
+ import type { InputTypeToggleOptionProps } from '../../../../src/panels/properties/types';
24
+ import { InputType } from '../../../../src/panels/properties/types';
25
+ import { render } from '../../utils';
26
+
27
+ describe('InputTypeWrapper', () => {
28
+ const controlId = 'testControlId';
29
+ beforeAll(() => {
30
+ initI18n();
31
+ });
32
+
33
+ test('getDefaultInputType', () => {
34
+ expect(getDefaultInputType(DROPDOWN_EDITOR_TYPE, STRING_VALUE_TYPE, 'option1')).toMatchInlineSnapshot(
35
+ `"enumMember"`
36
+ );
37
+ expect(getDefaultInputType(INPUT_EDITOR_TYPE, STRING_VALUE_TYPE, 'some string')).toMatchInlineSnapshot(
38
+ `"string"`
39
+ );
40
+ expect(getDefaultInputType(INPUT_EDITOR_TYPE, INTEGER_VALUE_TYPE, '10')).toMatchInlineSnapshot(`"number"`);
41
+ expect(getDefaultInputType(INPUT_EDITOR_TYPE, FLOAT_VALUE_TYPE, '10.2345')).toMatchInlineSnapshot(`"number"`);
42
+ expect(getDefaultInputType(CHECKBOX_EDITOR_TYPE, BOOLEAN_VALUE_TYPE, true)).toMatchInlineSnapshot(
43
+ `"booleanTrue"`
44
+ );
45
+ expect(getDefaultInputType(CHECKBOX_EDITOR_TYPE, BOOLEAN_VALUE_TYPE, '{expression}')).toMatchInlineSnapshot(
46
+ `"expression"`
47
+ );
48
+ });
49
+
50
+ test('getInputTypeToggleOptions', () => {
51
+ // Checkbox
52
+ const propCheckbox: BooleanControlProperty = {
53
+ editor: CHECKBOX_EDITOR_TYPE,
54
+ type: BOOLEAN_VALUE_TYPE,
55
+ value: true,
56
+ isEnabled: false,
57
+ name: 'testPropNameCheckbox',
58
+ readableName: 'Test Prop Name Checkbox'
59
+ };
60
+ expect(getInputTypeToggleOptions({ ...propCheckbox })).toMatchInlineSnapshot(`
61
+ Array [
62
+ Object {
63
+ "iconName": "boolTrue",
64
+ "inputType": "booleanTrue",
65
+ "selected": true,
66
+ "tooltip": "BOOLEAN_TYPE_TRUE",
67
+ },
68
+ Object {
69
+ "iconName": "boolFalse",
70
+ "inputType": "booleanFalse",
71
+ "selected": false,
72
+ "tooltip": "BOOLEAN_TYPE_FALSE",
73
+ },
74
+ Object {
75
+ "iconName": "expression",
76
+ "inputType": "expression",
77
+ "selected": false,
78
+ "tooltip": "EXPRESSION_TYPE",
79
+ },
80
+ ]
81
+ `);
82
+ expect(getInputTypeToggleOptions({ ...propCheckbox, value: false })).toMatchInlineSnapshot(`
83
+ Array [
84
+ Object {
85
+ "iconName": "boolTrue",
86
+ "inputType": "booleanTrue",
87
+ "selected": false,
88
+ "tooltip": "BOOLEAN_TYPE_TRUE",
89
+ },
90
+ Object {
91
+ "iconName": "boolFalse",
92
+ "inputType": "booleanFalse",
93
+ "selected": true,
94
+ "tooltip": "BOOLEAN_TYPE_FALSE",
95
+ },
96
+ Object {
97
+ "iconName": "expression",
98
+ "inputType": "expression",
99
+ "selected": false,
100
+ "tooltip": "EXPRESSION_TYPE",
101
+ },
102
+ ]
103
+ `);
104
+ expect(getInputTypeToggleOptions({ ...propCheckbox, value: '{myExpression}' })).toMatchInlineSnapshot(`
105
+ Array [
106
+ Object {
107
+ "iconName": "boolTrue",
108
+ "inputType": "booleanTrue",
109
+ "selected": false,
110
+ "tooltip": "BOOLEAN_TYPE_TRUE",
111
+ },
112
+ Object {
113
+ "iconName": "boolFalse",
114
+ "inputType": "booleanFalse",
115
+ "selected": false,
116
+ "tooltip": "BOOLEAN_TYPE_FALSE",
117
+ },
118
+ Object {
119
+ "iconName": "expression",
120
+ "inputType": "expression",
121
+ "selected": true,
122
+ "tooltip": "EXPRESSION_TYPE",
123
+ },
124
+ ]
125
+ `);
126
+ // String Input
127
+ const propString: StringControlProperty = {
128
+ editor: INPUT_EDITOR_TYPE,
129
+ type: STRING_VALUE_TYPE,
130
+ value: 'myString',
131
+ isEnabled: true,
132
+ name: 'testPropNameString',
133
+ readableName: 'Test Prop Name String'
134
+ };
135
+ expect(getInputTypeToggleOptions({ ...propString })).toMatchInlineSnapshot(`
136
+ Array [
137
+ Object {
138
+ "iconName": "string",
139
+ "inputType": "string",
140
+ "selected": true,
141
+ "tooltip": "STRING_TYPE",
142
+ },
143
+ Object {
144
+ "iconName": "expression",
145
+ "inputType": "expression",
146
+ "selected": false,
147
+ "tooltip": "EXPRESSION_TYPE",
148
+ },
149
+ ]
150
+ `);
151
+ expect(getInputTypeToggleOptions({ ...propString, value: '{myExpression}' })).toMatchInlineSnapshot(`
152
+ Array [
153
+ Object {
154
+ "iconName": "string",
155
+ "inputType": "string",
156
+ "selected": false,
157
+ "tooltip": "STRING_TYPE",
158
+ },
159
+ Object {
160
+ "iconName": "expression",
161
+ "inputType": "expression",
162
+ "selected": true,
163
+ "tooltip": "EXPRESSION_TYPE",
164
+ },
165
+ ]
166
+ `);
167
+ // Integer
168
+ expect(getInputTypeToggleOptions({ ...propString, type: INTEGER_VALUE_TYPE, value: '10' }))
169
+ .toMatchInlineSnapshot(`
170
+ Array [
171
+ Object {
172
+ "iconName": "number",
173
+ "inputType": "number",
174
+ "selected": true,
175
+ "tooltip": "INTEGER_TYPE",
176
+ },
177
+ Object {
178
+ "iconName": "expression",
179
+ "inputType": "expression",
180
+ "selected": false,
181
+ "tooltip": "EXPRESSION_TYPE",
182
+ },
183
+ ]
184
+ `);
185
+ expect(getInputTypeToggleOptions({ ...propString, type: INTEGER_VALUE_TYPE, value: '{myExpression}' }))
186
+ .toMatchInlineSnapshot(`
187
+ Array [
188
+ Object {
189
+ "iconName": "number",
190
+ "inputType": "number",
191
+ "selected": false,
192
+ "tooltip": "INTEGER_TYPE",
193
+ },
194
+ Object {
195
+ "iconName": "expression",
196
+ "inputType": "expression",
197
+ "selected": true,
198
+ "tooltip": "EXPRESSION_TYPE",
199
+ },
200
+ ]
201
+ `);
202
+ // Float
203
+ expect(getInputTypeToggleOptions({ ...propString, type: INTEGER_VALUE_TYPE, value: '10.23456' }))
204
+ .toMatchInlineSnapshot(`
205
+ Array [
206
+ Object {
207
+ "iconName": "number",
208
+ "inputType": "number",
209
+ "selected": true,
210
+ "tooltip": "INTEGER_TYPE",
211
+ },
212
+ Object {
213
+ "iconName": "expression",
214
+ "inputType": "expression",
215
+ "selected": false,
216
+ "tooltip": "EXPRESSION_TYPE",
217
+ },
218
+ ]
219
+ `);
220
+ expect(getInputTypeToggleOptions({ ...propString, type: INTEGER_VALUE_TYPE, value: '{myExpression}' }))
221
+ .toMatchInlineSnapshot(`
222
+ Array [
223
+ Object {
224
+ "iconName": "number",
225
+ "inputType": "number",
226
+ "selected": false,
227
+ "tooltip": "INTEGER_TYPE",
228
+ },
229
+ Object {
230
+ "iconName": "expression",
231
+ "inputType": "expression",
232
+ "selected": true,
233
+ "tooltip": "EXPRESSION_TYPE",
234
+ },
235
+ ]
236
+ `);
237
+ // Drop
238
+ const propDropDown: StringControlPropertyWithOptions = {
239
+ editor: DROPDOWN_EDITOR_TYPE,
240
+ type: STRING_VALUE_TYPE,
241
+ value: 'option2',
242
+ isEnabled: true,
243
+ name: 'testPropNameDropDown',
244
+ options: [
245
+ { key: 'option1', text: 'option1' },
246
+ { key: 'option2', text: 'option2' }
247
+ ],
248
+ readableName: 'Test Prop Name Drop Down'
249
+ };
250
+ expect(getInputTypeToggleOptions({ ...propDropDown })).toMatchInlineSnapshot(`
251
+ Array [
252
+ Object {
253
+ "iconName": "dropdown",
254
+ "inputType": "enumMember",
255
+ "selected": true,
256
+ "tooltip": "ENUM_TYPE",
257
+ },
258
+ Object {
259
+ "iconName": "expression",
260
+ "inputType": "expression",
261
+ "selected": false,
262
+ "tooltip": "EXPRESSION_TYPE",
263
+ },
264
+ ]
265
+ `);
266
+ expect(getInputTypeToggleOptions({ ...propDropDown, value: '{myExpression}' })).toMatchInlineSnapshot(`
267
+ Array [
268
+ Object {
269
+ "iconName": "dropdown",
270
+ "inputType": "enumMember",
271
+ "selected": false,
272
+ "tooltip": "ENUM_TYPE",
273
+ },
274
+ Object {
275
+ "iconName": "expression",
276
+ "inputType": "expression",
277
+ "selected": true,
278
+ "tooltip": "EXPRESSION_TYPE",
279
+ },
280
+ ]
281
+ `);
282
+ expect(getInputTypeToggleOptions({ ...propDropDown, value: '{myIncompleteExpression' })).toMatchInlineSnapshot(`
283
+ Array [
284
+ Object {
285
+ "iconName": "dropdown",
286
+ "inputType": "enumMember",
287
+ "selected": false,
288
+ "tooltip": "ENUM_TYPE",
289
+ },
290
+ Object {
291
+ "iconName": "expression",
292
+ "inputType": "expression",
293
+ "selected": false,
294
+ "tooltip": "EXPRESSION_TYPE",
295
+ },
296
+ ]
297
+ `);
298
+ });
299
+
300
+ test('render (for boolean value)', () => {
301
+ const value = true;
302
+ const propertyName = 'testProperty';
303
+ const property: BooleanControlProperty = {
304
+ type: BOOLEAN_VALUE_TYPE,
305
+ editor: CHECKBOX_EDITOR_TYPE,
306
+ isEnabled: false,
307
+ name: propertyName,
308
+ readableName: 'Test Property',
309
+ value,
310
+ documentation: {
311
+ defaultValue: 'testDefault',
312
+ description: 'Test doc',
313
+ propertyName: propertyName,
314
+ type: BOOLEAN_VALUE_TYPE,
315
+ propertyType: 'testingTypeText'
316
+ }
317
+ };
318
+ const toggleOptions: InputTypeToggleOptionProps[] = getInputTypeToggleOptions(property);
319
+ render(
320
+ <InputTypeWrapper
321
+ property={property}
322
+ controlId={controlId}
323
+ key={propertyName}
324
+ toggleOptions={toggleOptions}
325
+ controlName="controlName"
326
+ />
327
+ );
328
+
329
+ const label = screen.getByTestId(`${propertyName}--Label`);
330
+ expect(label).toBeInTheDocument();
331
+
332
+ const inputTypeTrue = screen.getByTestId(`${propertyName}--InputTypeToggle--${InputType.booleanTrue}`);
333
+ expect(inputTypeTrue).toBeInTheDocument();
334
+ const inputTypeFalse = screen.getByTestId(`${propertyName}--InputTypeToggle--${InputType.booleanFalse}`);
335
+ expect(inputTypeFalse).toBeInTheDocument();
336
+ const inputTypeExpression = screen.getByTestId(`${propertyName}--InputTypeToggle--${InputType.expression}`);
337
+ expect(inputTypeExpression).toBeInTheDocument();
338
+
339
+ // no expression input since value is boolean
340
+ let exception: Error | null = null;
341
+ try {
342
+ screen.getByTestId(`${propertyName}--StringEditor`);
343
+ } catch (e) {
344
+ exception = e as Error;
345
+ }
346
+ expect(exception).toBeTruthy();
347
+ });
348
+
349
+ test('delete property changes', async () => {
350
+ const propertyName = 'testProperty';
351
+ const property: StringControlProperty = {
352
+ editor: INPUT_EDITOR_TYPE,
353
+ type: STRING_VALUE_TYPE,
354
+ value: 'myString',
355
+ isEnabled: true,
356
+ name: propertyName,
357
+ readableName: 'Test Prop Name String',
358
+ documentation: {
359
+ defaultValue: 'testDefault',
360
+ description: 'Test doc',
361
+ propertyName: propertyName,
362
+ type: 'string',
363
+ propertyType: 'testingTypeText'
364
+ }
365
+ };
366
+ const toggleOptions: InputTypeToggleOptionProps[] = getInputTypeToggleOptions(property);
367
+ const { dispatch } = render(
368
+ <InputTypeWrapper
369
+ property={property}
370
+ controlId={controlId}
371
+ key={propertyName}
372
+ toggleOptions={toggleOptions}
373
+ controlName="controlName"
374
+ />,
375
+ {
376
+ initialState: {
377
+ selectedControl: {
378
+ id: 'control1'
379
+ } as any,
380
+ changes: {
381
+ stack: [],
382
+ controls: {
383
+ control1: {
384
+ pending: 0,
385
+ saved: 1,
386
+ properties: {
387
+ testProperty: {
388
+ saved: 1,
389
+ pending: 0,
390
+ lastSavedChange: {
391
+ propertyName,
392
+ value: 'old value',
393
+ type: 'saved',
394
+ fileName: 'file',
395
+ timestamp: 123,
396
+ controlId: 'control1'
397
+ }
398
+ }
399
+ }
400
+ }
401
+ }
402
+ }
403
+ } as any
404
+ }
405
+ );
406
+
407
+ const label = screen.getByTestId(`${propertyName}--Label`);
408
+
409
+ fireEvent.mouseOver(label);
410
+
411
+ const deleteButton = await screen.findByRole('button', { name: 'Delete all changes for this property' });
412
+
413
+ deleteButton.click();
414
+
415
+ expect(
416
+ screen.getByText(
417
+ /Are you sure you want to delete all changes for this property\? This action cannot be undone\./i
418
+ )
419
+ ).toBeInTheDocument();
420
+
421
+ const confirmButton = screen.getByRole('button', { name: /^Delete$/i });
422
+ // const confirmButton = screen.getByText(/Delete/i);
423
+ confirmButton.click();
424
+
425
+ expect(dispatch).toHaveBeenCalledWith({
426
+ type: '[ext] delete-property-changes',
427
+ payload: { controlId: 'control1', propertyName }
428
+ });
429
+ });
430
+ });