diff options
Diffstat (limited to 'src/components/ui')
| -rw-r--r-- | src/components/ui/alert.test.tsx | 30 | ||||
| -rw-r--r-- | src/components/ui/button-variants.test.ts | 28 | ||||
| -rw-r--r-- | src/components/ui/button.test.tsx | 15 | ||||
| -rw-r--r-- | src/components/ui/card.test.tsx | 40 | ||||
| -rw-r--r-- | src/components/ui/input.test.tsx | 22 | ||||
| -rw-r--r-- | src/components/ui/label.test.tsx | 15 | ||||
| -rw-r--r-- | src/components/ui/pagination.test.tsx | 61 | ||||
| -rw-r--r-- | src/components/ui/skeleton.test.tsx | 16 |
8 files changed, 223 insertions, 4 deletions
diff --git a/src/components/ui/alert.test.tsx b/src/components/ui/alert.test.tsx new file mode 100644 index 0000000..ded0356 --- /dev/null +++ b/src/components/ui/alert.test.tsx @@ -0,0 +1,30 @@ +import { render, screen } from '@testing-library/react'; +import { describe, expect, test } from 'vitest'; +import { Alert, AlertDescription, AlertTitle } from './alert'; + +describe('Alert', () => { + test('renders with role and slot attributes', () => { + render( + <Alert> + <AlertTitle>Heads up</AlertTitle> + <AlertDescription>Something happened.</AlertDescription> + </Alert>, + ); + + const alert = screen.getByRole('alert'); + expect(alert).toHaveAttribute('data-slot', 'alert'); + expect(screen.getByText('Heads up')).toHaveAttribute('data-slot', 'alert-title'); + expect(screen.getByText('Something happened.')).toHaveAttribute( + 'data-slot', + 'alert-description', + ); + }); + + test('applies destructive variant classes', () => { + render(<Alert variant='destructive'>Danger</Alert>); + + const alert = screen.getByRole('alert'); + expect(alert.className).toContain('text-destructive'); + }); +}); + diff --git a/src/components/ui/button-variants.test.ts b/src/components/ui/button-variants.test.ts new file mode 100644 index 0000000..5090703 --- /dev/null +++ b/src/components/ui/button-variants.test.ts @@ -0,0 +1,28 @@ +import { describe, expect, test } from 'vitest'; +import { buttonVariants } from './button'; + +describe('buttonVariants', () => { + test('returns default variant and size classes when no args are provided', () => { + const classes = buttonVariants(); + + expect(classes).toContain('bg-primary'); + expect(classes).toContain('h-9'); + }); + + test('returns destructive and icon classes for explicit options', () => { + const classes = buttonVariants({ + variant: 'destructive', + size: 'icon', + }); + + expect(classes).toContain('bg-destructive'); + expect(classes).toContain('size-9'); + }); + + test('includes caller-provided className', () => { + const classes = buttonVariants({ className: 'w-full' }); + + expect(classes).toContain('w-full'); + }); +}); + diff --git a/src/components/ui/button.test.tsx b/src/components/ui/button.test.tsx index 314e9bf..f8bd3a9 100644 --- a/src/components/ui/button.test.tsx +++ b/src/components/ui/button.test.tsx @@ -14,9 +14,16 @@ describe('Button', () => { // Test buttons with different variants test('renders button with different variants', () => { - const variants = ['default', 'destructive', 'outline', 'secondary', 'ghost', 'link']; + const variants = [ + 'default', + 'destructive', + 'outline', + 'secondary', + 'ghost', + 'link', + ] as const; variants.forEach((variant) => { - render(<Button variant={variant as any}>{variant} Variant</Button>); + render(<Button variant={variant}>{variant} Variant</Button>); const button = screen.getByText(`${variant} Variant`); expect(button).toBeInTheDocument(); }); @@ -24,9 +31,9 @@ describe('Button', () => { // Test buttons with different sizes test('renders button with different sizes', () => { - const sizes = ['default', 'sm', 'lg', 'icon']; + const sizes = ['default', 'sm', 'lg', 'icon'] as const; sizes.forEach((size) => { - render(<Button size={size as any}>{size} Size</Button>); + render(<Button size={size}>{size} Size</Button>); const button = screen.getByText(`${size} Size`); expect(button).toBeInTheDocument(); }); diff --git a/src/components/ui/card.test.tsx b/src/components/ui/card.test.tsx new file mode 100644 index 0000000..aba3d00 --- /dev/null +++ b/src/components/ui/card.test.tsx @@ -0,0 +1,40 @@ +import { render, screen } from '@testing-library/react'; +import { describe, expect, test } from 'vitest'; +import { + Card, + CardAction, + CardContent, + CardDescription, + CardFooter, + CardHeader, + CardTitle, +} from './card'; + +describe('Card', () => { + test('renders all card slots', () => { + render( + <Card> + <CardHeader> + <CardTitle>Card Title</CardTitle> + <CardDescription>Card Description</CardDescription> + <CardAction>Action</CardAction> + </CardHeader> + <CardContent>Content</CardContent> + <CardFooter>Footer</CardFooter> + </Card>, + ); + + expect(screen.getByText('Card Title')).toHaveAttribute( + 'data-slot', + 'card-title', + ); + expect(screen.getByText('Card Description')).toHaveAttribute( + 'data-slot', + 'card-description', + ); + expect(screen.getByText('Action')).toHaveAttribute('data-slot', 'card-action'); + expect(screen.getByText('Content')).toHaveAttribute('data-slot', 'card-content'); + expect(screen.getByText('Footer')).toHaveAttribute('data-slot', 'card-footer'); + }); +}); + diff --git a/src/components/ui/input.test.tsx b/src/components/ui/input.test.tsx new file mode 100644 index 0000000..aabe76f --- /dev/null +++ b/src/components/ui/input.test.tsx @@ -0,0 +1,22 @@ +import { render, screen } from '@testing-library/react'; +import { describe, expect, test } from 'vitest'; +import { Input } from './input'; + +describe('Input', () => { + test('renders an input with the expected slot attribute', () => { + render(<Input aria-label='Email' />); + + const input = screen.getByLabelText('Email'); + expect(input).toBeInTheDocument(); + expect(input).toHaveAttribute('data-slot', 'input'); + }); + + test('supports input type and disabled props', () => { + render(<Input aria-label='Password' type='password' disabled />); + + const input = screen.getByLabelText('Password'); + expect(input).toHaveAttribute('type', 'password'); + expect(input).toBeDisabled(); + }); +}); + diff --git a/src/components/ui/label.test.tsx b/src/components/ui/label.test.tsx new file mode 100644 index 0000000..08031b6 --- /dev/null +++ b/src/components/ui/label.test.tsx @@ -0,0 +1,15 @@ +import { render, screen } from '@testing-library/react'; +import { describe, expect, test } from 'vitest'; +import { Label } from './label'; + +describe('Label', () => { + test('renders label text and exposes data-slot', () => { + render(<Label htmlFor='email'>Email</Label>); + + const label = screen.getByText('Email'); + expect(label).toBeInTheDocument(); + expect(label).toHaveAttribute('for', 'email'); + expect(label).toHaveAttribute('data-slot', 'label'); + }); +}); + diff --git a/src/components/ui/pagination.test.tsx b/src/components/ui/pagination.test.tsx new file mode 100644 index 0000000..77309b8 --- /dev/null +++ b/src/components/ui/pagination.test.tsx @@ -0,0 +1,61 @@ +import { render, screen } from '@testing-library/react'; +import { describe, expect, test } from 'vitest'; +import { + Pagination, + PaginationContent, + PaginationEllipsis, + PaginationItem, + PaginationLink, + PaginationNext, + PaginationPrevious, +} from './pagination'; + +describe('Pagination UI', () => { + test('renders pagination container and list slots', () => { + render( + <Pagination> + <PaginationContent> + <PaginationItem> + <PaginationLink href='#'>1</PaginationLink> + </PaginationItem> + </PaginationContent> + </Pagination>, + ); + + const nav = screen.getByLabelText('pagination'); + expect(nav).toHaveAttribute('data-slot', 'pagination'); + expect(screen.getByRole('link', { name: '1' })).toHaveAttribute( + 'data-slot', + 'pagination-link', + ); + }); + + test('sets active page attributes', () => { + render( + <PaginationLink href='#' isActive> + 2 + </PaginationLink>, + ); + + const link = screen.getByRole('link', { name: '2' }); + expect(link).toHaveAttribute('aria-current', 'page'); + expect(link).toHaveAttribute('data-active', 'true'); + }); + + test('renders previous, next, and ellipsis affordances', () => { + render( + <div> + <PaginationPrevious href='#' /> + <PaginationNext href='#' /> + <PaginationEllipsis /> + </div>, + ); + + expect( + screen.getByRole('link', { name: 'Go to previous page' }), + ).toBeInTheDocument(); + expect(screen.getByRole('link', { name: 'Go to next page' })).toBeInTheDocument(); + expect(screen.getByText('More pages')).toBeInTheDocument(); + }); +}); + diff --git a/src/components/ui/skeleton.test.tsx b/src/components/ui/skeleton.test.tsx new file mode 100644 index 0000000..4459d77 --- /dev/null +++ b/src/components/ui/skeleton.test.tsx @@ -0,0 +1,16 @@ +import { render, screen } from '@testing-library/react'; +import { describe, expect, test } from 'vitest'; +import { Skeleton } from './skeleton'; + +describe('Skeleton', () => { + test('renders with default and custom classes', () => { + render(<Skeleton data-testid='skeleton' className='h-4 w-20' />); + + const skeleton = screen.getByTestId('skeleton'); + expect(skeleton).toHaveAttribute('data-slot', 'skeleton'); + expect(skeleton.className).toContain('animate-pulse'); + expect(skeleton.className).toContain('h-4'); + expect(skeleton.className).toContain('w-20'); + }); +}); + |
