From 3da3d94c267f0da175ad786d4702e888a573b250 Mon Sep 17 00:00:00 2001 From: Eric Olkowski Date: Thu, 3 Apr 2025 08:44:59 -0400 Subject: [PATCH 1/2] chore(List): updated unit tests --- .../react-core/src/components/List/List.tsx | 3 + .../components/List/__tests__/List.test.tsx | 194 ++++++------- .../__snapshots__/List.test.tsx.snap | 265 +----------------- test.setup.ts | 2 + 4 files changed, 101 insertions(+), 363 deletions(-) create mode 100644 test.setup.ts diff --git a/packages/react-core/src/components/List/List.tsx b/packages/react-core/src/components/List/List.tsx index d76842de30d..a57b58aa283 100644 --- a/packages/react-core/src/components/List/List.tsx +++ b/packages/react-core/src/components/List/List.tsx @@ -49,12 +49,14 @@ export const List: React.FunctionComponent = ({ type = OrderType.number, ref = null, component = ListComponent.ul, + 'aria-label': ariaLabel, ...props }: ListProps) => component === ListComponent.ol ? (
    } type={type} + aria-label={ariaLabel} {...(isPlain && { role: 'list' })} {...props} className={css( @@ -71,6 +73,7 @@ export const List: React.FunctionComponent = ({ ) : (
      } + aria-label={ariaLabel} {...(isPlain && { role: 'list' })} {...props} className={css( diff --git a/packages/react-core/src/components/List/__tests__/List.test.tsx b/packages/react-core/src/components/List/__tests__/List.test.tsx index c9e13bea094..8140078eb6d 100644 --- a/packages/react-core/src/components/List/__tests__/List.test.tsx +++ b/packages/react-core/src/components/List/__tests__/List.test.tsx @@ -1,117 +1,107 @@ import { render, screen } from '@testing-library/react'; - -import BookOpen from '@patternfly/react-icons/dist/esm/icons/book-open-icon'; -import Key from '@patternfly/react-icons/dist/esm/icons/key-icon'; -import Desktop from '@patternfly/react-icons/dist/esm/icons/desktop-icon'; import { List, ListVariant, ListComponent, OrderType } from '../List'; -import { ListItem } from '../ListItem'; - -const ListItems = () => ( - - First - Second - Third - -); - -describe('List', () => { - test('simple list', () => { - const { asFragment } = render( - - - - ); - expect(asFragment()).toMatchSnapshot(); - }); +import styles from '@patternfly/react-styles/css/components/List/list'; - test('inline list', () => { - const { asFragment } = render( - - - - ); - expect(asFragment()).toMatchSnapshot(); - }); +describe('Shared tests between ol and ul lists', () => { + Object.values(ListComponent).forEach((component) => { + test(`Renders without children for ${component} list`, () => { + render(); - test('ordered list', () => { - const { asFragment } = render( - - Apple - Banana - Orange - - ); - expect(asFragment()).toMatchSnapshot(); - }); + expect(screen.getByRole('list')).toBeVisible(); + }); - test('ordered list starts with 2nd item', () => { - render( - - Banana - Orange - - ); - expect(screen.getByRole('list')).toHaveAttribute('start', '2'); - }); + test(`Renders children for ${component} list`, () => { + render(Children content); - test('ordered list items will be numbered with uppercase letters', () => { - render( - - Banana - Orange - - ); - expect(screen.getByRole('list')).toHaveAttribute('type', 'A'); - }); + expect(screen.getByRole('list')).toHaveTextContent('Children content'); + }); - test('inlined ordered list', () => { - render( - - Apple - Banana - Orange - - ); - expect(screen.getByRole('list')).toHaveClass('pf-m-inline'); - }); + test(`Renders with ${component} tag`, () => { + render(); - test('bordered list', () => { - render( - - - - ); - expect(screen.getAllByRole('list')[0]).toHaveClass('pf-m-bordered'); - }); + expect(screen.getByRole('list').tagName).toBe(component.toUpperCase()); + }); + + test(`Renders with only class ${styles.list} by default for ${component} list`, () => { + render(); + + expect(screen.getByRole('list')).toHaveClass(styles.list, { exact: true }); + }); + + test(`Renders with custom class when className is passed for ${component} list`, () => { + render(); + + expect(screen.getByRole('list')).toHaveClass('custom-class'); + }); + + test(`Renders with variant class ${styles.modifiers.inline} when variant prop is inline for ${component} list`, () => { + render(); + + expect(screen.getByRole('list')).toHaveClass(styles.modifiers.inline); + }); + + test(`Renders with class ${styles.modifiers.bordered} when isBordered is true for ${component} list`, () => { + render(); + + expect(screen.getByRole('list')).toHaveClass(styles.modifiers.bordered); + }); + + test(`Renders with class ${styles.modifiers.plain} when isPlain is true for ${component} list`, () => { + render(); - test('plain list', () => { - render( - - - - ); - expect(screen.getAllByRole('list')[0]).toHaveClass('pf-m-plain'); + expect(screen.getByRole('list')).toHaveClass(styles.modifiers.plain); + }); + + test(`Renders with class ${styles.modifiers.iconLg} when iconSize is "large" for ${component} list`, () => { + render(); + + expect(screen.getByRole('list')).toHaveClass(styles.modifiers.iconLg); + }); + + test(`Renders with aria-label for ${component} list`, () => { + render(); + + expect(screen.getByRole('list')).toHaveAccessibleName('Testing stuff'); + }); + + test(`Renders with spread props for ${component} list`, () => { + render(); + + expect(screen.getByRole('list')).toHaveAttribute('id', 'Test ID'); + }); + + test(`Does not render with role attribute when isPlain is false for ${component} list`, () => { + render(); + + expect(screen.getByRole('list')).not.toHaveAttribute('role'); + }); + + test(`Renders with role attribute of "list" when isPlain is true for ${component} list`, () => { + render(); + + expect(screen.getByRole('list')).toHaveAttribute('role', 'list'); + }); + + test(`Matches snapshot for ${component} list`, () => { + const { asFragment } = render(); + + expect(asFragment()).toMatchSnapshot(); + }); }); +}); + +describe('Ol component list', () => { + test(`Renders with type attribute when type is passed`, () => { + render(); - test('icon list', () => { - const { asFragment } = render( - - }>Apple - }>Banana - }>Orange - - ); - expect(asFragment()).toMatchSnapshot(); + expect(screen.getByRole('list')).toHaveAttribute('type', 'i'); }); +}); + +describe('Ul component list', () => { + test(`Does not render with type attribute when type is passed`, () => { + render(); - test('icon large list', () => { - const { asFragment } = render( - - }>Apple - }>Banana - }>Orange - - ); - expect(asFragment()).toMatchSnapshot(); + expect(screen.getByRole('list')).not.toHaveAttribute('type'); }); }); diff --git a/packages/react-core/src/components/List/__tests__/__snapshots__/List.test.tsx.snap b/packages/react-core/src/components/List/__tests__/__snapshots__/List.test.tsx.snap index 1a3a92f7f23..fc1261ba44f 100644 --- a/packages/react-core/src/components/List/__tests__/__snapshots__/List.test.tsx.snap +++ b/packages/react-core/src/components/List/__tests__/__snapshots__/List.test.tsx.snap @@ -1,275 +1,18 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`List icon large list 1`] = ` - -
        -
      • - - - - - Apple - -
      • -
      • - - - - - Banana - -
      • -
      • - - - - - Orange - -
      • -
      -
      -`; - -exports[`List icon list 1`] = ` - -
        -
      • - - - - - Apple - -
      • -
      • - - - - - Banana - -
      • -
      • - - - - - Orange - -
      • -
      -
      -`; - -exports[`List inline list 1`] = ` - -
        -
          -
        • - - First - -
        • -
        • - - Second - -
        • -
        • - - Third - -
        • -
        -
      -
      -`; - -exports[`List ordered list 1`] = ` +exports[`Shared tests between ol and ul lists Matches snapshot for ol list 1`] = `
        -
      1. - - Apple - -
      2. -
      3. - - Banana - -
      4. -
      5. - - Orange - -
      6. -
      + />
      `; -exports[`List simple list 1`] = ` +exports[`Shared tests between ol and ul lists Matches snapshot for ul list 1`] = `
        -
          -
        • - - First - -
        • -
        • - - Second - -
        • -
        • - - Third - -
        • -
        -
      + />
      `; diff --git a/test.setup.ts b/test.setup.ts new file mode 100644 index 00000000000..52b79e9723a --- /dev/null +++ b/test.setup.ts @@ -0,0 +1,2 @@ +// Add custom jest matchers from jest-dom +import '@testing-library/jest-dom'; From 5d9be8d4305feb6fcee06590cef594271c74cd78 Mon Sep 17 00:00:00 2001 From: Eric Olkowski Date: Thu, 3 Apr 2025 09:17:23 -0400 Subject: [PATCH 2/2] Added tests for ListItem --- .../src/components/List/ListItem.tsx | 11 ++-- .../__tests__/Generated/ListItem.test.tsx | 12 ----- .../__snapshots__/ListItem.test.tsx.snap | 13 ----- .../components/List/__tests__/List.test.tsx | 12 +++-- .../List/__tests__/ListItem.test.tsx | 51 +++++++++++++++++++ .../__snapshots__/ListItem.test.tsx.snap | 34 +++++++++++++ 6 files changed, 101 insertions(+), 32 deletions(-) delete mode 100644 packages/react-core/src/components/List/__tests__/Generated/ListItem.test.tsx delete mode 100644 packages/react-core/src/components/List/__tests__/Generated/__snapshots__/ListItem.test.tsx.snap create mode 100644 packages/react-core/src/components/List/__tests__/ListItem.test.tsx create mode 100644 packages/react-core/src/components/List/__tests__/__snapshots__/ListItem.test.tsx.snap diff --git a/packages/react-core/src/components/List/ListItem.tsx b/packages/react-core/src/components/List/ListItem.tsx index e9b0e86301d..993c2ea97e4 100644 --- a/packages/react-core/src/components/List/ListItem.tsx +++ b/packages/react-core/src/components/List/ListItem.tsx @@ -2,18 +2,21 @@ import styles from '@patternfly/react-styles/css/components/List/list'; import { css } from '@patternfly/react-styles'; export interface ListItemProps extends React.HTMLProps { - /** Icon for the list item */ - icon?: React.ReactNode | null; + /** Additional classes added to the list item */ + className?: string; /** Anything that can be rendered inside of list item */ children: React.ReactNode; + /** Icon for the list item */ + icon?: React.ReactNode | null; } export const ListItem: React.FunctionComponent = ({ - icon = null, + className, children = null, + icon = null, ...props }: ListItemProps) => ( -
    • +
    • {icon && {icon}} {children}
    • diff --git a/packages/react-core/src/components/List/__tests__/Generated/ListItem.test.tsx b/packages/react-core/src/components/List/__tests__/Generated/ListItem.test.tsx deleted file mode 100644 index 9eb4309f382..00000000000 --- a/packages/react-core/src/components/List/__tests__/Generated/ListItem.test.tsx +++ /dev/null @@ -1,12 +0,0 @@ -/** - * This test was generated - */ -import { render } from '@testing-library/react'; -import { ListItem } from '../../ListItem'; -// any missing imports can usually be resolved by adding them here -import {} from '../..'; - -it('ListItem should match snapshot (auto-generated)', () => { - const { asFragment } = render(ReactNode} />); - expect(asFragment()).toMatchSnapshot(); -}); diff --git a/packages/react-core/src/components/List/__tests__/Generated/__snapshots__/ListItem.test.tsx.snap b/packages/react-core/src/components/List/__tests__/Generated/__snapshots__/ListItem.test.tsx.snap deleted file mode 100644 index 432ecd7f726..00000000000 --- a/packages/react-core/src/components/List/__tests__/Generated/__snapshots__/ListItem.test.tsx.snap +++ /dev/null @@ -1,13 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`ListItem should match snapshot (auto-generated) 1`] = ` - -
    • - - ReactNode - -
    • -
      -`; diff --git a/packages/react-core/src/components/List/__tests__/List.test.tsx b/packages/react-core/src/components/List/__tests__/List.test.tsx index 8140078eb6d..3193f31622d 100644 --- a/packages/react-core/src/components/List/__tests__/List.test.tsx +++ b/packages/react-core/src/components/List/__tests__/List.test.tsx @@ -64,7 +64,7 @@ describe('Shared tests between ol and ul lists', () => { expect(screen.getByRole('list')).toHaveAccessibleName('Testing stuff'); }); - test(`Renders with spread props for ${component} list`, () => { + test(`Spreads additional props when passed for ${component} list`, () => { render(); expect(screen.getByRole('list')).toHaveAttribute('id', 'Test ID'); @@ -91,10 +91,16 @@ describe('Shared tests between ol and ul lists', () => { }); describe('Ol component list', () => { + test(`Renders with type of "1" by default`, () => { + render(); + + expect(screen.getByRole('list')).toHaveAttribute('type', '1'); + }); + test(`Renders with type attribute when type is passed`, () => { - render(); + render(); - expect(screen.getByRole('list')).toHaveAttribute('type', 'i'); + expect(screen.getByRole('list')).toHaveAttribute('type', 'A'); }); }); diff --git a/packages/react-core/src/components/List/__tests__/ListItem.test.tsx b/packages/react-core/src/components/List/__tests__/ListItem.test.tsx new file mode 100644 index 00000000000..fe099c79c11 --- /dev/null +++ b/packages/react-core/src/components/List/__tests__/ListItem.test.tsx @@ -0,0 +1,51 @@ +import { render, screen } from '@testing-library/react'; +import { ListItem } from '../ListItem'; +import styles from '@patternfly/react-styles/css/components/List/list'; + +test('Renders with children', () => { + render(List item content); + + expect(screen.getByRole('listitem')).toHaveTextContent('List item content'); +}); + +test(`Does not render with a class by default`, () => { + render(List item content); + + expect(screen.getByRole('listitem')).not.toHaveClass(); +}); + +test(`Renders with custom class when className is passed`, () => { + render(List item content); + + expect(screen.getByRole('listitem')).toHaveClass('test-class', { exact: true }); +}); + +test(`Renders with icon content when icon prop is passed`, () => { + render(Icon content}>List item content); + + expect(screen.getByRole('listitem')).toContainHTML('
      Icon content
      '); +}); + +test(`Renders with class ${styles.listItem} when icon prop is passed`, () => { + render(Icon content}>List item content); + + expect(screen.getByRole('listitem')).toHaveClass(styles.listItem, { exact: true }); +}); + +test(`Spreads additional props when passed`, () => { + render(List item content); + + expect(screen.getByRole('listitem')).toHaveAttribute('id', 'test-ID'); +}); + +test('Matches snapshot without icon', () => { + const { asFragment } = render(List item content); + + expect(asFragment()).toMatchSnapshot(); +}); + +test('Matches snapshot with icon', () => { + const { asFragment } = render(Icon content}>List item content); + + expect(asFragment()).toMatchSnapshot(); +}); diff --git a/packages/react-core/src/components/List/__tests__/__snapshots__/ListItem.test.tsx.snap b/packages/react-core/src/components/List/__tests__/__snapshots__/ListItem.test.tsx.snap new file mode 100644 index 00000000000..b4d45faf665 --- /dev/null +++ b/packages/react-core/src/components/List/__tests__/__snapshots__/ListItem.test.tsx.snap @@ -0,0 +1,34 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Matches snapshot with icon 1`] = ` + +
    • + +
      + Icon content +
      +
      + + List item content + +
    • +
      +`; + +exports[`Matches snapshot without icon 1`] = ` + +
    • + + List item content + +
    • +
      +`;