Skip to content

Commit e41b09a

Browse files
chore(List): updated unit tests (#11738)
* chore(List): updated unit tests * Added tests for ListItem
1 parent 9e9f965 commit e41b09a

File tree

9 files changed

+198
-391
lines changed

9 files changed

+198
-391
lines changed

packages/react-core/src/components/List/List.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,14 @@ export const List: React.FunctionComponent<ListProps> = ({
4949
type = OrderType.number,
5050
ref = null,
5151
component = ListComponent.ul,
52+
'aria-label': ariaLabel,
5253
...props
5354
}: ListProps) =>
5455
component === ListComponent.ol ? (
5556
<ol
5657
ref={ref as React.Ref<HTMLOListElement>}
5758
type={type}
59+
aria-label={ariaLabel}
5860
{...(isPlain && { role: 'list' })}
5961
{...props}
6062
className={css(
@@ -71,6 +73,7 @@ export const List: React.FunctionComponent<ListProps> = ({
7173
) : (
7274
<ul
7375
ref={ref as React.Ref<HTMLUListElement>}
76+
aria-label={ariaLabel}
7477
{...(isPlain && { role: 'list' })}
7578
{...props}
7679
className={css(

packages/react-core/src/components/List/ListItem.tsx

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,21 @@ import styles from '@patternfly/react-styles/css/components/List/list';
22
import { css } from '@patternfly/react-styles';
33

44
export interface ListItemProps extends React.HTMLProps<HTMLLIElement> {
5-
/** Icon for the list item */
6-
icon?: React.ReactNode | null;
5+
/** Additional classes added to the list item */
6+
className?: string;
77
/** Anything that can be rendered inside of list item */
88
children: React.ReactNode;
9+
/** Icon for the list item */
10+
icon?: React.ReactNode | null;
911
}
1012

1113
export const ListItem: React.FunctionComponent<ListItemProps> = ({
12-
icon = null,
14+
className,
1315
children = null,
16+
icon = null,
1417
...props
1518
}: ListItemProps) => (
16-
<li className={css(icon && styles.listItem)} {...props}>
19+
<li className={css(icon && styles.listItem, className)} {...props}>
1720
{icon && <span className={css(styles.listItemIcon)}>{icon}</span>}
1821
<span className={icon && css(`${styles.list}__item-text`)}>{children}</span>
1922
</li>

packages/react-core/src/components/List/__tests__/Generated/ListItem.test.tsx

Lines changed: 0 additions & 12 deletions
This file was deleted.

packages/react-core/src/components/List/__tests__/Generated/__snapshots__/ListItem.test.tsx.snap

Lines changed: 0 additions & 13 deletions
This file was deleted.
Lines changed: 97 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -1,117 +1,113 @@
11
import { render, screen } from '@testing-library/react';
2-
3-
import BookOpen from '@patternfly/react-icons/dist/esm/icons/book-open-icon';
4-
import Key from '@patternfly/react-icons/dist/esm/icons/key-icon';
5-
import Desktop from '@patternfly/react-icons/dist/esm/icons/desktop-icon';
62
import { List, ListVariant, ListComponent, OrderType } from '../List';
7-
import { ListItem } from '../ListItem';
8-
9-
const ListItems = () => (
10-
<List>
11-
<ListItem>First</ListItem>
12-
<ListItem>Second</ListItem>
13-
<ListItem>Third</ListItem>
14-
</List>
15-
);
16-
17-
describe('List', () => {
18-
test('simple list', () => {
19-
const { asFragment } = render(
20-
<List>
21-
<ListItems />
22-
</List>
23-
);
24-
expect(asFragment()).toMatchSnapshot();
25-
});
3+
import styles from '@patternfly/react-styles/css/components/List/list';
264

27-
test('inline list', () => {
28-
const { asFragment } = render(
29-
<List variant={ListVariant.inline}>
30-
<ListItems />
31-
</List>
32-
);
33-
expect(asFragment()).toMatchSnapshot();
34-
});
5+
describe('Shared tests between ol and ul lists', () => {
6+
Object.values(ListComponent).forEach((component) => {
7+
test(`Renders without children for ${component} list`, () => {
8+
render(<List component={component}></List>);
359

36-
test('ordered list', () => {
37-
const { asFragment } = render(
38-
<List component={ListComponent.ol}>
39-
<ListItem>Apple</ListItem>
40-
<ListItem>Banana</ListItem>
41-
<ListItem>Orange</ListItem>
42-
</List>
43-
);
44-
expect(asFragment()).toMatchSnapshot();
45-
});
10+
expect(screen.getByRole('list')).toBeVisible();
11+
});
4612

47-
test('ordered list starts with 2nd item', () => {
48-
render(
49-
<List component={ListComponent.ol} start={2}>
50-
<ListItem>Banana</ListItem>
51-
<ListItem>Orange</ListItem>
52-
</List>
53-
);
54-
expect(screen.getByRole('list')).toHaveAttribute('start', '2');
55-
});
13+
test(`Renders children for ${component} list`, () => {
14+
render(<List component={component}>Children content</List>);
5615

57-
test('ordered list items will be numbered with uppercase letters', () => {
58-
render(
59-
<List component={ListComponent.ol} type={OrderType.uppercaseLetter}>
60-
<ListItem>Banana</ListItem>
61-
<ListItem>Orange</ListItem>
62-
</List>
63-
);
64-
expect(screen.getByRole('list')).toHaveAttribute('type', 'A');
65-
});
16+
expect(screen.getByRole('list')).toHaveTextContent('Children content');
17+
});
6618

67-
test('inlined ordered list', () => {
68-
render(
69-
<List variant={ListVariant.inline} component={ListComponent.ol}>
70-
<ListItem>Apple</ListItem>
71-
<ListItem>Banana</ListItem>
72-
<ListItem>Orange</ListItem>
73-
</List>
74-
);
75-
expect(screen.getByRole('list')).toHaveClass('pf-m-inline');
76-
});
19+
test(`Renders with ${component} tag`, () => {
20+
render(<List component={component}></List>);
21+
22+
expect(screen.getByRole('list').tagName).toBe(component.toUpperCase());
23+
});
24+
25+
test(`Renders with only class ${styles.list} by default for ${component} list`, () => {
26+
render(<List component={component}></List>);
27+
28+
expect(screen.getByRole('list')).toHaveClass(styles.list, { exact: true });
29+
});
30+
31+
test(`Renders with custom class when className is passed for ${component} list`, () => {
32+
render(<List component={component} className="custom-class"></List>);
33+
34+
expect(screen.getByRole('list')).toHaveClass('custom-class');
35+
});
36+
37+
test(`Renders with variant class ${styles.modifiers.inline} when variant prop is inline for ${component} list`, () => {
38+
render(<List component={component} variant={ListVariant.inline}></List>);
39+
40+
expect(screen.getByRole('list')).toHaveClass(styles.modifiers.inline);
41+
});
42+
43+
test(`Renders with class ${styles.modifiers.bordered} when isBordered is true for ${component} list`, () => {
44+
render(<List component={component} isBordered></List>);
45+
46+
expect(screen.getByRole('list')).toHaveClass(styles.modifiers.bordered);
47+
});
48+
49+
test(`Renders with class ${styles.modifiers.plain} when isPlain is true for ${component} list`, () => {
50+
render(<List component={component} isPlain></List>);
7751

78-
test('bordered list', () => {
79-
render(
80-
<List isBordered>
81-
<ListItems />
82-
</List>
83-
);
84-
expect(screen.getAllByRole('list')[0]).toHaveClass('pf-m-bordered');
52+
expect(screen.getByRole('list')).toHaveClass(styles.modifiers.plain);
53+
});
54+
55+
test(`Renders with class ${styles.modifiers.iconLg} when iconSize is "large" for ${component} list`, () => {
56+
render(<List component={component} iconSize="large"></List>);
57+
58+
expect(screen.getByRole('list')).toHaveClass(styles.modifiers.iconLg);
59+
});
60+
61+
test(`Renders with aria-label for ${component} list`, () => {
62+
render(<List component={component} aria-label="Testing stuff"></List>);
63+
64+
expect(screen.getByRole('list')).toHaveAccessibleName('Testing stuff');
65+
});
66+
67+
test(`Spreads additional props when passed for ${component} list`, () => {
68+
render(<List component={component} id="Test ID"></List>);
69+
70+
expect(screen.getByRole('list')).toHaveAttribute('id', 'Test ID');
71+
});
72+
73+
test(`Does not render with role attribute when isPlain is false for ${component} list`, () => {
74+
render(<List component={component}></List>);
75+
76+
expect(screen.getByRole('list')).not.toHaveAttribute('role');
77+
});
78+
79+
test(`Renders with role attribute of "list" when isPlain is true for ${component} list`, () => {
80+
render(<List component={component} isPlain></List>);
81+
82+
expect(screen.getByRole('list')).toHaveAttribute('role', 'list');
83+
});
84+
85+
test(`Matches snapshot for ${component} list`, () => {
86+
const { asFragment } = render(<List component={component}></List>);
87+
88+
expect(asFragment()).toMatchSnapshot();
89+
});
8590
});
91+
});
92+
93+
describe('Ol component list', () => {
94+
test(`Renders with type of "1" by default`, () => {
95+
render(<List component={ListComponent.ol}></List>);
8696

87-
test('plain list', () => {
88-
render(
89-
<List isPlain>
90-
<ListItems />
91-
</List>
92-
);
93-
expect(screen.getAllByRole('list')[0]).toHaveClass('pf-m-plain');
97+
expect(screen.getByRole('list')).toHaveAttribute('type', '1');
9498
});
9599

96-
test('icon list', () => {
97-
const { asFragment } = render(
98-
<List isPlain>
99-
<ListItem icon={<BookOpen />}>Apple</ListItem>
100-
<ListItem icon={<Key />}>Banana</ListItem>
101-
<ListItem icon={<Desktop />}>Orange</ListItem>
102-
</List>
103-
);
104-
expect(asFragment()).toMatchSnapshot();
100+
test(`Renders with type attribute when type is passed`, () => {
101+
render(<List component={ListComponent.ol} type={OrderType.uppercaseLetter}></List>);
102+
103+
expect(screen.getByRole('list')).toHaveAttribute('type', 'A');
105104
});
105+
});
106+
107+
describe('Ul component list', () => {
108+
test(`Does not render with type attribute when type is passed`, () => {
109+
render(<List type={OrderType.lowercaseRomanNumber}></List>);
106110

107-
test('icon large list', () => {
108-
const { asFragment } = render(
109-
<List iconSize="large">
110-
<ListItem icon={<BookOpen />}>Apple</ListItem>
111-
<ListItem icon={<Key />}>Banana</ListItem>
112-
<ListItem icon={<Desktop />}>Orange</ListItem>
113-
</List>
114-
);
115-
expect(asFragment()).toMatchSnapshot();
111+
expect(screen.getByRole('list')).not.toHaveAttribute('type');
116112
});
117113
});
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { render, screen } from '@testing-library/react';
2+
import { ListItem } from '../ListItem';
3+
import styles from '@patternfly/react-styles/css/components/List/list';
4+
5+
test('Renders with children', () => {
6+
render(<ListItem>List item content</ListItem>);
7+
8+
expect(screen.getByRole('listitem')).toHaveTextContent('List item content');
9+
});
10+
11+
test(`Does not render with a class by default`, () => {
12+
render(<ListItem>List item content</ListItem>);
13+
14+
expect(screen.getByRole('listitem')).not.toHaveClass();
15+
});
16+
17+
test(`Renders with custom class when className is passed`, () => {
18+
render(<ListItem className="test-class">List item content</ListItem>);
19+
20+
expect(screen.getByRole('listitem')).toHaveClass('test-class', { exact: true });
21+
});
22+
23+
test(`Renders with icon content when icon prop is passed`, () => {
24+
render(<ListItem icon={<div>Icon content</div>}>List item content</ListItem>);
25+
26+
expect(screen.getByRole('listitem')).toContainHTML('<div>Icon content</div>');
27+
});
28+
29+
test(`Renders with class ${styles.listItem} when icon prop is passed`, () => {
30+
render(<ListItem icon={<div>Icon content</div>}>List item content</ListItem>);
31+
32+
expect(screen.getByRole('listitem')).toHaveClass(styles.listItem, { exact: true });
33+
});
34+
35+
test(`Spreads additional props when passed`, () => {
36+
render(<ListItem id="test-ID">List item content</ListItem>);
37+
38+
expect(screen.getByRole('listitem')).toHaveAttribute('id', 'test-ID');
39+
});
40+
41+
test('Matches snapshot without icon', () => {
42+
const { asFragment } = render(<ListItem>List item content</ListItem>);
43+
44+
expect(asFragment()).toMatchSnapshot();
45+
});
46+
47+
test('Matches snapshot with icon', () => {
48+
const { asFragment } = render(<ListItem icon={<div>Icon content</div>}>List item content</ListItem>);
49+
50+
expect(asFragment()).toMatchSnapshot();
51+
});

0 commit comments

Comments
 (0)