@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,8 +1,9 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { mount, shallow } from 'enzyme';
|
|
3
|
-
import 'jest-enzyme';
|
|
4
|
-
import { commonTestsSuite } from '@lumx/react/testing/utils';
|
|
5
2
|
|
|
3
|
+
import { commonTestsSuiteRTL } from '@lumx/react/testing/utils';
|
|
4
|
+
|
|
5
|
+
import { render, screen } from '@testing-library/react';
|
|
6
|
+
import { getByClassName } from '@lumx/react/testing/utils/queries';
|
|
6
7
|
import { TableRow, TableRowProps } from './TableRow';
|
|
7
8
|
|
|
8
9
|
const CLASSNAME = TableRow.className as string;
|
|
@@ -10,13 +11,32 @@ const CLASSNAME = TableRow.className as string;
|
|
|
10
11
|
/**
|
|
11
12
|
* Mounts the component and returns common DOM elements / data needed in multiple tests further down.
|
|
12
13
|
*/
|
|
13
|
-
const setup = (props: Partial<TableRowProps> = {}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
const setup = (props: Partial<TableRowProps> = {}) => {
|
|
15
|
+
render(
|
|
16
|
+
<table>
|
|
17
|
+
<tbody>
|
|
18
|
+
<TableRow {...(props as any)} />
|
|
19
|
+
</tbody>
|
|
20
|
+
</table>,
|
|
21
|
+
);
|
|
22
|
+
const tableRow = getByClassName(document.body, CLASSNAME);
|
|
23
|
+
return { props, tableRow };
|
|
17
24
|
};
|
|
18
25
|
|
|
19
26
|
describe(`<${TableRow.displayName}>`, () => {
|
|
27
|
+
it('should render default', () => {
|
|
28
|
+
const content = 'Content';
|
|
29
|
+
const { tableRow } = setup({ children: <td>{content}</td> });
|
|
30
|
+
expect(tableRow).toBe(screen.queryByRole('row', { name: content }));
|
|
31
|
+
expect(tableRow).toHaveAttribute('tabindex', '-1');
|
|
32
|
+
expect(tableRow).not.toHaveAttribute('aria-disabled');
|
|
33
|
+
});
|
|
34
|
+
|
|
20
35
|
// Common tests suite.
|
|
21
|
-
|
|
36
|
+
commonTestsSuiteRTL(setup, {
|
|
37
|
+
baseClassName: CLASSNAME,
|
|
38
|
+
forwardClassName: 'tableRow',
|
|
39
|
+
forwardAttributes: 'tableRow',
|
|
40
|
+
forwardRef: 'tableRow',
|
|
41
|
+
});
|
|
22
42
|
});
|
|
@@ -1,116 +1,47 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { commonTestsSuite, Wrapper } from '@lumx/react/testing/utils';
|
|
3
|
-
import { getBasicClass } from '@lumx/react/utils/className';
|
|
1
|
+
import React from 'react';
|
|
4
2
|
|
|
5
|
-
import {
|
|
6
|
-
import '
|
|
7
|
-
import
|
|
3
|
+
import { commonTestsSuiteRTL } from '@lumx/react/testing/utils';
|
|
4
|
+
import { render, screen } from '@testing-library/react';
|
|
5
|
+
import { getByClassName, queryByClassName } from '@lumx/react/testing/utils/queries';
|
|
8
6
|
|
|
7
|
+
import { Icon } from '@lumx/react';
|
|
8
|
+
import { mdiPlay } from '@lumx/icons';
|
|
9
9
|
import { Tab, TabProps } from './Tab';
|
|
10
|
-
import { setupTabProviderMocks } from './test.mocks';
|
|
11
10
|
|
|
12
11
|
const CLASSNAME = Tab.className as string;
|
|
13
12
|
|
|
14
|
-
// Mock useTabProviderContext.
|
|
15
|
-
jest.mock('./state', () => {
|
|
16
|
-
const state = jest.requireActual('./state');
|
|
17
|
-
return { ...state, useTabProviderContext: jest.fn(), useTabProviderContextState: jest.fn() };
|
|
18
|
-
});
|
|
19
|
-
|
|
20
13
|
type SetupProps = Partial<TabProps>;
|
|
21
14
|
|
|
22
15
|
/**
|
|
23
16
|
* Mounts the component and returns common DOM elements / data needed in multiple tests further down.
|
|
24
17
|
*/
|
|
25
|
-
const setup = (
|
|
26
|
-
const props
|
|
27
|
-
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
return { props,
|
|
18
|
+
const setup = (propsOverride: SetupProps = {}) => {
|
|
19
|
+
const props = { label: 'Label', ...propsOverride };
|
|
20
|
+
render(<Tab {...props} />);
|
|
21
|
+
const tab = getByClassName(document.body, CLASSNAME);
|
|
22
|
+
const icon = queryByClassName(tab, Icon.className as string);
|
|
23
|
+
return { props, tab, icon };
|
|
31
24
|
};
|
|
32
25
|
|
|
33
26
|
describe(`<${Tab.displayName}>`, () => {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
it('should render icon', () => {
|
|
44
|
-
setupTabProviderMocks({ index: 2 });
|
|
45
|
-
const { wrapper } = setup({ icon: mdiCheck });
|
|
46
|
-
expect(wrapper).toMatchSnapshot();
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
it('should render active state', () => {
|
|
50
|
-
setupTabProviderMocks({ index: 3, isActive: true });
|
|
51
|
-
const { wrapper } = setup({});
|
|
52
|
-
expect(wrapper).toMatchSnapshot();
|
|
53
|
-
});
|
|
27
|
+
it('should render default', () => {
|
|
28
|
+
const label = 'Label';
|
|
29
|
+
const { tab, icon } = setup({ label });
|
|
30
|
+
expect(tab).toBe(screen.queryByRole('tab', { name: label }));
|
|
31
|
+
expect(tab.tagName).toBe('BUTTON');
|
|
32
|
+
expect(tab).toHaveAttribute('type', 'button');
|
|
33
|
+
expect(icon).not.toBeInTheDocument();
|
|
54
34
|
});
|
|
55
35
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
setupTabProviderMocks();
|
|
60
|
-
const props: any = {
|
|
61
|
-
isActive: true,
|
|
62
|
-
isDisabled: true,
|
|
63
|
-
};
|
|
64
|
-
const { wrapper } = setup(props);
|
|
65
|
-
|
|
66
|
-
Object.keys(props).forEach((prop) => {
|
|
67
|
-
expect(wrapper).toHaveClassName(getBasicClass({ prefix: CLASSNAME, type: prop, value: props[prop] }));
|
|
68
|
-
});
|
|
69
|
-
});
|
|
36
|
+
it('should render icon', () => {
|
|
37
|
+
const { icon } = setup({ icon: mdiPlay });
|
|
38
|
+
expect(icon).toBeInTheDocument();
|
|
70
39
|
});
|
|
71
40
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
wrapper.simulate('focus');
|
|
79
|
-
expect(changeToTab).toHaveBeenCalledTimes(1);
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
it('should trigger `onChange` when clicked', () => {
|
|
83
|
-
const { changeToTab } = setupTabProviderMocks();
|
|
84
|
-
const { wrapper } = setup({}, false);
|
|
85
|
-
|
|
86
|
-
wrapper.simulate('click');
|
|
87
|
-
expect(changeToTab).toHaveBeenCalledTimes(1);
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
it('should trigger `onChange` when pressing `enter`', () => {
|
|
91
|
-
const { changeToTab } = setupTabProviderMocks();
|
|
92
|
-
const { wrapper } = setup({}, false);
|
|
93
|
-
|
|
94
|
-
wrapper.simulate('keypress', { key: 'Enter' });
|
|
95
|
-
expect(changeToTab).toHaveBeenCalledTimes(1);
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
it('should not trigger `onChange` when pressing any other key', () => {
|
|
99
|
-
const { changeToTab } = setupTabProviderMocks();
|
|
100
|
-
const { wrapper } = setup({}, false);
|
|
101
|
-
|
|
102
|
-
wrapper.simulate('keypress', { key: 'a' });
|
|
103
|
-
expect(changeToTab).not.toHaveBeenCalled();
|
|
104
|
-
});
|
|
41
|
+
commonTestsSuiteRTL(setup, {
|
|
42
|
+
baseClassName: CLASSNAME,
|
|
43
|
+
forwardClassName: 'tab',
|
|
44
|
+
forwardAttributes: 'tab',
|
|
45
|
+
forwardRef: 'tab',
|
|
105
46
|
});
|
|
106
|
-
|
|
107
|
-
// Common tests suite.
|
|
108
|
-
commonTestsSuite(
|
|
109
|
-
(...args: any[]) => {
|
|
110
|
-
setupTabProviderMocks();
|
|
111
|
-
return setup(...args);
|
|
112
|
-
},
|
|
113
|
-
{ className: 'wrapper', prop: 'wrapper' },
|
|
114
|
-
{ className: CLASSNAME },
|
|
115
|
-
);
|
|
116
47
|
});
|
|
@@ -1,80 +1,45 @@
|
|
|
1
|
-
import
|
|
1
|
+
import React from 'react';
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { Tab } from '@lumx/react';
|
|
4
|
+
import { commonTestsSuiteRTL } from '@lumx/react/testing/utils';
|
|
5
|
+
import { render, screen } from '@testing-library/react';
|
|
6
|
+
import { getByClassName, queryByClassName } from '@lumx/react/testing/utils/queries';
|
|
5
7
|
|
|
6
|
-
import {
|
|
7
|
-
import 'jest-enzyme';
|
|
8
|
-
import React, { ReactElement } from 'react';
|
|
9
|
-
import { build, oneOf } from 'test-data-bot';
|
|
10
|
-
import { TabList, TabListLayout, TabListProps } from './TabList';
|
|
11
|
-
import { setupTabProviderMocks } from './test.mocks';
|
|
8
|
+
import { TabList, TabListProps } from './TabList';
|
|
12
9
|
|
|
13
10
|
const CLASSNAME = TabList.className as string;
|
|
14
11
|
|
|
15
|
-
// Mock useTabProviderContext.
|
|
16
|
-
jest.mock('./state', () => {
|
|
17
|
-
const state = jest.requireActual('./state');
|
|
18
|
-
return { ...state, useTabProviderContext: jest.fn(), useTabProviderContextState: jest.fn() };
|
|
19
|
-
});
|
|
20
|
-
|
|
21
12
|
type SetupProps = Partial<TabListProps>;
|
|
22
13
|
|
|
23
14
|
/**
|
|
24
15
|
* Mounts the component and returns common DOM elements / data needed in multiple tests further down.
|
|
25
16
|
*/
|
|
26
|
-
const setup = (
|
|
17
|
+
const setup = (propsOverride: SetupProps = {}) => {
|
|
27
18
|
const tabs = [<Tab key={0} label="Tab 0" />, <Tab key={1} label="Tab 1" />];
|
|
28
19
|
const props: TabListProps = {
|
|
29
20
|
children: tabs,
|
|
30
21
|
'aria-label': 'Tab list',
|
|
31
22
|
...propsOverride,
|
|
32
23
|
};
|
|
33
|
-
const renderer: (el: ReactElement) => Wrapper = shallowRendering ? shallow : mount;
|
|
34
|
-
const wrapper = renderer(<TabList {...props} />);
|
|
35
24
|
|
|
36
|
-
|
|
25
|
+
render(<TabList {...props} />);
|
|
26
|
+
const tabList = getByClassName(document.body, CLASSNAME);
|
|
27
|
+
const links = queryByClassName(tabList, `${CLASSNAME}__links`);
|
|
28
|
+
return { props, tabList, links };
|
|
37
29
|
};
|
|
38
30
|
|
|
39
31
|
describe(`<${TabList.displayName}>`, () => {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
// 1. Test render via snapshot (default states of component).
|
|
45
|
-
describe('Snapshots and structure', () => {
|
|
46
|
-
it('should render correctly', () => {
|
|
47
|
-
const { wrapper } = setup();
|
|
48
|
-
expect(wrapper).toMatchSnapshot();
|
|
49
|
-
|
|
50
|
-
expect(wrapper).toExist();
|
|
51
|
-
expect(wrapper).toHaveClassName(CLASSNAME);
|
|
52
|
-
|
|
53
|
-
expect(wrapper.childAt(0)).toExist();
|
|
54
|
-
expect(wrapper.childAt(0)).toHaveClassName('lumx-tabs__links');
|
|
55
|
-
});
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
// 2. Test defaultProps value and important props custom values.
|
|
59
|
-
describe('Props', () => {
|
|
60
|
-
it('should use the given props', () => {
|
|
61
|
-
const modifiedPropsBuilder: () => SetupProps = build('props').fields({
|
|
62
|
-
layout: TabListLayout.clustered,
|
|
63
|
-
position: oneOf(Alignment.center, Alignment.right),
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
const modifiedProps: SetupProps = modifiedPropsBuilder();
|
|
67
|
-
|
|
68
|
-
const { wrapper } = setup({ ...modifiedProps });
|
|
69
|
-
|
|
70
|
-
Object.keys(modifiedProps).forEach((prop) => {
|
|
71
|
-
expect(wrapper).toHaveClassName(
|
|
72
|
-
getBasicClass({ prefix: CLASSNAME, type: prop, value: modifiedProps[prop] }),
|
|
73
|
-
);
|
|
74
|
-
});
|
|
75
|
-
});
|
|
32
|
+
it('should render default', () => {
|
|
33
|
+
const name = 'Tab list';
|
|
34
|
+
const { links } = setup({ 'aria-label': name });
|
|
35
|
+
expect(links).toBe(screen.queryByRole('tablist', { name }));
|
|
76
36
|
});
|
|
77
37
|
|
|
78
38
|
// Common tests suite.
|
|
79
|
-
|
|
39
|
+
commonTestsSuiteRTL(setup, {
|
|
40
|
+
baseClassName: CLASSNAME,
|
|
41
|
+
forwardClassName: 'tabList',
|
|
42
|
+
forwardAttributes: 'tabList',
|
|
43
|
+
forwardRef: 'tabList',
|
|
44
|
+
});
|
|
80
45
|
});
|
|
@@ -1,74 +1,39 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
import '
|
|
4
|
-
import
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import { commonTestsSuiteRTL } from '@lumx/react/testing/utils';
|
|
4
|
+
import { getByClassName } from '@lumx/react/testing/utils/queries';
|
|
5
|
+
import { render, screen } from '@testing-library/react';
|
|
5
6
|
|
|
6
7
|
import { TabPanel, TabPanelProps } from './TabPanel';
|
|
7
|
-
import { setupTabProviderMocks } from './test.mocks';
|
|
8
8
|
|
|
9
9
|
const CLASSNAME = TabPanel.className as string;
|
|
10
10
|
|
|
11
|
-
// Mock useTabProviderContext.
|
|
12
|
-
jest.mock('./state', () => {
|
|
13
|
-
const state = jest.requireActual('./state');
|
|
14
|
-
return { ...state, useTabProviderContext: jest.fn(), useTabProviderContextState: jest.fn() };
|
|
15
|
-
});
|
|
16
|
-
|
|
17
11
|
type SetupProps = Partial<TabPanelProps>;
|
|
18
12
|
|
|
19
13
|
/**
|
|
20
14
|
* Mounts the component and returns common DOM elements / data needed in multiple tests further down.
|
|
21
15
|
*/
|
|
22
|
-
const setup = (
|
|
16
|
+
const setup = (propsOverride: SetupProps = {}) => {
|
|
23
17
|
const props: TabPanelProps = { ...propsOverride, children: 'Tab panel content' };
|
|
24
|
-
const renderer: (el: ReactElement) => Wrapper = shallowRendering ? shallow : mount;
|
|
25
|
-
const wrapper: Wrapper = renderer(<TabPanel {...props} />);
|
|
26
18
|
|
|
27
|
-
|
|
19
|
+
render(<TabPanel {...props} />);
|
|
20
|
+
const tabPanel = getByClassName(document.body, CLASSNAME);
|
|
21
|
+
|
|
22
|
+
return { props, tabPanel };
|
|
28
23
|
};
|
|
29
24
|
|
|
30
25
|
describe(`<${TabPanel.displayName}>`, () => {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
const { wrapper } = setup();
|
|
36
|
-
expect(wrapper).toMatchSnapshot();
|
|
37
|
-
expect(wrapper).toHaveClassName(CLASSNAME);
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
it('should render isActive state', () => {
|
|
41
|
-
setupTabProviderMocks({ index: 2, isActive: true });
|
|
42
|
-
const { wrapper } = setup();
|
|
43
|
-
expect(wrapper).toMatchSnapshot();
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
it('should not render children when not active and lazy', () => {
|
|
47
|
-
setupTabProviderMocks({ isLazy: true, isActive: false });
|
|
48
|
-
const { wrapper } = setup();
|
|
49
|
-
expect(wrapper.find('div').props().children).toBeFalsy();
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
it('should render children when active and lazy', () => {
|
|
53
|
-
setupTabProviderMocks({ isLazy: true, isActive: true });
|
|
54
|
-
const { wrapper } = setup();
|
|
55
|
-
expect(wrapper.find('div').props().children).toBeTruthy();
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
it('should render children when not active and not lazy', () => {
|
|
59
|
-
setupTabProviderMocks({ isActive: false, isLazy: false });
|
|
60
|
-
const { wrapper } = setup();
|
|
61
|
-
expect(wrapper.find('div').props().children).toBeTruthy();
|
|
62
|
-
});
|
|
26
|
+
it('should render default', () => {
|
|
27
|
+
const content = 'Content';
|
|
28
|
+
const { tabPanel } = setup({ children: content });
|
|
29
|
+
expect(tabPanel).toBe(screen.queryByRole('tabpanel'));
|
|
63
30
|
});
|
|
64
31
|
|
|
65
32
|
// Common tests suite.
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
{ className: CLASSNAME },
|
|
73
|
-
);
|
|
33
|
+
commonTestsSuiteRTL(setup, {
|
|
34
|
+
baseClassName: CLASSNAME,
|
|
35
|
+
forwardClassName: 'tabPanel',
|
|
36
|
+
forwardAttributes: 'tabPanel',
|
|
37
|
+
forwardRef: 'tabPanel',
|
|
38
|
+
});
|
|
74
39
|
});
|
|
@@ -53,7 +53,7 @@ export const TabPanel: Comp<TabPanelProps, HTMLDivElement> = forwardRef((props,
|
|
|
53
53
|
id={state?.tabPanelId}
|
|
54
54
|
className={classNames(className, handleBasicClasses({ prefix: CLASSNAME, isActive }))}
|
|
55
55
|
role="tabpanel"
|
|
56
|
-
tabIndex={0}
|
|
56
|
+
tabIndex={isActive ? 0 : -1}
|
|
57
57
|
aria-labelledby={state?.tabId}
|
|
58
58
|
>
|
|
59
59
|
{(!state?.isLazy || isActive) && children}
|
|
@@ -1,42 +1,163 @@
|
|
|
1
|
-
import { Tab, TabList, TabPanel, TabProvider } from '@lumx/react';
|
|
2
|
-
import { mount } from 'enzyme';
|
|
3
|
-
import 'jest-enzyme';
|
|
4
1
|
import React from 'react';
|
|
5
2
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
expect(
|
|
35
|
-
expect(
|
|
36
|
-
|
|
37
|
-
// Tab
|
|
38
|
-
|
|
39
|
-
expect(
|
|
3
|
+
import { Tab, TabList, TabPanel, TabProvider, TabProviderProps } from '@lumx/react';
|
|
4
|
+
import { render } from '@testing-library/react';
|
|
5
|
+
import userEvent from '@testing-library/user-event';
|
|
6
|
+
import { checkTabActive, query } from '@lumx/react/components/tabs/test-utils';
|
|
7
|
+
|
|
8
|
+
const setup = (props: Partial<TabProviderProps> = {}) => {
|
|
9
|
+
render(
|
|
10
|
+
<TabProvider {...props}>
|
|
11
|
+
<TabList aria-label="Tab list">
|
|
12
|
+
<Tab label="Tab 1" />
|
|
13
|
+
<Tab label="Tab 2" isDisabled />
|
|
14
|
+
<Tab label="Tab 3" />
|
|
15
|
+
</TabList>
|
|
16
|
+
|
|
17
|
+
<TabPanel>Tab 1 content</TabPanel>
|
|
18
|
+
<TabPanel>Tab 2 content</TabPanel>
|
|
19
|
+
<TabPanel>Tab 3 content</TabPanel>
|
|
20
|
+
</TabProvider>,
|
|
21
|
+
);
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
describe(`TabProvider`, () => {
|
|
25
|
+
describe('default config', () => {
|
|
26
|
+
it('should render with accessible DOM', () => {
|
|
27
|
+
setup();
|
|
28
|
+
|
|
29
|
+
// Tab list
|
|
30
|
+
const tabList = query.tabList('Tab list');
|
|
31
|
+
expect(tabList).toBeInTheDocument();
|
|
32
|
+
expect(query.tabs(tabList).length).toBe(3);
|
|
33
|
+
|
|
34
|
+
// Tab 1
|
|
35
|
+
const tab1 = query.tab('Tab 1', tabList);
|
|
36
|
+
expect(tab1).toBeInTheDocument();
|
|
37
|
+
|
|
38
|
+
// Tab 2
|
|
39
|
+
const tab2 = query.tab('Tab 2', tabList);
|
|
40
|
+
expect(tab2).toBeInTheDocument();
|
|
41
|
+
|
|
42
|
+
// Tab 3
|
|
43
|
+
const tab3 = query.tab('Tab 3', tabList);
|
|
44
|
+
expect(tab3).toBeInTheDocument();
|
|
45
|
+
|
|
46
|
+
// Tab panel 1
|
|
47
|
+
const tabPanel1 = query.tabPanel('Tab 1');
|
|
48
|
+
expect(tabPanel1).toBeInTheDocument();
|
|
49
|
+
expect(tab1).toHaveAttribute('aria-controls', tabPanel1?.id);
|
|
50
|
+
|
|
51
|
+
// Tab panel 2
|
|
52
|
+
const tabPanel2 = query.tabPanel('Tab 2');
|
|
53
|
+
expect(tabPanel2).toBeInTheDocument();
|
|
54
|
+
expect(tab2).toHaveAttribute('aria-controls', tabPanel2?.id);
|
|
55
|
+
|
|
56
|
+
// Tab panel 3
|
|
57
|
+
const tabPanel3 = query.tabPanel('Tab 3');
|
|
58
|
+
expect(tabPanel3).toBeInTheDocument();
|
|
59
|
+
expect(tab3).toHaveAttribute('aria-controls', tabPanel3?.id);
|
|
60
|
+
|
|
61
|
+
// First tab is active
|
|
62
|
+
checkTabActive('Tab 1');
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('should switch tab on click', async () => {
|
|
66
|
+
setup();
|
|
67
|
+
|
|
68
|
+
checkTabActive('Tab 1');
|
|
69
|
+
|
|
70
|
+
// Click on second tab (that is disabled) should do nothing
|
|
71
|
+
await userEvent.click(query.tab('Tab 2'));
|
|
72
|
+
checkTabActive('Tab 1');
|
|
73
|
+
|
|
74
|
+
// Click on third tab should work
|
|
75
|
+
await userEvent.click(query.tab('Tab 3'));
|
|
76
|
+
checkTabActive('Tab 3');
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('should be navigable with keyboard', async () => {
|
|
80
|
+
setup();
|
|
81
|
+
|
|
82
|
+
checkTabActive('Tab 1');
|
|
83
|
+
|
|
84
|
+
// First tab stop on active tab (tab1)
|
|
85
|
+
await userEvent.tab();
|
|
86
|
+
expect(query.tab('Tab 1')).toHaveFocus();
|
|
87
|
+
|
|
88
|
+
// Second tab stop on active tab panel (tabPanel1)
|
|
89
|
+
await userEvent.tab();
|
|
90
|
+
expect(query.tabPanel('Tab 1')).toHaveFocus();
|
|
91
|
+
|
|
92
|
+
// Go back to tab1
|
|
93
|
+
await userEvent.tab({ shift: true });
|
|
94
|
+
expect(query.tab('Tab 1')).toHaveFocus();
|
|
95
|
+
|
|
96
|
+
// Navigate with ArrowRight to go to the next tab (tab2)
|
|
97
|
+
await userEvent.keyboard('[ArrowRight]');
|
|
98
|
+
expect(query.tab('Tab 2')).toHaveFocus();
|
|
99
|
+
|
|
100
|
+
// Activate tab with Enter should not work on disabled tab
|
|
101
|
+
await userEvent.keyboard('{Enter}');
|
|
102
|
+
expect(query.tab('Tab 2')).toHaveFocus();
|
|
103
|
+
checkTabActive('Tab 1');
|
|
104
|
+
|
|
105
|
+
// Navigate with ArrowRight to go to the next tab (tab3)
|
|
106
|
+
await userEvent.keyboard('[ArrowRight]');
|
|
107
|
+
expect(query.tab('Tab 3')).toHaveFocus();
|
|
108
|
+
|
|
109
|
+
// Activate tab with Enter
|
|
110
|
+
await userEvent.keyboard('{Enter}');
|
|
111
|
+
expect(query.tab('Tab 3')).toHaveFocus();
|
|
112
|
+
checkTabActive('Tab 3');
|
|
113
|
+
|
|
114
|
+
// Focus next should go to active tab panel (tabPanel3)
|
|
115
|
+
await userEvent.tab();
|
|
116
|
+
expect(query.tabPanel('Tab 3')).toHaveFocus();
|
|
117
|
+
|
|
118
|
+
// Go back to tab3
|
|
119
|
+
await userEvent.tab({ shift: true });
|
|
120
|
+
expect(query.tab('Tab 3')).toHaveFocus();
|
|
121
|
+
|
|
122
|
+
// Navigate with ArrowRight to loop back to the first tab (tab1)
|
|
123
|
+
await userEvent.keyboard('[ArrowRight]');
|
|
124
|
+
expect(query.tab('Tab 1')).toHaveFocus();
|
|
125
|
+
|
|
126
|
+
// Navigate with ArrowLeft to loop back to the last tab (tab3)
|
|
127
|
+
await userEvent.keyboard('[ArrowLeft]');
|
|
128
|
+
expect(query.tab('Tab 3')).toHaveFocus();
|
|
129
|
+
|
|
130
|
+
checkTabActive('Tab 3');
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
describe('not lazy', () => {
|
|
135
|
+
it('should render tab panel everytime', () => {
|
|
136
|
+
setup({ isLazy: false });
|
|
137
|
+
// Check the first tab is active and all panel are loaded
|
|
138
|
+
checkTabActive('Tab 1', { isLazy: false });
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
describe('activate on focus', () => {
|
|
143
|
+
it('should activate tab on focus', async () => {
|
|
144
|
+
setup({ shouldActivateOnFocus: true });
|
|
145
|
+
|
|
146
|
+
checkTabActive('Tab 1');
|
|
147
|
+
|
|
148
|
+
await userEvent.tab();
|
|
149
|
+
expect(query.tab('Tab 1')).toHaveFocus();
|
|
150
|
+
checkTabActive('Tab 1');
|
|
151
|
+
|
|
152
|
+
await userEvent.keyboard('[ArrowRight]');
|
|
153
|
+
expect(query.tab('Tab 2')).toHaveFocus();
|
|
154
|
+
// Active tab not changed since tab 2 is disabled
|
|
155
|
+
checkTabActive('Tab 1');
|
|
156
|
+
|
|
157
|
+
await userEvent.keyboard('[ArrowRight]');
|
|
158
|
+
expect(query.tab('Tab 3')).toHaveFocus();
|
|
159
|
+
// Active tab changed to tab 3
|
|
160
|
+
checkTabActive('Tab 3');
|
|
40
161
|
});
|
|
41
162
|
});
|
|
42
163
|
});
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/* istanbul ignore file */
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Test util module. Do not import in production code !
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
8
|
+
import { screen, within } from '@testing-library/react';
|
|
9
|
+
|
|
10
|
+
/** RTL queries for tabs */
|
|
11
|
+
export const query = {
|
|
12
|
+
tabList: (name: string) => screen.getByRole('tablist', { name }),
|
|
13
|
+
tabs: (tabList?: any) => (tabList ? within(tabList) : screen).getAllByRole('tab'),
|
|
14
|
+
tab: (name: string, tabList?: any) => (tabList ? within(tabList) : screen).getByRole('tab', { name }),
|
|
15
|
+
tabPanel: (name: string) => screen.getByRole('tabpanel', { name }),
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
/** Assert that the given tab is active */
|
|
19
|
+
export const checkTabActive = (activeTabName: string, { isLazy = true } = {}) => {
|
|
20
|
+
for (const tab of query.tabs()) {
|
|
21
|
+
const isTabActive = tab.textContent === activeTabName;
|
|
22
|
+
|
|
23
|
+
// Tab state
|
|
24
|
+
expect(tab).toHaveAttribute('aria-selected', String(isTabActive));
|
|
25
|
+
expect(tab).toHaveAttribute('tabindex', isTabActive ? '0' : '-1');
|
|
26
|
+
|
|
27
|
+
const tabPanel = query.tabPanel(tab.textContent as string);
|
|
28
|
+
|
|
29
|
+
// Tab panel state
|
|
30
|
+
expect(tabPanel).toHaveAttribute('tabindex', isTabActive ? '0' : '-1');
|
|
31
|
+
|
|
32
|
+
if (!isTabActive && isLazy) {
|
|
33
|
+
// Tab panel content not rendered when isLazy and not active
|
|
34
|
+
expect(tabPanel).toBeEmptyDOMElement();
|
|
35
|
+
} else {
|
|
36
|
+
expect(tabPanel).not.toBeEmptyDOMElement();
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
};
|