@lumx/react 3.3.1-alpha.0 → 3.3.1
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/_internal/ClickAwayProvider.js.map +1 -1
- package/_internal/types.d.ts +0 -2
- package/index.d.ts +2 -0
- package/index.js +347 -75
- package/index.js.map +1 -1
- package/package.json +23 -19
- package/src/components/autocomplete/Autocomplete.test.tsx +55 -142
- package/src/components/autocomplete/AutocompleteMultiple.test.tsx +37 -75
- package/src/components/autocomplete/__mockData__/index.ts +6 -1
- package/src/components/badge/Badge.test.tsx +20 -64
- package/src/components/button/Button.test.tsx +44 -121
- package/src/components/button/ButtonGroup.test.tsx +16 -39
- package/src/components/button/IconButton.stories.tsx +7 -0
- package/src/components/button/IconButton.test.tsx +37 -78
- package/src/components/button/IconButton.tsx +8 -1
- package/src/components/checkbox/Checkbox.test.tsx +62 -67
- package/src/components/chip/Chip.test.tsx +89 -139
- package/src/components/chip/ChipGroup.test.tsx +27 -10
- package/src/components/date-picker/DatePicker.test.tsx +15 -23
- package/src/components/date-picker/DatePickerControlled.test.tsx +24 -20
- package/src/components/date-picker/DatePickerField.test.tsx +43 -27
- package/src/components/dialog/Dialog.test.tsx +36 -35
- package/src/components/divider/Divider.test.tsx +23 -69
- package/src/components/dropdown/Dropdown.test.tsx +30 -61
- package/src/components/expansion-panel/ExpansionPanel.test.tsx +12 -8
- package/src/components/flag/Flag.test.tsx +28 -53
- package/src/components/generic-block/GenericBlock.test.tsx +93 -89
- package/src/components/grid-column/GridColumn.stories.tsx +3 -3
- package/src/components/icon/Icon.test.tsx +80 -64
- package/src/components/index.ts +0 -2
- package/src/components/inline-list/InlineList.test.tsx +30 -17
- package/src/components/input-helper/InputHelper.test.tsx +21 -81
- package/src/components/input-label/InputLabel.test.tsx +19 -61
- package/src/components/lightbox/Lightbox.test.tsx +3 -2
- package/src/components/link/Link.test.tsx +47 -31
- package/src/components/link-preview/LinkPreview.test.tsx +51 -51
- package/src/components/message/Message.test.tsx +31 -52
- package/src/components/mosaic/Mosaic.test.tsx +56 -72
- package/src/components/notification/Notification.test.tsx +51 -82
- package/src/components/popover/Popover.tsx +7 -9
- package/src/components/progress-tracker/ProgressTracker.test.tsx +20 -33
- package/src/components/progress-tracker/ProgressTrackerProvider.test.tsx +61 -36
- package/src/components/progress-tracker/ProgressTrackerStep.test.tsx +19 -109
- package/src/components/progress-tracker/ProgressTrackerStepPanel.test.tsx +21 -58
- package/src/components/progress-tracker/ProgressTrackerStepPanel.tsx +1 -1
- package/src/components/radio-button/RadioButton.test.tsx +78 -92
- package/src/components/radio-button/RadioGroup.test.tsx +13 -59
- package/src/components/select/Select.test.tsx +115 -284
- package/src/components/select/SelectMultiple.stories.tsx +105 -2
- package/src/components/select/SelectMultiple.test.tsx +126 -322
- package/src/components/select/WithSelectContext.tsx +10 -4
- package/src/components/side-navigation/SideNavigation.test.tsx +22 -35
- package/src/components/side-navigation/SideNavigationItem.test.tsx +72 -139
- package/src/components/switch/Switch.test.tsx +70 -149
- package/src/components/table/Table.test.tsx +2 -0
- package/src/components/table/TableBody.test.tsx +18 -8
- package/src/components/table/TableCell.test.tsx +34 -9
- package/src/components/table/TableHeader.test.tsx +18 -8
- package/src/components/table/TableRow.test.tsx +28 -8
- package/src/components/tabs/Tab.test.tsx +27 -96
- package/src/components/tabs/TabList.test.tsx +21 -56
- package/src/components/tabs/TabPanel.test.tsx +20 -55
- package/src/components/tabs/TabPanel.tsx +1 -1
- package/src/components/tabs/TabProvider.test.tsx +158 -37
- package/src/components/tabs/test-utils.ts +39 -0
- package/src/components/text-field/TextField.stories.tsx +14 -5
- package/src/components/text-field/TextField.test.tsx +54 -8
- package/src/components/text-field/TextField.tsx +49 -5
- package/src/components/tooltip/Tooltip.test.tsx +134 -75
- package/src/components/tooltip/useInjectTooltipRef.tsx +9 -2
- package/src/components/uploader/Uploader.test.tsx +60 -48
- package/src/components/user-block/UserBlock.test.tsx +69 -13
- package/src/hooks/useFocusTrap.ts +2 -2
- package/src/testing/utils/commonTestsSuiteRTL.ts +18 -8
- package/src/testing/utils/index.ts +0 -1
- package/src/utils/flattenChildren.ts +5 -0
- package/src/components/autocomplete/__snapshots__/Autocomplete.test.tsx.snap +0 -213
- package/src/components/autocomplete/__snapshots__/AutocompleteMultiple.test.tsx.snap +0 -88
- package/src/components/badge/__snapshots__/Badge.test.tsx.snap +0 -11
- package/src/components/button/ButtonRoot.test.tsx +0 -203
- package/src/components/button/__snapshots__/Button.test.tsx.snap +0 -96
- package/src/components/button/__snapshots__/ButtonGroup.test.tsx.snap +0 -22
- package/src/components/button/__snapshots__/ButtonRoot.test.tsx.snap +0 -160
- package/src/components/button/__snapshots__/IconButton.test.tsx.snap +0 -83
- package/src/components/checkbox/__snapshots__/Checkbox.test.tsx.snap +0 -141
- package/src/components/chip/__snapshots__/Chip.test.tsx.snap +0 -12
- package/src/components/chip/__snapshots__/ChipGroup.test.tsx.snap +0 -29
- package/src/components/date-picker/__snapshots__/DatePicker.test.tsx.snap +0 -22
- package/src/components/date-picker/__snapshots__/DatePickerControlled.test.tsx.snap +0 -597
- package/src/components/date-picker/__snapshots__/DatePickerField.test.tsx.snap +0 -43
- package/src/components/divider/__snapshots__/Divider.test.tsx.snap +0 -9
- package/src/components/dropdown/__snapshots__/Dropdown.test.tsx.snap +0 -35
- package/src/components/icon/__snapshots__/Icon.test.tsx.snap +0 -49
- package/src/components/input-helper/__snapshots__/InputHelper.test.tsx.snap +0 -9
- package/src/components/input-label/__snapshots__/InputLabel.test.tsx.snap +0 -10
- package/src/components/link/__snapshots__/Link.test.tsx.snap +0 -29
- package/src/components/message/__snapshots__/Message.test.tsx.snap +0 -15
- package/src/components/notification/__snapshots__/Notification.test.tsx.snap +0 -34
- package/src/components/progress-tracker/__snapshots__/ProgressTracker.test.tsx.snap +0 -41
- package/src/components/progress-tracker/__snapshots__/ProgressTrackerStep.test.tsx.snap +0 -141
- package/src/components/progress-tracker/__snapshots__/ProgressTrackerStepPanel.test.tsx.snap +0 -25
- package/src/components/radio-button/__snapshots__/RadioButton.test.tsx.snap +0 -113
- package/src/components/radio-button/__snapshots__/RadioGroup.test.tsx.snap +0 -26
- package/src/components/select/__snapshots__/Select.test.tsx.snap +0 -43
- package/src/components/select/__snapshots__/SelectMultiple.test.tsx.snap +0 -87
- package/src/components/side-navigation/__snapshots__/SideNavigation.test.tsx.snap +0 -7
- package/src/components/side-navigation/__snapshots__/SideNavigationItem.test.tsx.snap +0 -30
- package/src/components/switch/__snapshots__/Switch.test.tsx.snap +0 -179
- package/src/components/tabs/__snapshots__/Tab.test.tsx.snap +0 -62
- package/src/components/tabs/__snapshots__/TabList.test.tsx.snap +0 -22
- package/src/components/tabs/__snapshots__/TabPanel.test.tsx.snap +0 -25
- package/src/components/tabs/test.mocks.ts +0 -33
- package/src/components/text-field/__snapshots__/TextField.test.tsx.snap +0 -42
- package/src/components/tooltip/__snapshots__/Tooltip.test.tsx.snap +0 -233
- package/src/components/uploader/__snapshots__/Uploader.test.tsx.snap +0 -14
- package/src/testing/utils/commonTestsSuite.ts +0 -71
- package/src/utils/flattenChildren.test.tsx +0 -58
|
@@ -1,405 +1,209 @@
|
|
|
1
|
-
import React
|
|
1
|
+
import React from 'react';
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
import 'jest-enzyme';
|
|
5
|
-
|
|
6
|
-
import { mdiCloseCircle, mdiMenuDown } from '@lumx/icons';
|
|
7
|
-
import { Kind, Theme } from '@lumx/react/components';
|
|
3
|
+
import { Theme } from '@lumx/react/components';
|
|
8
4
|
import { Chip } from '@lumx/react/components/chip/Chip';
|
|
9
5
|
import { Dropdown } from '@lumx/react/components/dropdown/Dropdown';
|
|
10
|
-
import {
|
|
6
|
+
import { commonTestsSuiteRTL } from '@lumx/react/testing/utils';
|
|
7
|
+
import { render, within } from '@testing-library/react';
|
|
8
|
+
import {
|
|
9
|
+
getAllByClassName,
|
|
10
|
+
getByClassName,
|
|
11
|
+
queryAllByClassName,
|
|
12
|
+
queryByClassName,
|
|
13
|
+
} from '@lumx/react/testing/utils/queries';
|
|
14
|
+
import userEvent from '@testing-library/user-event';
|
|
11
15
|
|
|
12
|
-
import { commonTestsSuite, Wrapper } from '@lumx/react/testing/utils';
|
|
13
|
-
import { getBasicClass } from '@lumx/react/utils/className';
|
|
14
16
|
import { SelectMultiple, SelectMultipleProps } from './SelectMultiple';
|
|
15
|
-
import { DEFAULT_PROPS } from './WithSelectContext';
|
|
16
17
|
import { SelectVariant } from './constants';
|
|
17
18
|
|
|
18
19
|
const CLASSNAME = SelectMultiple.className as string;
|
|
19
20
|
|
|
20
21
|
jest.mock('uid', () => ({ uid: () => 'uid' }));
|
|
21
22
|
|
|
22
|
-
type SetupProps = Partial<SelectMultipleProps>;
|
|
23
|
-
|
|
24
23
|
/**
|
|
25
24
|
* Mounts the component and returns common DOM elements / data needed in multiple tests further down.
|
|
26
25
|
*/
|
|
27
|
-
const setup = (props:
|
|
26
|
+
const setup = (props: Partial<SelectMultipleProps> = {}) => {
|
|
28
27
|
const setupProps: SelectMultipleProps = {
|
|
29
28
|
children: <span>Select Component</span>,
|
|
30
29
|
value: [],
|
|
31
30
|
...props,
|
|
32
31
|
};
|
|
33
|
-
|
|
34
|
-
const
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
.findWhere(
|
|
42
|
-
(n: ShallowWrapper | ReactWrapper) => n.name() === 'InputHelper' && n.prop('kind') === Kind.error,
|
|
43
|
-
)
|
|
44
|
-
.first(),
|
|
45
|
-
helper: wrapper.findWhere(
|
|
46
|
-
(n: ShallowWrapper | ReactWrapper) => n.name() === 'InputHelper' && n.prop('kind') === Kind.info,
|
|
47
|
-
),
|
|
48
|
-
input: wrapper.find('#select-uid:not(SelectMultipleField)').first(),
|
|
49
|
-
chip: wrapper.find('Chip'),
|
|
50
|
-
inputWrapper: wrapper.find('.lumx-select__wrapper'),
|
|
51
|
-
props,
|
|
52
|
-
wrapper,
|
|
53
|
-
};
|
|
32
|
+
render(<SelectMultiple {...setupProps} />);
|
|
33
|
+
const select = getByClassName(document.body, CLASSNAME);
|
|
34
|
+
const getDropdown = () => queryByClassName(document.body, Dropdown.className as string);
|
|
35
|
+
const helpers = queryAllByClassName(select, `${CLASSNAME}__helper`);
|
|
36
|
+
const inputWrapper = queryByClassName(select, `${CLASSNAME}__wrapper`);
|
|
37
|
+
const chip = !inputWrapper ? queryByClassName(select, Chip.className as string) : null;
|
|
38
|
+
const valueChips = queryByClassName(select, `${CLASSNAME}__chips`);
|
|
39
|
+
return { props, select, getDropdown, helpers, inputWrapper, chip, valueChips };
|
|
54
40
|
};
|
|
55
41
|
|
|
56
42
|
describe(`<SelectMultiple>`, () => {
|
|
57
|
-
// 1. Test render via snapshot (default states of component).
|
|
58
|
-
describe('Snapshots and structure', () => {
|
|
59
|
-
it('should render defaults', () => {
|
|
60
|
-
const { wrapper } = setup();
|
|
61
|
-
expect(wrapper).toMatchSnapshot();
|
|
62
|
-
expect(wrapper).toExist();
|
|
63
|
-
expect(wrapper).toHaveClassName(CLASSNAME);
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
it('should render chips', () => {
|
|
67
|
-
const { wrapper } = setup({
|
|
68
|
-
variant: SelectVariant.chip,
|
|
69
|
-
});
|
|
70
|
-
expect(wrapper).toMatchSnapshot();
|
|
71
|
-
});
|
|
72
|
-
});
|
|
73
|
-
|
|
74
43
|
describe('Props', () => {
|
|
75
44
|
it('should have default classNames', () => {
|
|
76
|
-
const {
|
|
77
|
-
wrapper.update();
|
|
45
|
+
const { select, inputWrapper, valueChips, chip } = setup();
|
|
78
46
|
|
|
79
|
-
expect(
|
|
80
|
-
expect(
|
|
81
|
-
|
|
47
|
+
expect(inputWrapper).toBeInTheDocument();
|
|
48
|
+
expect(valueChips).toBeEmptyDOMElement();
|
|
49
|
+
expect(chip).not.toBeInTheDocument();
|
|
50
|
+
expect(select.className).toMatchInlineSnapshot(
|
|
51
|
+
`"lumx-select lumx-select--has-multiple lumx-select lumx-select--is-empty lumx-select--theme-light"`,
|
|
82
52
|
);
|
|
83
|
-
expect(container).toHaveClassName(getBasicClass({ prefix: CLASSNAME, type: 'isEmpty', value: true }));
|
|
84
53
|
});
|
|
85
54
|
|
|
86
55
|
it('should use the given `theme`', () => {
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
[testedProp]: Theme.dark,
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
const { container } = setup(modifiedProps);
|
|
93
|
-
|
|
94
|
-
expect(container).toHaveClassName(
|
|
95
|
-
getBasicClass({ prefix: CLASSNAME, type: testedProp, value: modifiedProps[testedProp] }),
|
|
96
|
-
);
|
|
97
|
-
expect(container).not.toHaveClassName(
|
|
98
|
-
getBasicClass({ prefix: CLASSNAME, type: testedProp, value: DEFAULT_PROPS.theme }),
|
|
99
|
-
);
|
|
56
|
+
const { select } = setup({ theme: Theme.dark });
|
|
57
|
+
expect(select).toHaveClass(`${CLASSNAME}--theme-dark`);
|
|
100
58
|
});
|
|
101
59
|
|
|
102
60
|
it('should use the given `isValid`', () => {
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
[testedProp]: true,
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
const { container } = setup(modifiedProps);
|
|
109
|
-
|
|
110
|
-
expect(container).toHaveClassName(
|
|
111
|
-
getBasicClass({ prefix: CLASSNAME, type: testedProp, value: modifiedProps[testedProp] }),
|
|
112
|
-
);
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
it('should use the given `hasError`', () => {
|
|
116
|
-
const testedProp = 'hasError';
|
|
117
|
-
const modifiedProps: SetupProps = {
|
|
118
|
-
[testedProp]: true,
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
const { container } = setup(modifiedProps);
|
|
122
|
-
|
|
123
|
-
expect(container).toHaveClassName(
|
|
124
|
-
getBasicClass({ prefix: CLASSNAME, type: testedProp, value: modifiedProps[testedProp] }),
|
|
125
|
-
);
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
it('should display the given `error`', () => {
|
|
129
|
-
const { container, error } = setup({
|
|
130
|
-
error: 'You are not bold!',
|
|
131
|
-
hasError: true,
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
expect(error).toExist();
|
|
135
|
-
expect(container).toHaveClassName(getBasicClass({ prefix: CLASSNAME, type: 'hasError', value: true }));
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
it('should NOT display the given `error`', () => {
|
|
139
|
-
const { container, error } = setup({
|
|
140
|
-
error: 'You are not bold!',
|
|
141
|
-
hasError: false,
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
expect(error).not.toExist();
|
|
145
|
-
expect(container).not.toHaveClassName(getBasicClass({ prefix: CLASSNAME, type: 'hasError', value: true }));
|
|
61
|
+
const { select } = setup({ isValid: true });
|
|
62
|
+
expect(select).toHaveClass(`${CLASSNAME}--is-valid`);
|
|
146
63
|
});
|
|
147
64
|
|
|
148
65
|
it('should use the given `value`', () => {
|
|
149
|
-
const {
|
|
150
|
-
value: [''],
|
|
151
|
-
});
|
|
66
|
+
const { select, valueChips } = setup({ value: ['val1', 'val2'] });
|
|
152
67
|
|
|
153
|
-
expect(
|
|
154
|
-
expect(
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
const onDropdownClose = jest.fn();
|
|
159
|
-
const { dropdown } = setup({ onDropdownClose });
|
|
160
|
-
|
|
161
|
-
const props: any = dropdown.props();
|
|
162
|
-
|
|
163
|
-
props.onClose();
|
|
164
|
-
|
|
165
|
-
expect(onDropdownClose).toHaveBeenCalled();
|
|
68
|
+
expect(select).not.toHaveClass(`${CLASSNAME}--is-empty`);
|
|
69
|
+
expect(select).toHaveClass(`${CLASSNAME}--has-value`);
|
|
70
|
+
expect(valueChips).not.toBeEmptyDOMElement();
|
|
71
|
+
expect(within(valueChips as any).queryByText('val1')).toBeInTheDocument();
|
|
72
|
+
expect(within(valueChips as any).queryByText('val2')).toBeInTheDocument();
|
|
166
73
|
});
|
|
167
74
|
|
|
168
75
|
it('should pass the given `isOpen` to the dropdown', () => {
|
|
169
|
-
const
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
expect(dropdown).toHaveProp('isOpen', isOpen);
|
|
76
|
+
const { getDropdown } = setup({ isOpen: true });
|
|
77
|
+
expect(getDropdown()).toBeInTheDocument();
|
|
173
78
|
});
|
|
174
79
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
80
|
+
describe('helpers', () => {
|
|
81
|
+
it('should display the given `error`', () => {
|
|
82
|
+
const { select, helpers, props } = setup({ hasError: true, error: 'You are not bold!' });
|
|
83
|
+
expect(select).toHaveClass(`${CLASSNAME}--has-error`);
|
|
84
|
+
expect(helpers.length).toBe(1);
|
|
85
|
+
expect(helpers[0]).toHaveTextContent(props.error as string);
|
|
178
86
|
});
|
|
179
87
|
|
|
180
|
-
|
|
181
|
-
|
|
88
|
+
it('should NOT display the given `error`', () => {
|
|
89
|
+
const { select, helpers } = setup({
|
|
90
|
+
error: 'You are not bold!',
|
|
91
|
+
hasError: false,
|
|
92
|
+
});
|
|
93
|
+
expect(select).not.toHaveClass(`${CLASSNAME}--has-error`);
|
|
94
|
+
expect(helpers.length).toBe(0);
|
|
95
|
+
});
|
|
182
96
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
helper: 'Be bold',
|
|
97
|
+
it('should display the given `helper`', () => {
|
|
98
|
+
const { helpers, props } = setup({ helper: 'Be bold' });
|
|
99
|
+
expect(helpers.length).toBe(1);
|
|
100
|
+
expect(helpers[0]).toHaveTextContent(props.helper as string);
|
|
188
101
|
});
|
|
189
102
|
|
|
190
|
-
|
|
191
|
-
|
|
103
|
+
it('should display the given `helper` and `error`', () => {
|
|
104
|
+
const { select, helpers, props } = setup({
|
|
105
|
+
error: 'You are not bold!',
|
|
106
|
+
hasError: true,
|
|
107
|
+
helper: 'Be bold',
|
|
108
|
+
});
|
|
109
|
+
expect(select).toHaveClass(`${CLASSNAME}--has-error`);
|
|
110
|
+
expect(helpers.length).toBe(2);
|
|
111
|
+
expect(helpers[0]).toHaveTextContent(props.error as string);
|
|
112
|
+
expect(helpers[1]).toHaveTextContent(props.helper as string);
|
|
113
|
+
});
|
|
192
114
|
});
|
|
193
115
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
{
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
116
|
+
describe('chip variant', () => {
|
|
117
|
+
it('should render chip variant', () => {
|
|
118
|
+
const { select, inputWrapper, chip } = setup({ variant: SelectVariant.chip });
|
|
119
|
+
expect(inputWrapper).not.toBeInTheDocument();
|
|
120
|
+
expect(chip).toBeInTheDocument();
|
|
121
|
+
expect(select.className).toMatchInlineSnapshot(
|
|
122
|
+
`"lumx-select lumx-select--has-multiple lumx-select lumx-select--is-empty lumx-select--theme-light"`,
|
|
123
|
+
);
|
|
124
|
+
});
|
|
201
125
|
|
|
202
|
-
|
|
203
|
-
|
|
126
|
+
it('should render chip variant with value', () => {
|
|
127
|
+
const { select, chip } = setup({ variant: SelectVariant.chip, value: ['val1', 'val2'] });
|
|
128
|
+
expect(chip).toHaveTextContent('val1 +1');
|
|
129
|
+
expect(select.className).toMatchInlineSnapshot(
|
|
130
|
+
`"lumx-select lumx-select--has-multiple lumx-select lumx-select--has-value lumx-select--theme-light"`,
|
|
131
|
+
);
|
|
132
|
+
});
|
|
204
133
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
{
|
|
134
|
+
it('should forward prop to chip variant', () => {
|
|
135
|
+
const { chip } = setup({
|
|
208
136
|
'data-id': 'select',
|
|
209
137
|
variant: SelectVariant.chip,
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
);
|
|
213
|
-
|
|
214
|
-
expect(chip.prop('data-id')).toEqual('select');
|
|
138
|
+
});
|
|
139
|
+
expect(chip).toHaveAttribute('data-id', 'select');
|
|
140
|
+
});
|
|
215
141
|
});
|
|
216
142
|
});
|
|
217
143
|
|
|
218
|
-
// 3. Test events.
|
|
219
144
|
describe('Events', () => {
|
|
220
|
-
const onClick: jest.Mock = jest.fn();
|
|
221
|
-
|
|
222
|
-
beforeEach(() => {
|
|
223
|
-
onClick.mockClear();
|
|
224
|
-
});
|
|
225
|
-
|
|
226
145
|
describe('should trigger `onInputClick` when the select button is clicked', () => {
|
|
227
|
-
it('with input variant', () => {
|
|
228
|
-
const
|
|
229
|
-
|
|
230
|
-
input.simulate('click');
|
|
146
|
+
it('with input variant', async () => {
|
|
147
|
+
const onClick = jest.fn();
|
|
148
|
+
const { inputWrapper } = setup({ onInputClick: onClick, variant: SelectVariant.input });
|
|
231
149
|
|
|
150
|
+
await userEvent.click(inputWrapper as any);
|
|
232
151
|
expect(onClick).toHaveBeenCalled();
|
|
233
152
|
});
|
|
234
153
|
|
|
235
|
-
it('with chip variant', () => {
|
|
236
|
-
const
|
|
237
|
-
|
|
238
|
-
input.simulate('click');
|
|
154
|
+
it('with chip variant', async () => {
|
|
155
|
+
const onClick = jest.fn();
|
|
156
|
+
const { chip } = setup({ onInputClick: onClick, variant: SelectVariant.chip });
|
|
239
157
|
|
|
158
|
+
await userEvent.click(chip as any);
|
|
240
159
|
expect(onClick).toHaveBeenCalled();
|
|
241
160
|
});
|
|
242
161
|
});
|
|
243
162
|
|
|
244
|
-
it('should call onClear when an item is clicked with the correct value', () => {
|
|
245
|
-
const onClear
|
|
246
|
-
const {
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
variant: SelectVariant.input,
|
|
251
|
-
clearButtonProps: { label: 'Clear' },
|
|
252
|
-
},
|
|
253
|
-
false,
|
|
254
|
-
);
|
|
255
|
-
|
|
256
|
-
input.find('Chip').first().simulate('click');
|
|
257
|
-
|
|
258
|
-
expect(onClear).toHaveBeenCalled();
|
|
259
|
-
});
|
|
260
|
-
|
|
261
|
-
it('should call onClear when a chip is clicked with the correct value', () => {
|
|
262
|
-
const value1 = 'Value 1';
|
|
263
|
-
const value2 = 'Value 2';
|
|
264
|
-
|
|
265
|
-
const onClear: jest.Mock = jest.fn();
|
|
266
|
-
const { input } = setup(
|
|
267
|
-
{
|
|
268
|
-
onClear,
|
|
269
|
-
value: [value1, value2],
|
|
270
|
-
variant: SelectVariant.chip,
|
|
271
|
-
clearButtonProps: { label: 'Clear' },
|
|
272
|
-
},
|
|
273
|
-
false,
|
|
274
|
-
);
|
|
275
|
-
|
|
276
|
-
(input.find('Chip').first().props() as any).onAfterClick();
|
|
277
|
-
|
|
278
|
-
expect(onClear).toHaveBeenCalled();
|
|
279
|
-
});
|
|
280
|
-
});
|
|
281
|
-
|
|
282
|
-
// 4. Test conditions (i.e. things that display or not in the UI based on props).
|
|
283
|
-
describe('Conditions', () => {
|
|
284
|
-
describe('Input variant', () => {
|
|
285
|
-
it('should render a div as the select input', () => {
|
|
286
|
-
const { dropdown, input } = setup({}, false);
|
|
287
|
-
const dropdownRef: RefObject<HTMLDivElement> = dropdown.prop('anchorRef');
|
|
288
|
-
expect(input.type()).toBe('div');
|
|
289
|
-
// Impossible to get the ref passed to a div so we check if ref.current is matching the input html.
|
|
290
|
-
expect(input.html()).toEqual(dropdownRef && dropdownRef.current && dropdownRef.current.outerHTML);
|
|
163
|
+
it('should call onClear when an item is clicked with the correct value', async () => {
|
|
164
|
+
const onClear = jest.fn();
|
|
165
|
+
const { valueChips } = setup({
|
|
166
|
+
onClear,
|
|
167
|
+
value: ['val 1', 'val 2'],
|
|
168
|
+
variant: SelectVariant.input,
|
|
291
169
|
});
|
|
292
170
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
const hasMultipleValues: Partial<SetupProps> = {
|
|
298
|
-
value: [value1, value2, value3],
|
|
299
|
-
variant: SelectVariant.input,
|
|
300
|
-
};
|
|
301
|
-
|
|
302
|
-
it('should render the values selected in Chips if multiple ', () => {
|
|
303
|
-
const { input, props } = setup({ ...hasMultipleValues }, false);
|
|
304
|
-
|
|
305
|
-
expect(input.find(Chip).length).toBe(props.value?.length);
|
|
306
|
-
expect(input.find(Chip).at(0).children().text()).toBe(props.value?.[0]);
|
|
307
|
-
expect(input.find(Chip).at(1).children().text()).toBe(props.value?.[1]);
|
|
308
|
-
expect(input.find(Chip).at(2).children().text()).toBe(props.value?.[2]);
|
|
309
|
-
});
|
|
310
|
-
});
|
|
171
|
+
const clearButtons = getAllByClassName(
|
|
172
|
+
valueChips as any,
|
|
173
|
+
`${Chip.className as string}__after--is-clickable`,
|
|
174
|
+
);
|
|
311
175
|
|
|
312
|
-
|
|
313
|
-
const placeholder = 'My placeholder';
|
|
314
|
-
const hasNoValueProps: Partial<SetupProps> = {
|
|
315
|
-
placeholder,
|
|
316
|
-
value: [],
|
|
317
|
-
variant: SelectVariant.input,
|
|
318
|
-
};
|
|
176
|
+
expect(clearButtons.length).toBe(2);
|
|
319
177
|
|
|
320
|
-
|
|
321
|
-
const { input } = setup({ ...hasNoValueProps }, false);
|
|
178
|
+
await userEvent.click(clearButtons[1]);
|
|
322
179
|
|
|
323
|
-
|
|
324
|
-
placeholder,
|
|
325
|
-
);
|
|
326
|
-
});
|
|
327
|
-
});
|
|
180
|
+
expect(onClear).toHaveBeenCalledWith(expect.any(Object), 'val 2');
|
|
328
181
|
});
|
|
329
182
|
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
expect(input.type()).toEqual(Chip);
|
|
335
|
-
});
|
|
336
|
-
|
|
337
|
-
describe('Has value', () => {
|
|
338
|
-
const value = 'Value';
|
|
339
|
-
const hasValueProps: Partial<SetupProps> = {
|
|
340
|
-
value: [value],
|
|
341
|
-
variant: SelectVariant.chip,
|
|
342
|
-
};
|
|
343
|
-
|
|
344
|
-
it('should render the value', () => {
|
|
345
|
-
const label = 'The label';
|
|
346
|
-
const { input } = setup(
|
|
347
|
-
{
|
|
348
|
-
...hasValueProps,
|
|
349
|
-
label,
|
|
350
|
-
},
|
|
351
|
-
false,
|
|
352
|
-
);
|
|
353
|
-
|
|
354
|
-
expect(input.find('.lumx-chip__label').text()).toEqual(value);
|
|
355
|
-
});
|
|
356
|
-
|
|
357
|
-
it('should render a close icon if there is a value', () => {
|
|
358
|
-
const { input } = setup({ ...hasValueProps }, false);
|
|
359
|
-
|
|
360
|
-
expect(input.find(Icon).first().prop('icon')).toBe(mdiCloseCircle);
|
|
361
|
-
});
|
|
362
|
-
});
|
|
363
|
-
|
|
364
|
-
describe('Has multiple values', () => {
|
|
365
|
-
const value = ['v1', 'v2', 'v3'];
|
|
366
|
-
|
|
367
|
-
it('should render the value and additional text if multiple values', () => {
|
|
368
|
-
const { input } = setup(
|
|
369
|
-
{
|
|
370
|
-
label: 'The label',
|
|
371
|
-
value,
|
|
372
|
-
variant: SelectVariant.chip,
|
|
373
|
-
},
|
|
374
|
-
false,
|
|
375
|
-
);
|
|
183
|
+
it('should clear all with chip variant', async () => {
|
|
184
|
+
const value1 = 'Value 1';
|
|
185
|
+
const value2 = 'Value 2';
|
|
376
186
|
|
|
377
|
-
|
|
378
|
-
|
|
187
|
+
const onClear = jest.fn();
|
|
188
|
+
const { chip } = setup({
|
|
189
|
+
onClear,
|
|
190
|
+
value: [value1, value2],
|
|
191
|
+
variant: SelectVariant.chip,
|
|
379
192
|
});
|
|
380
193
|
|
|
381
|
-
|
|
382
|
-
const hasNoValue: Partial<SetupProps> = {
|
|
383
|
-
value: [],
|
|
384
|
-
variant: SelectVariant.chip,
|
|
385
|
-
};
|
|
386
|
-
|
|
387
|
-
it('should render the label', () => {
|
|
388
|
-
const label = 'The label';
|
|
389
|
-
const { input } = setup({ ...hasNoValue, label }, false);
|
|
194
|
+
const clearButton = getByClassName(chip as any, `${Chip.className as string}__after--is-clickable`);
|
|
390
195
|
|
|
391
|
-
|
|
392
|
-
});
|
|
393
|
-
|
|
394
|
-
it('should render a MenuDown icon', () => {
|
|
395
|
-
const { input } = setup({ ...hasNoValue }, false);
|
|
196
|
+
await userEvent.click(clearButton);
|
|
396
197
|
|
|
397
|
-
|
|
398
|
-
});
|
|
399
|
-
});
|
|
198
|
+
expect(onClear).toHaveBeenCalled();
|
|
400
199
|
});
|
|
401
200
|
});
|
|
402
201
|
|
|
403
202
|
// Common tests suite.
|
|
404
|
-
|
|
203
|
+
commonTestsSuiteRTL(setup, {
|
|
204
|
+
baseClassName: CLASSNAME,
|
|
205
|
+
forwardClassName: 'select',
|
|
206
|
+
forwardAttributes: 'inputWrapper',
|
|
207
|
+
forwardRef: 'select',
|
|
208
|
+
});
|
|
405
209
|
});
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import React, { Ref, useCallback, useMemo, useRef } from 'react';
|
|
2
|
-
|
|
3
1
|
import classNames from 'classnames';
|
|
2
|
+
import React, { Ref, useCallback, useMemo, useRef } from 'react';
|
|
4
3
|
import { uid } from 'uid';
|
|
5
4
|
|
|
5
|
+
import { Placement } from '@lumx/react';
|
|
6
6
|
import { Kind, Theme } from '@lumx/react/components';
|
|
7
7
|
import { Dropdown } from '@lumx/react/components/dropdown/Dropdown';
|
|
8
8
|
import { InputHelper } from '@lumx/react/components/input-helper/InputHelper';
|
|
9
|
+
import { useFocusTrap } from '@lumx/react/hooks/useFocusTrap';
|
|
10
|
+
import { useListenFocus } from '@lumx/react/hooks/useListenFocus';
|
|
9
11
|
import { getRootClassName, handleBasicClasses } from '@lumx/react/utils/className';
|
|
10
12
|
import { mergeRefs } from '@lumx/react/utils/mergeRefs';
|
|
11
|
-
import { useListenFocus } from '@lumx/react/hooks/useListenFocus';
|
|
12
|
-
import { Placement } from '@lumx/react';
|
|
13
13
|
|
|
14
14
|
import { CoreSelectProps, SelectVariant } from './constants';
|
|
15
15
|
|
|
@@ -30,6 +30,7 @@ export const WithSelectContext = (
|
|
|
30
30
|
{
|
|
31
31
|
children,
|
|
32
32
|
className,
|
|
33
|
+
focusElement,
|
|
33
34
|
isMultiple,
|
|
34
35
|
closeOnClick = !isMultiple,
|
|
35
36
|
disabled,
|
|
@@ -58,6 +59,7 @@ export const WithSelectContext = (
|
|
|
58
59
|
const selectId = useMemo(() => id || `select-${uid()}`, [id]);
|
|
59
60
|
const anchorRef = useRef<HTMLElement>(null);
|
|
60
61
|
const selectRef = useRef<HTMLDivElement>(null);
|
|
62
|
+
const dropdownRef = useRef<HTMLDivElement>(null);
|
|
61
63
|
const isFocus = useListenFocus(anchorRef);
|
|
62
64
|
|
|
63
65
|
const handleKeyboardNav = useCallback(
|
|
@@ -77,6 +79,9 @@ export const WithSelectContext = (
|
|
|
77
79
|
anchorRef?.current?.blur();
|
|
78
80
|
};
|
|
79
81
|
|
|
82
|
+
// Handle focus trap.
|
|
83
|
+
useFocusTrap(isOpen && dropdownRef.current, focusElement?.current);
|
|
84
|
+
|
|
80
85
|
return (
|
|
81
86
|
<div
|
|
82
87
|
ref={mergeRefs(ref, selectRef)}
|
|
@@ -125,6 +130,7 @@ export const WithSelectContext = (
|
|
|
125
130
|
placement={Placement.BOTTOM_START}
|
|
126
131
|
onClose={onClose}
|
|
127
132
|
onInfiniteScroll={onInfiniteScroll}
|
|
133
|
+
ref={dropdownRef}
|
|
128
134
|
>
|
|
129
135
|
{children}
|
|
130
136
|
</Dropdown>
|
|
@@ -1,52 +1,39 @@
|
|
|
1
|
-
import React
|
|
1
|
+
import React from 'react';
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
import '
|
|
5
|
-
|
|
6
|
-
import {
|
|
3
|
+
import { render } from '@testing-library/react';
|
|
4
|
+
import { getByClassName } from '@lumx/react/testing/utils/queries';
|
|
5
|
+
import { commonTestsSuiteRTL } from '@lumx/react/testing/utils';
|
|
6
|
+
import { Theme } from '@lumx/react';
|
|
7
7
|
|
|
8
8
|
import { SideNavigation, SideNavigationProps } from './SideNavigation';
|
|
9
9
|
|
|
10
10
|
const CLASSNAME = SideNavigation.className as string;
|
|
11
11
|
|
|
12
|
-
type SetupProps = Partial<SideNavigationProps>;
|
|
13
|
-
|
|
14
12
|
/**
|
|
15
13
|
* Mounts the component and returns common DOM elements / data needed in multiple tests further down.
|
|
16
14
|
*/
|
|
17
|
-
const setup = (
|
|
18
|
-
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
return {
|
|
23
|
-
props,
|
|
24
|
-
root: wrapper.find(`.${CLASSNAME}`),
|
|
25
|
-
wrapper,
|
|
26
|
-
};
|
|
15
|
+
const setup = (props: Partial<SideNavigationProps> = {}) => {
|
|
16
|
+
render(<SideNavigation {...(props as any)} />);
|
|
17
|
+
const sideNavigation = getByClassName(document.body, CLASSNAME);
|
|
18
|
+
return { props, sideNavigation };
|
|
27
19
|
};
|
|
28
20
|
|
|
29
21
|
describe(`<${SideNavigation.displayName}>`, () => {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
it('should render correctly', () => {
|
|
35
|
-
const { root, wrapper } = setup();
|
|
36
|
-
expect(wrapper).toMatchSnapshot();
|
|
37
|
-
|
|
38
|
-
expect(root).toExist();
|
|
39
|
-
expect(root).toHaveClassName(CLASSNAME);
|
|
40
|
-
});
|
|
22
|
+
it('should render default', () => {
|
|
23
|
+
const { sideNavigation } = setup();
|
|
24
|
+
expect(sideNavigation.className).toMatchInlineSnapshot(`"lumx-side-navigation"`);
|
|
41
25
|
});
|
|
42
26
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
// 4. Test conditions => no conditions
|
|
27
|
+
it('should render dark theme', () => {
|
|
28
|
+
const { sideNavigation } = setup({ theme: Theme.dark });
|
|
29
|
+
expect(sideNavigation.className).toMatchInlineSnapshot(`"lumx-color-font-light-N lumx-side-navigation"`);
|
|
30
|
+
});
|
|
48
31
|
|
|
49
|
-
// 5. Test state => no state
|
|
50
32
|
// Common tests suite.
|
|
51
|
-
|
|
33
|
+
commonTestsSuiteRTL(setup, {
|
|
34
|
+
baseClassName: CLASSNAME,
|
|
35
|
+
forwardClassName: 'sideNavigation',
|
|
36
|
+
forwardAttributes: 'sideNavigation',
|
|
37
|
+
forwardRef: 'sideNavigation',
|
|
38
|
+
});
|
|
52
39
|
});
|