Skip to content

Commit 8cae75e

Browse files
committed
refactor unit tests
1 parent e8d5aa3 commit 8cae75e

9 files changed

+139
-264
lines changed

__tests__/AriaLiveRegion.test.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,5 @@ test('"ariaLive" prop can be passed as one of the accepted aria-live values and
5656
const mergedProps = { ...props, ariaLive };
5757
const { container } = renderAriaLiveRegion(mergedProps);
5858
const a11yTextRootSpanEl = container.firstChild;
59-
6059
expect(a11yTextRootSpanEl).toHaveAttribute('aria-live', ariaLive);
6160
});

__tests__/AutosizeInput.test.tsx

Lines changed: 23 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -22,95 +22,65 @@ const renderAutosizeInput = (props: AutosizeInputProps) => {
2222
};
2323
};
2424

25-
const createAutosizeInputProps = () => {
26-
const onBlurSpy = jest.fn();
27-
const onFocusSpy = jest.fn();
28-
const onChangeSpy = jest.fn();
29-
30-
const props: AutosizeInputProps = {
31-
inputValue: '',
32-
readOnly: false,
33-
menuOpen: false,
34-
onBlur: onBlurSpy,
35-
onFocus: onFocusSpy,
36-
onChange: onChangeSpy,
37-
hasSelectedOptions: false
38-
};
39-
40-
return {
41-
props,
42-
onBlurSpy,
43-
onFocusSpy,
44-
onChangeSpy
45-
};
46-
};
25+
const onBlurSpy = jest.fn();
26+
const onFocusSpy = jest.fn();
27+
const onChangeSpy = jest.fn();
28+
29+
const BASE_PROPS: AutosizeInputProps = {
30+
inputValue: '',
31+
readOnly: false,
32+
menuOpen: false,
33+
onBlur: onBlurSpy,
34+
onFocus: onFocusSpy,
35+
onChange: onChangeSpy,
36+
hasSelectedOptions: false
37+
} as const;
4738

4839
// ============================================
4940
// Test cases
5041
// ============================================
5142

5243
test('input element has a static className (enables styling via classic CSS)', async () => {
53-
const { props } = createAutosizeInputProps();
54-
const { getByTestId } = renderAutosizeInput(props);
44+
const { getByTestId } = renderAutosizeInput(BASE_PROPS);
5545
expect(getByTestId(AUTOSIZE_INPUT_TESTID!)).toHaveClass(AUTOSIZE_INPUT_CLS);
5646
});
5747

