From 682943ed1a9dd53dd590929ea717a29890d444d2 Mon Sep 17 00:00:00 2001 From: Collin Fingar Date: Thu, 8 May 2025 09:53:11 -0400 Subject: [PATCH] GrafanaUI: Added Unit Tests to Components (#105083) * GrafanaUI: Added Unit Tests to Components * Fixed typo --- .../components/FilterPill/FilterPill.test.tsx | 38 +++++++ .../src/components/FilterPill/FilterPill.tsx | 2 +- .../components/Pagination/Pagination.test.tsx | 5 + .../src/components/Pagination/Pagination.tsx | 2 +- .../grafana-ui/src/components/Tabs/Tab.tsx | 2 +- .../src/components/Tabs/Tabs.test.tsx | 99 +++++++++++++++++++ 6 files changed, 145 insertions(+), 3 deletions(-) create mode 100644 packages/grafana-ui/src/components/FilterPill/FilterPill.test.tsx create mode 100644 packages/grafana-ui/src/components/Tabs/Tabs.test.tsx diff --git a/packages/grafana-ui/src/components/FilterPill/FilterPill.test.tsx b/packages/grafana-ui/src/components/FilterPill/FilterPill.test.tsx new file mode 100644 index 00000000000..1fff175840f --- /dev/null +++ b/packages/grafana-ui/src/components/FilterPill/FilterPill.test.tsx @@ -0,0 +1,38 @@ +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; + +import { FilterPill } from './FilterPill'; + +const onClick = jest.fn(); + +const setup = (jsx: JSX.Element) => { + return { + user: userEvent.setup(), + ...render(jsx), + }; +}; + +describe('FilterPill', () => { + it('should call onClick when clicked', async () => { + const { user } = setup(); + + const button = screen.getByRole('button'); + await user.click(button); + + expect(onClick).toHaveBeenCalledTimes(1); + }); + + it('should not show icon when not selected', () => { + render(); + + const icon = screen.queryByTestId('filter-pill-icon'); + expect(icon).not.toBeInTheDocument(); + }); + + it('should show icon when selected', () => { + render(); + + const icon = screen.getByTestId('filter-pill-icon'); + expect(icon).toBeInTheDocument(); + }); +}); diff --git a/packages/grafana-ui/src/components/FilterPill/FilterPill.tsx b/packages/grafana-ui/src/components/FilterPill/FilterPill.tsx index 653a9688939..6b1a6aa87ac 100644 --- a/packages/grafana-ui/src/components/FilterPill/FilterPill.tsx +++ b/packages/grafana-ui/src/components/FilterPill/FilterPill.tsx @@ -21,7 +21,7 @@ export const FilterPill = ({ label, selected, onClick, icon = 'check' }: FilterP return ( ); }; diff --git a/packages/grafana-ui/src/components/Pagination/Pagination.test.tsx b/packages/grafana-ui/src/components/Pagination/Pagination.test.tsx index 2e9fe1a44e5..a0bfec245cf 100644 --- a/packages/grafana-ui/src/components/Pagination/Pagination.test.tsx +++ b/packages/grafana-ui/src/components/Pagination/Pagination.test.tsx @@ -11,4 +11,9 @@ describe('Pagination component', () => { render( {}} showSmallVersion />); expect(screen.getAllByRole('button')).toHaveLength(4); }); + it('should render two ellipsis when there are more than 14 page and a middle page is selected', () => { + render( {}} />); + expect(screen.getAllByRole('button')).toHaveLength(9); + expect(screen.getAllByTestId('pagination-ellipsis-icon')).toHaveLength(2); + }); }); diff --git a/packages/grafana-ui/src/components/Pagination/Pagination.tsx b/packages/grafana-ui/src/components/Pagination/Pagination.tsx index 901e5f68420..75958c30914 100644 --- a/packages/grafana-ui/src/components/Pagination/Pagination.tsx +++ b/packages/grafana-ui/src/components/Pagination/Pagination.tsx @@ -83,7 +83,7 @@ export const Pagination = ({ // Renders and ellipsis to represent condensed pages pagesToRender.push(
  • - +
  • ); } diff --git a/packages/grafana-ui/src/components/Tabs/Tab.tsx b/packages/grafana-ui/src/components/Tabs/Tab.tsx index 2cc0cc42515..f102ed3f0fa 100644 --- a/packages/grafana-ui/src/components/Tabs/Tab.tsx +++ b/packages/grafana-ui/src/components/Tabs/Tab.tsx @@ -39,7 +39,7 @@ export const Tab = React.forwardRef( const content = () => ( <> - {icon && } + {icon && } {label} {typeof counter === 'number' && } {Suffix && } diff --git a/packages/grafana-ui/src/components/Tabs/Tabs.test.tsx b/packages/grafana-ui/src/components/Tabs/Tabs.test.tsx new file mode 100644 index 00000000000..78594fc083a --- /dev/null +++ b/packages/grafana-ui/src/components/Tabs/Tabs.test.tsx @@ -0,0 +1,99 @@ +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; + +import { Tab } from './Tab'; +import { TabsBar } from './TabsBar'; + +const setup = (jsx: JSX.Element) => { + return { + user: userEvent.setup(), + ...render(jsx), + }; +}; + +const onChangeTab = jest.fn(); + +describe('Tabs', () => { + it('should call onChangeTab when clicking a tab', async () => { + const { user } = setup( + + + + ); + + const tab = screen.getByRole('tab'); + await user.click(tab); + + expect(onChangeTab).toHaveBeenCalledTimes(1); + }); + + it('should render active tab correctly', () => { + render( + + + + + ); + + const activeTab = screen.getByRole('tab', { name: 'Active Tab' }); + expect(activeTab).toHaveAttribute('aria-selected', 'true'); + }); + + it('should render tabs with icons', () => { + render( + + + + ); + + const icon = screen.getByTestId('tab-icon-star'); + expect(icon).toBeInTheDocument(); + }); + + it('should render tabs with counters', () => { + render( + + + + ); + + expect(screen.getByText('5')).toBeInTheDocument(); + }); + + it('should render tabs with tooltips', async () => { + const { user } = setup( + + + + ); + + const tab = screen.getByRole('tab'); + await user.hover(tab); + + expect(await screen.findByText('Tooltip content')).toBeInTheDocument(); + }); + + it('should render tabs as links when href is provided', () => { + render( + + + + ); + + const link = screen.getByRole('tab'); + expect(link.tagName).toBe('A'); + expect(link).toHaveAttribute('href', '/some-path'); + }); + + it('should render tabs with suffix content', () => { + const Suffix = () => Suffix; + + render( + + + + ); + + expect(screen.getByTestId('tab-suffix')).toBeInTheDocument(); + }); +});