mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2025-09-18 17:39:24 +00:00
217 lines
6.1 KiB
TypeScript
217 lines
6.1 KiB
TypeScript
![]() |
import { describe, expect, test, vi, beforeEach } from 'vitest';
|
||
|
import { render, screen, fireEvent } from '@testing-library/react';
|
||
|
import { MantineProvider } from '@mantine/core';
|
||
|
import ButtonSelector from './ButtonSelector';
|
||
|
|
||
|
// Wrapper component to provide Mantine context
|
||
|
const TestWrapper = ({ children }: { children: React.ReactNode }) => (
|
||
|
<MantineProvider>{children}</MantineProvider>
|
||
|
);
|
||
|
|
||
|
describe('ButtonSelector', () => {
|
||
|
const mockOnChange = vi.fn();
|
||
|
|
||
|
beforeEach(() => {
|
||
|
vi.clearAllMocks();
|
||
|
});
|
||
|
|
||
|
test('should render all options as buttons', () => {
|
||
|
const options = [
|
||
|
{ value: 'option1', label: 'Option 1' },
|
||
|
{ value: 'option2', label: 'Option 2' },
|
||
|
];
|
||
|
|
||
|
render(
|
||
|
<TestWrapper>
|
||
|
<ButtonSelector
|
||
|
value="option1"
|
||
|
onChange={mockOnChange}
|
||
|
options={options}
|
||
|
label="Test Label"
|
||
|
/>
|
||
|
</TestWrapper>
|
||
|
);
|
||
|
|
||
|
expect(screen.getByText('Test Label')).toBeInTheDocument();
|
||
|
expect(screen.getByText('Option 1')).toBeInTheDocument();
|
||
|
expect(screen.getByText('Option 2')).toBeInTheDocument();
|
||
|
});
|
||
|
|
||
|
test('should highlight selected button with filled variant', () => {
|
||
|
const options = [
|
||
|
{ value: 'option1', label: 'Option 1' },
|
||
|
{ value: 'option2', label: 'Option 2' },
|
||
|
];
|
||
|
|
||
|
render(
|
||
|
<TestWrapper>
|
||
|
<ButtonSelector
|
||
|
value="option1"
|
||
|
onChange={mockOnChange}
|
||
|
options={options}
|
||
|
label="Selection Label"
|
||
|
/>
|
||
|
</TestWrapper>
|
||
|
);
|
||
|
|
||
|
const selectedButton = screen.getByRole('button', { name: 'Option 1' });
|
||
|
const unselectedButton = screen.getByRole('button', { name: 'Option 2' });
|
||
|
|
||
|
// Check data-variant attribute for filled/outline
|
||
|
expect(selectedButton).toHaveAttribute('data-variant', 'filled');
|
||
|
expect(unselectedButton).toHaveAttribute('data-variant', 'outline');
|
||
|
expect(screen.getByText('Selection Label')).toBeInTheDocument();
|
||
|
});
|
||
|
|
||
|
test('should call onChange when button is clicked', () => {
|
||
|
const options = [
|
||
|
{ value: 'option1', label: 'Option 1' },
|
||
|
{ value: 'option2', label: 'Option 2' },
|
||
|
];
|
||
|
|
||
|
render(
|
||
|
<TestWrapper>
|
||
|
<ButtonSelector
|
||
|
value="option1"
|
||
|
onChange={mockOnChange}
|
||
|
options={options}
|
||
|
/>
|
||
|
</TestWrapper>
|
||
|
);
|
||
|
|
||
|
fireEvent.click(screen.getByRole('button', { name: 'Option 2' }));
|
||
|
|
||
|
expect(mockOnChange).toHaveBeenCalledWith('option2');
|
||
|
});
|
||
|
|
||
|
test('should handle undefined value (no selection)', () => {
|
||
|
const options = [
|
||
|
{ value: 'option1', label: 'Option 1' },
|
||
|
{ value: 'option2', label: 'Option 2' },
|
||
|
];
|
||
|
|
||
|
render(
|
||
|
<TestWrapper>
|
||
|
<ButtonSelector
|
||
|
value={undefined}
|
||
|
onChange={mockOnChange}
|
||
|
options={options}
|
||
|
/>
|
||
|
</TestWrapper>
|
||
|
);
|
||
|
|
||
|
// Both buttons should be outlined when no value is selected
|
||
|
const button1 = screen.getByRole('button', { name: 'Option 1' });
|
||
|
const button2 = screen.getByRole('button', { name: 'Option 2' });
|
||
|
|
||
|
expect(button1).toHaveAttribute('data-variant', 'outline');
|
||
|
expect(button2).toHaveAttribute('data-variant', 'outline');
|
||
|
});
|
||
|
|
||
|
test.each([
|
||
|
{
|
||
|
description: 'disable buttons when disabled prop is true',
|
||
|
options: [
|
||
|
{ value: 'option1', label: 'Option 1' },
|
||
|
{ value: 'option2', label: 'Option 2' },
|
||
|
],
|
||
|
globalDisabled: true,
|
||
|
expectedStates: [true, true],
|
||
|
},
|
||
|
{
|
||
|
description: 'disable individual options when option.disabled is true',
|
||
|
options: [
|
||
|
{ value: 'option1', label: 'Option 1' },
|
||
|
{ value: 'option2', label: 'Option 2', disabled: true },
|
||
|
],
|
||
|
globalDisabled: false,
|
||
|
expectedStates: [false, true],
|
||
|
},
|
||
|
])('should $description', ({ options, globalDisabled, expectedStates }) => {
|
||
|
render(
|
||
|
<TestWrapper>
|
||
|
<ButtonSelector
|
||
|
value="option1"
|
||
|
onChange={mockOnChange}
|
||
|
options={options}
|
||
|
disabled={globalDisabled}
|
||
|
/>
|
||
|
</TestWrapper>
|
||
|
);
|
||
|
|
||
|
options.forEach((option, index) => {
|
||
|
const button = screen.getByRole('button', { name: option.label });
|
||
|
expect(button).toHaveProperty('disabled', expectedStates[index]);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
test('should not call onChange when disabled button is clicked', () => {
|
||
|
const options = [
|
||
|
{ value: 'option1', label: 'Option 1' },
|
||
|
{ value: 'option2', label: 'Option 2', disabled: true },
|
||
|
];
|
||
|
|
||
|
render(
|
||
|
<TestWrapper>
|
||
|
<ButtonSelector
|
||
|
value="option1"
|
||
|
onChange={mockOnChange}
|
||
|
options={options}
|
||
|
/>
|
||
|
</TestWrapper>
|
||
|
);
|
||
|
|
||
|
fireEvent.click(screen.getByRole('button', { name: 'Option 2' }));
|
||
|
|
||
|
expect(mockOnChange).not.toHaveBeenCalled();
|
||
|
});
|
||
|
|
||
|
test('should not apply fullWidth styling when fullWidth is false', () => {
|
||
|
const options = [
|
||
|
{ value: 'option1', label: 'Option 1' },
|
||
|
{ value: 'option2', label: 'Option 2' },
|
||
|
];
|
||
|
|
||
|
render(
|
||
|
<TestWrapper>
|
||
|
<ButtonSelector
|
||
|
value="option1"
|
||
|
onChange={mockOnChange}
|
||
|
options={options}
|
||
|
fullWidth={false}
|
||
|
label="Layout Label"
|
||
|
/>
|
||
|
</TestWrapper>
|
||
|
);
|
||
|
|
||
|
const button = screen.getByRole('button', { name: 'Option 1' });
|
||
|
expect(button).not.toHaveStyle({ flex: '1' });
|
||
|
expect(screen.getByText('Layout Label')).toBeInTheDocument();
|
||
|
});
|
||
|
|
||
|
test('should not render label element when not provided', () => {
|
||
|
const options = [
|
||
|
{ value: 'option1', label: 'Option 1' },
|
||
|
{ value: 'option2', label: 'Option 2' },
|
||
|
];
|
||
|
|
||
|
const { container } = render(
|
||
|
<TestWrapper>
|
||
|
<ButtonSelector
|
||
|
value="option1"
|
||
|
onChange={mockOnChange}
|
||
|
options={options}
|
||
|
/>
|
||
|
</TestWrapper>
|
||
|
);
|
||
|
|
||
|
// Should render buttons
|
||
|
expect(screen.getByText('Option 1')).toBeInTheDocument();
|
||
|
expect(screen.getByText('Option 2')).toBeInTheDocument();
|
||
|
|
||
|
// Stack should only contain the Group (buttons), no Text element for label
|
||
|
const stackElement = container.querySelector('[class*="mantine-Stack-root"]');
|
||
|
expect(stackElement?.children).toHaveLength(1); // Only the Group, no label Text
|
||
|
});
|
||
|
});
|