5848
test('input has functional, optional ARIA attributes', async () => {
59-
const { props } = createAutosizeInputProps();
60-
61-
const mergedProps = {
62-
...props,
49+
const props = {
50+
...BASE_PROPS,
6351
ariaLabel: 'test-label',
6452
ariaLabelledBy: 'test-labelledby',
6553
};
6654

67-
const { getByTestId } = renderAutosizeInput(mergedProps);
55+
const { getByTestId } = renderAutosizeInput(props);
6856
const verifyAriaAttrs = ['aria-label', 'aria-labelledby', 'aria-autocomplete'];
6957

70-
verifyAriaAttrs.forEach((attr) => {
58+
verifyAriaAttrs.forEach((attr: string) => {
7159
expect(getByTestId(AUTOSIZE_INPUT_TESTID!)).toHaveAttribute(attr);
7260
});
7361
});
7462

7563
test('when "id" has a non-empty string value, input element should get an "id" attribute reflecting that value', async () => {
7664
const inputId = 'test-input-id';
77-
const { props } = createAutosizeInputProps();
78-
79-
const mergedProps = {
80-
...props,
81-
id: inputId,
82-
};
83-
84-
const { getByTestId } = renderAutosizeInput(mergedProps);
85-
65+
const props = { ...BASE_PROPS, id: inputId };
66+
const { getByTestId } = renderAutosizeInput(props);
8667
expect(getByTestId(AUTOSIZE_INPUT_TESTID!)).toHaveAttribute('id', inputId);
8768
});
8869

8970
test('when "readOnly" = true, the onChange event handler should not be attached to input and the "readonly" attribute is added', async () => {
90-
const { props, onChangeSpy } = createAutosizeInputProps();
91-
92-
const mergedProps = {
93-
...props,
94-
readOnly: true,
95-
};
96-
97-
const { user, getByTestId } = renderAutosizeInput(mergedProps);
71+
const props = { ...BASE_PROPS, readOnly: true };
72+
const { user, getByTestId } = renderAutosizeInput(props);
9873
const inputElement = getByTestId(AUTOSIZE_INPUT_TESTID!);
99-
10074
await user.type(inputElement, 'no change');
101-
10275
expect(onChangeSpy).not.toBeCalled();
10376
expect(inputElement).toHaveAttribute('readonly');
10477
});
10578

10679
test('"blur" and "focus" events with callback handlers are attached to the input element', async () => {
107-
const { props, onBlurSpy, onFocusSpy } = createAutosizeInputProps();
108-
const { getByTestId } = renderAutosizeInput(props);
80+
const { getByTestId } = renderAutosizeInput(BASE_PROPS);
10981
const inputElement = getByTestId(AUTOSIZE_INPUT_TESTID!);
110-
11182
fireEvent.blur(inputElement);
11283
fireEvent.focus(inputElement);
113-
11484
expect(onBlurSpy).toBeCalled();
11585
expect(onFocusSpy).toBeCalled();
11686
});

__tests__/IndicatorIcons.test.tsx

Lines changed: 31 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -22,23 +22,15 @@ const renderIndicatorIcons = (props: IndicatorIconsProps) => {
2222
};
2323
};
2424

25-
const createIndicatorIconsProps = () => {
26-
const onClearMouseDownSpy = jest.fn();
27-
const onCaretMouseDownSpy = jest.fn();
28-
29-
const props: IndicatorIconsProps = {
30-
menuOpen: false,
31-
showClear: true,
32-
onClearMouseDown: onClearMouseDownSpy,
33-
onCaretMouseDown: onCaretMouseDownSpy
34-
};
25+
const onClearMouseDownSpy = jest.fn();
26+
const onCaretMouseDownSpy = jest.fn();
3527

36-
return {
37-
props,
38-
onClearMouseDownSpy,
39-
onCaretMouseDownSpy
40-
};
41-
};
28+
const BASE_PROPS: IndicatorIconsProps = {
29+
menuOpen: false,
30+
showClear: true,
31+
onClearMouseDown: onClearMouseDownSpy,
32+
onCaretMouseDown: onCaretMouseDownSpy
33+
} as const;
4234

4335
const customIconFn = (props: Partial<IndicatorIconsProps>): ReactNode => {
4436
const { menuOpen, isLoading, isInvalid, isDisabled } = props;
@@ -56,95 +48,82 @@ const customIconFn = (props: Partial<IndicatorIconsProps>): ReactNode => {
5648
// ============================================
5749

5850
test('clear icon has a static className (enables styling via classic CSS)', async () => {
59-
const { props } = createIndicatorIconsProps();
60-
const { getByTestId } = renderIndicatorIcons(props);
51+
const { getByTestId } = renderIndicatorIcons(BASE_PROPS);
6152
const firstChildOfClearIconElement = getByTestId(CLEAR_ICON_TESTID!).firstChild;
6253
expect(firstChildOfClearIconElement).toHaveClass(CLEAR_ICON_CLS);
6354
});
6455

6556
test('clear indicator has functioning "click" user interactions', async () => {
66-
const { props, onClearMouseDownSpy } = createIndicatorIconsProps();
67-
const { user, getByTestId } = renderIndicatorIcons(props);
57+
const { user, getByTestId } = renderIndicatorIcons(BASE_PROPS);
6858
const clearIndicatorEl = getByTestId(CLEAR_ICON_TESTID!);
69-
7059
await user.click(clearIndicatorEl);
71-
7260
expect(onClearMouseDownSpy).toBeCalled();
7361
});
7462

7563
test('caret indicator has functioning "click" user interactions', async () => {
76-
const { props, onCaretMouseDownSpy } = createIndicatorIconsProps();
77-
const { user, getByTestId } = renderIndicatorIcons(props);
64+
const { user, getByTestId } = renderIndicatorIcons(BASE_PROPS);
7865
const caretIndicatorEl = getByTestId(CARET_ICON_TESTID!);
79-
8066
await user.click(caretIndicatorEl);
81-
8267
expect(onCaretMouseDownSpy).toBeCalled();
8368
});
8469

8570
test('clear icon is not rendered and loading animation is rendered when "isLoading" = true', async () => {
86-
const { props } = createIndicatorIconsProps();
87-
const mergedProps = { ...props, isLoading: true };
88-
const { queryByTestId } = renderIndicatorIcons(mergedProps);
71+
const props = { ...BASE_PROPS, isLoading: true };
72+
const { queryByTestId } = renderIndicatorIcons(props);
8973
expect(queryByTestId(CLEAR_ICON_TESTID!)).toBeNull();
9074
});
9175

9276
test('loading can render as a custom node (instead of default LoadingDots.tsx component)', async () => {
9377
const loadingNodeText = 'loading-node';
9478
const loadingNode = <span>{loadingNodeText}</span>;
95-
const { props } = createIndicatorIconsProps();
9679

97-
const mergedProps = {
98-
...props,
80+
const props = {
81+
...BASE_PROPS,
9982
loadingNode,
10083
isLoading: true,
10184
};
10285

103-
const { getByText } = renderIndicatorIcons(mergedProps);
104-
86+
const { getByText } = renderIndicatorIcons(props);
10587
expect(getByText(loadingNodeText)).toBeInTheDocument();
10688
});
10789

10890
test('clear icon can render as a ReactNode', async () => {
10991
const clearIconText = 'clear-icon-node';
11092
const clearIcon = <span>{clearIconText}</span>;
111-
const { props } = createIndicatorIconsProps();
112-
const mergedProps = { ...props, clearIcon };
113-
const { getByText } = renderIndicatorIcons(mergedProps);
114-
93+
const props = { ...BASE_PROPS, clearIcon };
94+
const { getByText } = renderIndicatorIcons(props);
11595
expect(getByText(clearIconText)).toBeInTheDocument();
11696
});
11797

11898
test('clear icon can render as a callback function with return type of ReactNode - callback accepts forwarded state props from wrapping component.', async () => {
119-
const { props } = createIndicatorIconsProps();
120-
const mergedProps = { ...props, menuOpen: true, clearIcon: customIconFn };
121-
const { getByTestId } = renderIndicatorIcons(mergedProps);
99+
const props = {
100+
...BASE_PROPS,
101+
menuOpen: true,
102+
clearIcon: customIconFn
103+
};
104+
105+
const { getByTestId } = renderIndicatorIcons(props);
122106

123107
// Build test-id from forwarded state javascript object payload
124-
const { menuOpen, isLoading, isInvalid, isDisabled } = mergedProps;
108+
const { menuOpen, isLoading, isInvalid, isDisabled } = props;
125109
const forwardedStateId = `${menuOpen}-${isLoading}-${isInvalid}-${isDisabled}`
126-
127110
expect(getByTestId(forwardedStateId)).toBeInTheDocument();
128111
});
129112

130113
test('caret icon can render as a ReactNode', async () => {
131114
const caretIconText = 'caret-icon-node';
132115
const caretIcon = <span>{caretIconText}</span>;
133-
const { props } = createIndicatorIconsProps();
134-
const mergedProps = { ...props, caretIcon };
135-
const { getByText } = renderIndicatorIcons(mergedProps);
136-
116+
const props = { ...BASE_PROPS, caretIcon };
117+
const { getByText } = renderIndicatorIcons(props);
137118
expect(getByText(caretIconText)).toBeInTheDocument();
138119
});
139120

140121
test('caret icon can render as a callback function with return type of ReactNode - callback accepts forwarded state props from wrapping component.', async () => {
141-
const { props } = createIndicatorIconsProps();
142-
const mergedProps = { ...props, menuOpen: true, caretIcon: customIconFn };
143-
const { getByTestId } = renderIndicatorIcons(mergedProps);
122+
const props = { ...BASE_PROPS, menuOpen: true, caretIcon: customIconFn };
123+
const { getByTestId } = renderIndicatorIcons(props);
144124

145125
// Build test-id from forwarded state javascript object payload
146-
const { menuOpen, isLoading, isInvalid, isDisabled } = mergedProps;
126+
const { menuOpen, isLoading, isInvalid, isDisabled } = props;
147127
const forwardedStateId = `${menuOpen}-${isLoading}-${isInvalid}-${isDisabled}`
148-
149128
expect(getByTestId(forwardedStateId)).toBeInTheDocument();
150129
});

__tests__/MenuList.test.tsx

Lines changed: 28 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { ThemeTestHOC } from './helpers';
33
import type { MenuOption } from '../src';
44
import { render } from '@testing-library/react';
55
import MenuList from '../src/components/Menu/MenuList';
6-
import { MENU_OPTIONS, RENDER_OPTION_LABEL_MOCK } from './helpers/utils';
6+
import { MENU_OPTIONS, renderOptionLabelMock } from './helpers/utils';
77
import {
88
MENU_ITEM_SIZE_DEFAULT,
99
MENU_MAX_HEIGHT_DEFAULT,
@@ -26,75 +26,62 @@ const renderMenuList = (props: MenuListProps) => {
2626
);
2727
};
2828

29-
const createMenuListProps = (menuOptions: MenuOption[] = []): MenuListProps => {
30-
const selectOption = jest.fn();
31-
const renderOptionLabel = RENDER_OPTION_LABEL_MOCK;
32-
const { index: focusedOptionIndex } = FOCUSED_OPTION_DEFAULT;
33-
34-
return {
35-
menuOptions,
36-
selectOption,
37-
width: '100%',
38-
renderOptionLabel,
39-
focusedOptionIndex,
40-
memoOptions: false,
41-
itemKeySelector: undefined,
42-
fixedSizeListRef: undefined,
43-
height: MENU_MAX_HEIGHT_DEFAULT,
44-
loadingMsg: LOADING_MSG_DEFAULT,
45-
itemSize: MENU_ITEM_SIZE_DEFAULT,
46-
noOptionsMsg: NO_OPTIONS_MSG_DEFAULT
47-
};
48-
};
29+
const BASE_PROPS: MenuListProps = {
30+
width: '100%',
31+
memoOptions: false,
32+
menuOptions: MENU_OPTIONS,
33+
itemKeySelector: undefined,
34+
fixedSizeListRef: undefined,
35+
height: MENU_MAX_HEIGHT_DEFAULT,
36+
loadingMsg: LOADING_MSG_DEFAULT,
37+
itemSize: MENU_ITEM_SIZE_DEFAULT,
38+
noOptionsMsg: NO_OPTIONS_MSG_DEFAULT,
39+
selectOption: jest.fn(),
40+
renderOptionLabel: renderOptionLabelMock,
41+
focusedOptionIndex: FOCUSED_OPTION_DEFAULT.index
42+
} as const;
4943

5044
// ============================================
5145
// Test cases
5246
// ============================================
5347

5448
test('MenuList component mounts and renders successfully when "menuOptions" array has items', async () => {
55-
const props = createMenuListProps(MENU_OPTIONS);
56-
const { getByText } = renderMenuList(props);
49+
const { getByText } = renderMenuList(BASE_PROPS);
5750

5851
// Assert react-window + Option.tsx renders each menuOption correctly
59-
MENU_OPTIONS.forEach(({ label }: MenuOption) => {
52+
BASE_PROPS.menuOptions.forEach(({ label }: MenuOption) => {
6053
expect(getByText(String(label))).toBeInTheDocument();
6154
});
6255
});
6356

6457
test('The "itemKeySelector" property is used in "react-window" function property "itemKey" to select unqiue key based on property value rather than using default index for each option', async () => {
65-
const props = {
66-
...createMenuListProps(MENU_OPTIONS),
67-
itemKeySelector: 'value'
68-
};
69-
58+
const props = { ...BASE_PROPS, itemKeySelector: 'value' };
7059
const { getByText } = renderMenuList(props);
7160

7261
// Assert react-window + Option.tsx renders each menuOption correctly
73-
MENU_OPTIONS.forEach(({ label }: MenuOption) => {
62+
props.menuOptions.forEach(({ label }: MenuOption) => {
7463
expect(getByText(String(label))).toBeInTheDocument();
7564
});
7665
});
7766

7867
test('The "No Options" message element is NOT rendered when "menuOptions" length > 0', async () => {
79-
const props = createMenuListProps(MENU_OPTIONS);
80-
const { queryByText } = renderMenuList(props);
81-
expect(queryByText(props.noOptionsMsg!)).toBeNull();
68+
const { queryByText } = renderMenuList(BASE_PROPS);
69+
expect(queryByText(BASE_PROPS.noOptionsMsg!)).toBeNull();
8270
});
8371

84-
test('The "No Options" message element is rendered when "menuOptions" length = 0', async () => {
85-
const props = createMenuListProps();
72+
test('The "No Options" message element is rendered when "menuOptions" length === 0', async () => {
73+
const props = { ...BASE_PROPS, menuOptions: [] };
8674
const { getByText } = renderMenuList(props);
8775
expect(getByText(props.noOptionsMsg!)).toBeInTheDocument();
8876
});
8977

90-
test('The "Loading" message element is NOT rendered when "isLoading" != true', async () => {
91-
const props = createMenuListProps();
92-
const { queryByText } = renderMenuList(props);
93-
expect(queryByText(props.loadingMsg)).toBeNull();
78+
test('The "Loading" message element is NOT rendered when "isLoading" !== true', async () => {
79+
const { queryByText } = renderMenuList(BASE_PROPS);
80+
expect(queryByText(BASE_PROPS.loadingMsg)).toBeNull();
9481
});
9582

96-
test('The "Loading" message element is rendered when "isLoading" = true', async () => {
97-
const props = { isLoading: true, ...createMenuListProps() };
83+
test('The "Loading" message element is rendered when "isLoading" === true', async () => {
84+
const props = { ...BASE_PROPS, isLoading: true };
9885
const { getByText } = renderMenuList(props);
9986
expect(getByText(props.loadingMsg)).toBeInTheDocument();
10087
});

0 commit comments

Comments
 (0)