Sergey Krylov 53659a36b1 feat(design-system): add data components, form/page-state patterns, and frontend integration
- Inputs: TextField, Select, Checkbox
- Surfaces: Surface, Card, Chip, Badge
- Feedback: Alert, Dialog, Skeleton, Progress
- Financial data: DataTable, Metric, Money, PriceChange
- Form & page-state: FormField, FilterBar, EmptyState, ErrorState, LoadingState
- MUI CssVarsProvider -> ThemeProvider deprecation fix
- Inter font bundled via @fontsource/inter
- ESLint no-restricted-imports (warn) for gradual migration
- storybook-static gitignored

All 268 tests pass (157 design-system + 111 frontend)
2026-06-21 09:49:18 +03:00

63 lines
2.2 KiB
TypeScript

import { describe, it, expect, vi } from 'vitest';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { Chip } from './Chip';
import { MoexVibeThemeProvider } from '../../theme';
function renderWithTheme(element: React.ReactElement) {
return render(<MoexVibeThemeProvider>{element}</MoexVibeThemeProvider>);
}
describe('Chip', () => {
it('renders label', () => {
renderWithTheme(<Chip label="Default" />);
expect(screen.getByText('Default')).toBeInTheDocument();
});
it('renders with neutral tone by default', () => {
renderWithTheme(<Chip label="Neutral" />);
const chip = screen.getByText('Neutral').closest('.MuiChip-root')!;
expect(chip.classList.contains('MuiChip-filled')).toBe(true);
});
it('renders info tone', () => {
renderWithTheme(<Chip label="Info" tone="info" />);
expect(screen.getByText('Info')).toBeInTheDocument();
});
it('renders success tone', () => {
renderWithTheme(<Chip label="Success" tone="success" />);
expect(screen.getByText('Success')).toBeInTheDocument();
});
it('renders warning tone', () => {
renderWithTheme(<Chip label="Warning" tone="warning" />);
expect(screen.getByText('Warning')).toBeInTheDocument();
});
it('renders error tone', () => {
renderWithTheme(<Chip label="Error" tone="error" />);
expect(screen.getByText('Error')).toBeInTheDocument();
});
it('shows delete button when onDelete provided', () => {
renderWithTheme(<Chip label="Removable" onDelete={() => {}} />);
const deleteIcon = screen.getByLabelText('Remove Removable');
expect(deleteIcon).toBeInTheDocument();
});
it('calls onDelete when delete clicked', async () => {
const handleDelete = vi.fn();
const user = userEvent.setup();
renderWithTheme(<Chip label="Removable" onDelete={handleDelete} />);
const deleteIcon = screen.getByLabelText('Remove Removable');
await user.click(deleteIcon);
expect(handleDelete).toHaveBeenCalledTimes(1);
});
it('does not show delete button without onDelete', () => {
renderWithTheme(<Chip label="Static" />);
expect(screen.queryByRole('button')).not.toBeInTheDocument();
});
});