177 lines
5.8 KiB
TypeScript
177 lines
5.8 KiB
TypeScript
import { render, screen } from '@testing-library/react';
|
|
import { describe, it, expect } from 'vitest';
|
|
import { Progress } from './Progress';
|
|
|
|
describe('Progress Component', () => {
|
|
describe('Linear variant', () => {
|
|
it('renders linear progress bar', () => {
|
|
render(<Progress value={50} />);
|
|
|
|
const progressBar = screen.getByRole('progressbar');
|
|
expect(progressBar).toBeInTheDocument();
|
|
});
|
|
|
|
it('renders with correct percentage', () => {
|
|
const { container } = render(<Progress value={50} />);
|
|
|
|
const progressFill = container.querySelector('.h-full');
|
|
expect(progressFill).toHaveStyle({ width: '50%' });
|
|
});
|
|
|
|
it('clamps value to max', () => {
|
|
const { container } = render(<Progress value={150} max={100} />);
|
|
|
|
const progressFill = container.querySelector('.h-full');
|
|
expect(progressFill).toHaveStyle({ width: '100%' });
|
|
});
|
|
|
|
it('clamps value to 0 minimum', () => {
|
|
const { container } = render(<Progress value={-10} />);
|
|
|
|
const progressFill = container.querySelector('.h-full');
|
|
expect(progressFill).toHaveStyle({ width: '0%' });
|
|
});
|
|
|
|
it('shows label when provided', () => {
|
|
render(<Progress value={50} label="Upload progress" />);
|
|
|
|
expect(screen.getByText('Upload progress')).toBeInTheDocument();
|
|
});
|
|
|
|
it('shows percentage when showLabel is true', () => {
|
|
render(<Progress value={75} showLabel />);
|
|
|
|
expect(screen.getByText('75%')).toBeInTheDocument();
|
|
});
|
|
|
|
it('shows both label and percentage', () => {
|
|
render(<Progress value={60} label="Download" showLabel />);
|
|
|
|
expect(screen.getByText('Download')).toBeInTheDocument();
|
|
expect(screen.getByText('60%')).toBeInTheDocument();
|
|
});
|
|
|
|
it('applies custom color', () => {
|
|
const { container } = render(<Progress value={50} color="#ff0000" />);
|
|
|
|
const progressFill = container.querySelector('.h-full');
|
|
expect(progressFill).toHaveStyle({ backgroundColor: '#ff0000' });
|
|
});
|
|
|
|
it('has correct aria attributes', () => {
|
|
render(<Progress value={50} max={100} label="Progress" />);
|
|
|
|
const progressBar = screen.getByRole('progressbar');
|
|
expect(progressBar).toHaveAttribute('aria-valuenow', '50');
|
|
expect(progressBar).toHaveAttribute('aria-valuemin', '0');
|
|
expect(progressBar).toHaveAttribute('aria-valuemax', '100');
|
|
expect(progressBar).toHaveAttribute('aria-label');
|
|
const ariaLabel = progressBar.getAttribute('aria-label');
|
|
expect(ariaLabel).toContain('50%');
|
|
});
|
|
|
|
it('applies custom className', () => {
|
|
const { container } = render(
|
|
<Progress value={50} className="custom-progress" />,
|
|
);
|
|
|
|
const wrapper = container.firstChild;
|
|
expect(wrapper).toHaveClass('custom-progress');
|
|
});
|
|
});
|
|
|
|
describe('Circular variant', () => {
|
|
it('renders circular progress', () => {
|
|
render(<Progress value={50} variant="circular" />);
|
|
|
|
const progressBar = screen.getByRole('progressbar');
|
|
expect(progressBar).toBeInTheDocument();
|
|
expect(progressBar.tagName).toBe('svg');
|
|
});
|
|
|
|
it('renders with correct percentage', () => {
|
|
const { container } = render(<Progress value={50} variant="circular" />);
|
|
|
|
const svg = container.querySelector('svg');
|
|
expect(svg).toBeInTheDocument();
|
|
});
|
|
|
|
it('shows percentage when showLabel is true', () => {
|
|
render(<Progress value={75} variant="circular" showLabel />);
|
|
|
|
expect(screen.getByText('75%')).toBeInTheDocument();
|
|
});
|
|
|
|
it('does not show percentage when showLabel is false', () => {
|
|
render(<Progress value={75} variant="circular" showLabel={false} />);
|
|
|
|
expect(screen.queryByText('75%')).not.toBeInTheDocument();
|
|
});
|
|
|
|
it('applies custom color', () => {
|
|
const { container } = render(
|
|
<Progress value={50} variant="circular" color="#00ff00" />,
|
|
);
|
|
|
|
const circle = container.querySelector('circle[stroke-dasharray]');
|
|
expect(circle).toHaveStyle({ stroke: '#00ff00' });
|
|
});
|
|
|
|
it('has correct aria attributes', () => {
|
|
render(<Progress value={50} variant="circular" max={100} />);
|
|
|
|
const progressBar = screen.getByRole('progressbar');
|
|
expect(progressBar).toHaveAttribute('aria-valuenow', '50');
|
|
expect(progressBar).toHaveAttribute('aria-valuemin', '0');
|
|
expect(progressBar).toHaveAttribute('aria-valuemax', '100');
|
|
});
|
|
|
|
it('applies custom className', () => {
|
|
const { container } = render(
|
|
<Progress value={50} variant="circular" className="custom-circular" />,
|
|
);
|
|
|
|
const wrapper = container.firstChild;
|
|
expect(wrapper).toHaveClass('custom-circular');
|
|
});
|
|
|
|
it('clamps value to max in circular variant', () => {
|
|
const { container } = render(
|
|
<Progress value={150} variant="circular" max={100} />,
|
|
);
|
|
|
|
const svg = container.querySelector('svg');
|
|
expect(svg).toBeInTheDocument();
|
|
});
|
|
});
|
|
|
|
describe('Edge cases', () => {
|
|
it('handles zero value', () => {
|
|
const { container } = render(<Progress value={0} />);
|
|
|
|
const progressFill = container.querySelector('.h-full');
|
|
expect(progressFill).toHaveStyle({ width: '0%' });
|
|
});
|
|
|
|
it('handles max value', () => {
|
|
const { container } = render(<Progress value={100} />);
|
|
|
|
const progressFill = container.querySelector('.h-full');
|
|
expect(progressFill).toHaveStyle({ width: '100%' });
|
|
});
|
|
|
|
it('handles custom max value', () => {
|
|
const { container } = render(<Progress value={50} max={200} />);
|
|
|
|
const progressFill = container.querySelector('.h-full');
|
|
expect(progressFill).toHaveStyle({ width: '25%' });
|
|
});
|
|
|
|
it('handles decimal values', () => {
|
|
const { container } = render(<Progress value={33.33} />);
|
|
|
|
const progressFill = container.querySelector('.h-full');
|
|
expect(progressFill).toHaveStyle({ width: '33%' });
|
|
});
|
|
});
|
|
});
|