GrafanaUI: Added Unit Tests to Components (#105302)
* GrafanaUI: Added Unit Tests to Components * Updates per feedback / lint fix
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
|
||||
import { IconName } from '@grafana/data';
|
||||
|
||||
import { TabbedContainer } from './TabbedContainer';
|
||||
|
||||
const icon: IconName = 'info-circle';
|
||||
const icon2: IconName = 'user';
|
||||
const icon3: IconName = 'cog';
|
||||
|
||||
const mockTabs = [
|
||||
{
|
||||
label: 'Tab 1',
|
||||
value: 'tab1',
|
||||
content: <div data-testid="tab1-content">Tab 1 Content</div>,
|
||||
icon: icon,
|
||||
},
|
||||
{
|
||||
label: 'Tab 2',
|
||||
value: 'tab2',
|
||||
content: <div data-testid="tab2-content">Tab 2 Content</div>,
|
||||
icon: icon2,
|
||||
},
|
||||
{
|
||||
label: 'Tab 3',
|
||||
value: 'tab3',
|
||||
content: <div data-testid="tab3-content">Tab 3 Content</div>,
|
||||
icon: icon3,
|
||||
},
|
||||
];
|
||||
|
||||
const mockOnClose = jest.fn();
|
||||
const defaultProps = {
|
||||
tabs: mockTabs,
|
||||
onClose: mockOnClose,
|
||||
};
|
||||
|
||||
const setup = (jsx: JSX.Element) => {
|
||||
return {
|
||||
user: userEvent.setup(),
|
||||
...render(jsx),
|
||||
};
|
||||
};
|
||||
|
||||
describe('TabbedContainer', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should render all tabs with their labels and icons', () => {
|
||||
render(<TabbedContainer {...defaultProps} />);
|
||||
|
||||
mockTabs.forEach((tab) => {
|
||||
expect(screen.getByText(tab.label)).toBeInTheDocument();
|
||||
expect(screen.getByText(tab.label).closest('button')?.querySelector('svg')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('should render the first tab content by default', () => {
|
||||
render(<TabbedContainer {...defaultProps} />);
|
||||
|
||||
expect(screen.getByTestId('tab1-content')).toBeInTheDocument();
|
||||
expect(screen.queryByTestId('tab2-content')).not.toBeInTheDocument();
|
||||
expect(screen.queryByTestId('tab3-content')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render the default tab content when specified', () => {
|
||||
render(<TabbedContainer {...defaultProps} defaultTab="tab2" />);
|
||||
|
||||
expect(screen.queryByTestId('tab1-content')).not.toBeInTheDocument();
|
||||
expect(screen.getByTestId('tab2-content')).toBeInTheDocument();
|
||||
expect(screen.queryByTestId('tab3-content')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should switch content when clicking on different tabs', async () => {
|
||||
const { user } = setup(<TabbedContainer {...defaultProps} />);
|
||||
|
||||
expect(screen.getByTestId('tab1-content')).toBeInTheDocument();
|
||||
|
||||
await user.click(screen.getByText('Tab 2'));
|
||||
|
||||
expect(screen.queryByTestId('tab1-content')).not.toBeInTheDocument();
|
||||
expect(screen.getByTestId('tab2-content')).toBeInTheDocument();
|
||||
|
||||
await user.click(screen.getByText('Tab 3'));
|
||||
|
||||
expect(screen.queryByTestId('tab1-content')).not.toBeInTheDocument();
|
||||
expect(screen.queryByTestId('tab2-content')).not.toBeInTheDocument();
|
||||
expect(screen.getByTestId('tab3-content')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should call onClose when close button is clicked', async () => {
|
||||
const { user } = setup(<TabbedContainer {...defaultProps} />);
|
||||
|
||||
const closeButton = screen.getByRole('button', { name: /close/i });
|
||||
await user.click(closeButton);
|
||||
|
||||
expect(mockOnClose).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,50 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
|
||||
import { Tag } from './Tag';
|
||||
|
||||
const setup = (jsx: JSX.Element) => {
|
||||
return {
|
||||
user: userEvent.setup(),
|
||||
...render(jsx),
|
||||
};
|
||||
};
|
||||
|
||||
const mockOnClick = jest.fn();
|
||||
|
||||
describe('Tag', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should render with icon when provided', () => {
|
||||
render(<Tag name="test-tag" icon="info-circle" />);
|
||||
|
||||
const tag = screen.getByText('test-tag');
|
||||
expect(tag).toBeInTheDocument();
|
||||
expect(tag.parentElement?.querySelector('svg')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should handle click events', async () => {
|
||||
const { user } = setup(<Tag name="test-tag" onClick={mockOnClick} />);
|
||||
|
||||
const tag = screen.getByText('test-tag');
|
||||
await user.click(tag);
|
||||
|
||||
expect(mockOnClick).toHaveBeenCalledWith('test-tag', expect.any(Object));
|
||||
});
|
||||
|
||||
it('should render as button when onClick is provided', () => {
|
||||
render(<Tag name="test-tag" onClick={mockOnClick} />);
|
||||
|
||||
const tag = screen.getByRole('button', { name: 'test-tag' });
|
||||
expect(tag).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should not render as button when onClick is not provided', () => {
|
||||
render(<Tag name="test-tag" />);
|
||||
|
||||
const tag = screen.queryByRole('button', { name: 'test-tag' });
|
||||
expect(tag).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,55 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
|
||||
import { TagList } from './TagList';
|
||||
|
||||
const setup = (jsx: JSX.Element) => {
|
||||
return {
|
||||
user: userEvent.setup(),
|
||||
...render(jsx),
|
||||
};
|
||||
};
|
||||
|
||||
const mockTags = ['tag1', 'tag2', 'tag3', 'tag4', 'tag5'];
|
||||
const mockOnClick = jest.fn();
|
||||
|
||||
describe('TagList', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
it('should render all tags when displayMax is not provided', () => {
|
||||
render(<TagList tags={mockTags} />);
|
||||
|
||||
mockTags.forEach((tag) => {
|
||||
expect(screen.getByText(tag)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('should limit displayed tags when displayMax is provided', () => {
|
||||
const displayMax = 3;
|
||||
render(<TagList tags={mockTags} displayMax={displayMax} />);
|
||||
|
||||
for (let i = 0; i < displayMax; i++) {
|
||||
expect(screen.getByText(mockTags[i])).toBeInTheDocument();
|
||||
}
|
||||
|
||||
expect(screen.getByText(`+ ${mockTags.length - displayMax}`)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should handle tag clicks correctly', async () => {
|
||||
const { user } = setup(<TagList tags={mockTags} onClick={mockOnClick} />);
|
||||
|
||||
const firstTag = screen.getByText(mockTags[0]);
|
||||
await user.click(firstTag);
|
||||
|
||||
expect(mockOnClick).toHaveBeenCalledWith(mockTags[0], expect.any(Object));
|
||||
});
|
||||
|
||||
it('should apply custom aria labels when provided', () => {
|
||||
const getAriaLabel = (name: string, index: number) => `Custom label for ${name} at ${index}`;
|
||||
render(<TagList tags={mockTags} getAriaLabel={getAriaLabel} />);
|
||||
|
||||
const firstTag = screen.getByLabelText('Custom label for tag1 at 0');
|
||||
expect(firstTag).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,54 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
|
||||
import { ValuePicker } from './ValuePicker';
|
||||
|
||||
const mockOptions = [
|
||||
{ label: 'Option 1', value: 'opt1' },
|
||||
{ label: 'Option 2', value: 'opt2' },
|
||||
{ label: 'Option 3', value: 'opt3' },
|
||||
];
|
||||
|
||||
const mockOnChange = jest.fn();
|
||||
const defaultProps = {
|
||||
label: 'Add Option',
|
||||
options: mockOptions,
|
||||
onChange: mockOnChange,
|
||||
};
|
||||
|
||||
const setup = (jsx: JSX.Element) => {
|
||||
return {
|
||||
user: userEvent.setup(),
|
||||
...render(jsx),
|
||||
};
|
||||
};
|
||||
|
||||
describe('ValuePicker', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should switch to select view when button is clicked', async () => {
|
||||
const { user } = setup(<ValuePicker {...defaultProps} />);
|
||||
|
||||
expect(screen.getByRole('button')).toBeInTheDocument();
|
||||
expect(screen.queryByRole('combobox')).not.toBeInTheDocument();
|
||||
|
||||
await user.click(screen.getByRole('button'));
|
||||
|
||||
expect(screen.queryByRole('button')).not.toBeInTheDocument();
|
||||
expect(screen.getByRole('combobox')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should call onChange and switch back to button view when option is selected', async () => {
|
||||
const { user } = setup(<ValuePicker {...defaultProps} />);
|
||||
|
||||
await user.click(screen.getByRole('button'));
|
||||
await user.keyboard('{ArrowDown}{Enter}');
|
||||
|
||||
expect(mockOnChange).toHaveBeenCalledWith(mockOptions[0]);
|
||||
|
||||
expect(screen.getByRole('button')).toBeInTheDocument();
|
||||
expect(screen.queryByRole('combobox')).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user