@gv-tech/design-system 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agent/skills/dogfood-components/SKILL.md +34 -0
- package/.agent/skills/maintain-component/SKILL.md +42 -0
- package/.prettierignore +2 -0
- package/CHANGELOG.md +16 -0
- package/dist/App.d.ts.map +1 -1
- package/dist/components/docs/Footer.d.ts.map +1 -1
- package/dist/components/docs/PropsTable.d.ts +13 -0
- package/dist/components/docs/PropsTable.d.ts.map +1 -0
- package/dist/components/docs/Sidebar.d.ts.map +1 -1
- package/dist/components/docs/index.d.ts +1 -0
- package/dist/components/docs/index.d.ts.map +1 -1
- package/dist/components/ui/accordion.test.d.ts +2 -0
- package/dist/components/ui/accordion.test.d.ts.map +1 -0
- package/dist/components/ui/alert-dialog.test.d.ts +2 -0
- package/dist/components/ui/alert-dialog.test.d.ts.map +1 -0
- package/dist/components/ui/alert.test.d.ts +2 -0
- package/dist/components/ui/alert.test.d.ts.map +1 -0
- package/dist/components/ui/aspect-ratio.test.d.ts +2 -0
- package/dist/components/ui/aspect-ratio.test.d.ts.map +1 -0
- package/dist/components/ui/avatar.test.d.ts +2 -0
- package/dist/components/ui/avatar.test.d.ts.map +1 -0
- package/dist/components/ui/badge.test.d.ts +2 -0
- package/dist/components/ui/badge.test.d.ts.map +1 -0
- package/dist/components/ui/breadcrumb.test.d.ts +2 -0
- package/dist/components/ui/breadcrumb.test.d.ts.map +1 -0
- package/dist/components/ui/button.test.d.ts +2 -0
- package/dist/components/ui/button.test.d.ts.map +1 -0
- package/dist/components/ui/calendar.d.ts.map +1 -1
- package/dist/components/ui/calendar.test.d.ts +2 -0
- package/dist/components/ui/calendar.test.d.ts.map +1 -0
- package/dist/components/ui/card.test.d.ts +2 -0
- package/dist/components/ui/card.test.d.ts.map +1 -0
- package/dist/components/ui/carousel.test.d.ts +2 -0
- package/dist/components/ui/carousel.test.d.ts.map +1 -0
- package/dist/components/ui/chart.test.d.ts +2 -0
- package/dist/components/ui/chart.test.d.ts.map +1 -0
- package/dist/components/ui/checkbox.test.d.ts +2 -0
- package/dist/components/ui/checkbox.test.d.ts.map +1 -0
- package/dist/components/ui/collapsible.test.d.ts +2 -0
- package/dist/components/ui/collapsible.test.d.ts.map +1 -0
- package/dist/components/ui/command.test.d.ts +2 -0
- package/dist/components/ui/command.test.d.ts.map +1 -0
- package/dist/components/ui/context-menu.test.d.ts +2 -0
- package/dist/components/ui/context-menu.test.d.ts.map +1 -0
- package/dist/components/ui/dialog.test.d.ts +2 -0
- package/dist/components/ui/dialog.test.d.ts.map +1 -0
- package/dist/components/ui/drawer.test.d.ts +2 -0
- package/dist/components/ui/drawer.test.d.ts.map +1 -0
- package/dist/components/ui/dropdown-menu.test.d.ts +2 -0
- package/dist/components/ui/dropdown-menu.test.d.ts.map +1 -0
- package/dist/components/ui/form.test.d.ts +2 -0
- package/dist/components/ui/form.test.d.ts.map +1 -0
- package/dist/components/ui/hover-card.test.d.ts +2 -0
- package/dist/components/ui/hover-card.test.d.ts.map +1 -0
- package/dist/components/ui/input.test.d.ts +2 -0
- package/dist/components/ui/input.test.d.ts.map +1 -0
- package/dist/components/ui/label.test.d.ts +2 -0
- package/dist/components/ui/label.test.d.ts.map +1 -0
- package/dist/components/ui/menubar.test.d.ts +2 -0
- package/dist/components/ui/menubar.test.d.ts.map +1 -0
- package/dist/components/ui/navigation-menu.test.d.ts +2 -0
- package/dist/components/ui/navigation-menu.test.d.ts.map +1 -0
- package/dist/components/ui/pagination.test.d.ts +2 -0
- package/dist/components/ui/pagination.test.d.ts.map +1 -0
- package/dist/components/ui/popover.test.d.ts +2 -0
- package/dist/components/ui/popover.test.d.ts.map +1 -0
- package/dist/components/ui/progress.d.ts.map +1 -1
- package/dist/components/ui/progress.test.d.ts +2 -0
- package/dist/components/ui/progress.test.d.ts.map +1 -0
- package/dist/components/ui/radio-group.test.d.ts +2 -0
- package/dist/components/ui/radio-group.test.d.ts.map +1 -0
- package/dist/components/ui/resizable.test.d.ts +2 -0
- package/dist/components/ui/resizable.test.d.ts.map +1 -0
- package/dist/components/ui/scroll-area.test.d.ts +2 -0
- package/dist/components/ui/scroll-area.test.d.ts.map +1 -0
- package/dist/components/ui/select.test.d.ts +2 -0
- package/dist/components/ui/select.test.d.ts.map +1 -0
- package/dist/components/ui/separator.test.d.ts +2 -0
- package/dist/components/ui/separator.test.d.ts.map +1 -0
- package/dist/components/ui/sheet.test.d.ts +2 -0
- package/dist/components/ui/sheet.test.d.ts.map +1 -0
- package/dist/components/ui/skeleton.test.d.ts +2 -0
- package/dist/components/ui/skeleton.test.d.ts.map +1 -0
- package/dist/components/ui/slider.test.d.ts +2 -0
- package/dist/components/ui/slider.test.d.ts.map +1 -0
- package/dist/components/ui/sonner.test.d.ts +2 -0
- package/dist/components/ui/sonner.test.d.ts.map +1 -0
- package/dist/components/ui/switch.test.d.ts +2 -0
- package/dist/components/ui/switch.test.d.ts.map +1 -0
- package/dist/components/ui/table.test.d.ts +2 -0
- package/dist/components/ui/table.test.d.ts.map +1 -0
- package/dist/components/ui/tabs.test.d.ts +2 -0
- package/dist/components/ui/tabs.test.d.ts.map +1 -0
- package/dist/components/ui/textarea.test.d.ts +2 -0
- package/dist/components/ui/textarea.test.d.ts.map +1 -0
- package/dist/components/ui/theme-toggle.d.ts +17 -0
- package/dist/components/ui/theme-toggle.d.ts.map +1 -0
- package/dist/components/ui/toast.test.d.ts +2 -0
- package/dist/components/ui/toast.test.d.ts.map +1 -0
- package/dist/components/ui/toggle-group.test.d.ts +2 -0
- package/dist/components/ui/toggle-group.test.d.ts.map +1 -0
- package/dist/components/ui/toggle.test.d.ts +2 -0
- package/dist/components/ui/toggle.test.d.ts.map +1 -0
- package/dist/components/ui/tooltip.test.d.ts +2 -0
- package/dist/components/ui/tooltip.test.d.ts.map +1 -0
- package/dist/index.cjs.js +3 -3
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.es.js +978 -860
- package/dist/index.es.js.map +1 -1
- package/dist/lib/tokens.d.ts +54 -0
- package/dist/lib/tokens.d.ts.map +1 -0
- package/dist/pages/ColorTokensDocs.d.ts +2 -0
- package/dist/pages/ColorTokensDocs.d.ts.map +1 -0
- package/dist/pages/GettingStarted.d.ts.map +1 -1
- package/dist/pages/components/AccordionDocs.d.ts.map +1 -1
- package/dist/pages/components/AlertDialogDocs.d.ts.map +1 -1
- package/dist/pages/components/AlertDocs.d.ts.map +1 -1
- package/dist/pages/components/AspectRatioDocs.d.ts.map +1 -1
- package/dist/pages/components/AvatarDocs.d.ts.map +1 -1
- package/dist/pages/components/BadgeDocs.d.ts.map +1 -1
- package/dist/pages/components/BreadcrumbDocs.d.ts.map +1 -1
- package/dist/pages/components/ButtonDocs.d.ts.map +1 -1
- package/dist/pages/components/CalendarDocs.d.ts.map +1 -1
- package/dist/pages/components/CardDocs.d.ts.map +1 -1
- package/dist/pages/components/CarouselDocs.d.ts.map +1 -1
- package/dist/pages/components/ChartDocs.d.ts.map +1 -1
- package/dist/pages/components/CheckboxDocs.d.ts.map +1 -1
- package/dist/pages/components/CollapsibleDocs.d.ts.map +1 -1
- package/dist/pages/components/CommandDocs.d.ts.map +1 -1
- package/dist/pages/components/ContextMenuDocs.d.ts.map +1 -1
- package/dist/pages/components/DialogDocs.d.ts.map +1 -1
- package/dist/pages/components/DrawerDocs.d.ts.map +1 -1
- package/dist/pages/components/DropdownMenuDocs.d.ts.map +1 -1
- package/dist/pages/components/FormDocs.d.ts.map +1 -1
- package/dist/pages/components/HoverCardDocs.d.ts.map +1 -1
- package/dist/pages/components/InputDocs.d.ts.map +1 -1
- package/dist/pages/components/LabelDocs.d.ts.map +1 -1
- package/dist/pages/components/MenubarDocs.d.ts.map +1 -1
- package/dist/pages/components/NavigationMenuDocs.d.ts.map +1 -1
- package/dist/pages/components/PaginationDocs.d.ts.map +1 -1
- package/dist/pages/components/PopoverDocs.d.ts.map +1 -1
- package/dist/pages/components/ProgressDocs.d.ts.map +1 -1
- package/dist/pages/components/RadioGroupDocs.d.ts.map +1 -1
- package/dist/pages/components/ResizableDocs.d.ts.map +1 -1
- package/dist/pages/components/ScrollAreaDocs.d.ts.map +1 -1
- package/dist/pages/components/SelectDocs.d.ts.map +1 -1
- package/dist/pages/components/SeparatorDocs.d.ts.map +1 -1
- package/dist/pages/components/SheetDocs.d.ts.map +1 -1
- package/dist/pages/components/SkeletonDocs.d.ts.map +1 -1
- package/dist/pages/components/SliderDocs.d.ts.map +1 -1
- package/dist/pages/components/SonnerDocs.d.ts.map +1 -1
- package/dist/pages/components/SwitchDocs.d.ts.map +1 -1
- package/dist/pages/components/TableDocs.d.ts.map +1 -1
- package/dist/pages/components/TabsDocs.d.ts.map +1 -1
- package/dist/pages/components/TextareaDocs.d.ts.map +1 -1
- package/dist/pages/components/ThemeToggleDocs.d.ts +2 -0
- package/dist/pages/components/ThemeToggleDocs.d.ts.map +1 -0
- package/dist/pages/components/ToastDocs.d.ts.map +1 -1
- package/dist/pages/components/ToggleDocs.d.ts.map +1 -1
- package/dist/pages/components/ToggleGroupDocs.d.ts.map +1 -1
- package/dist/pages/components/TooltipDocs.d.ts.map +1 -1
- package/dist/pages/index.d.ts +2 -0
- package/dist/pages/index.d.ts.map +1 -1
- package/dist/registry/accordion.test.json +13 -0
- package/dist/registry/alert-dialog.test.json +13 -0
- package/dist/registry/alert.test.json +13 -0
- package/dist/registry/aspect-ratio.test.json +13 -0
- package/dist/registry/avatar.test.json +13 -0
- package/dist/registry/badge.test.json +13 -0
- package/dist/registry/breadcrumb.test.json +13 -0
- package/dist/registry/button.test.json +13 -0
- package/dist/registry/calendar.json +1 -1
- package/dist/registry/calendar.test.json +13 -0
- package/dist/registry/card.test.json +13 -0
- package/dist/registry/carousel.test.json +13 -0
- package/dist/registry/chart.test.json +13 -0
- package/dist/registry/checkbox.test.json +13 -0
- package/dist/registry/collapsible.test.json +13 -0
- package/dist/registry/command.test.json +13 -0
- package/dist/registry/context-menu.test.json +13 -0
- package/dist/registry/dialog.test.json +13 -0
- package/dist/registry/drawer.test.json +13 -0
- package/dist/registry/dropdown-menu.test.json +13 -0
- package/dist/registry/form.test.json +13 -0
- package/dist/registry/hover-card.test.json +13 -0
- package/dist/registry/index.json +322 -0
- package/dist/registry/input.test.json +13 -0
- package/dist/registry/label.test.json +13 -0
- package/dist/registry/menubar.test.json +13 -0
- package/dist/registry/navigation-menu.test.json +13 -0
- package/dist/registry/pagination.test.json +13 -0
- package/dist/registry/popover.test.json +13 -0
- package/dist/registry/progress.json +1 -1
- package/dist/registry/progress.test.json +13 -0
- package/dist/registry/radio-group.test.json +13 -0
- package/dist/registry/resizable.test.json +13 -0
- package/dist/registry/scroll-area.test.json +13 -0
- package/dist/registry/select.test.json +13 -0
- package/dist/registry/separator.test.json +13 -0
- package/dist/registry/sheet.test.json +13 -0
- package/dist/registry/skeleton.test.json +13 -0
- package/dist/registry/slider.test.json +13 -0
- package/dist/registry/sonner.test.json +13 -0
- package/dist/registry/switch.test.json +13 -0
- package/dist/registry/table.test.json +13 -0
- package/dist/registry/tabs.test.json +13 -0
- package/dist/registry/textarea.test.json +13 -0
- package/dist/registry/theme-toggle.json +13 -0
- package/dist/registry/toast.test.json +13 -0
- package/dist/registry/toggle-group.test.json +13 -0
- package/dist/registry/toggle.test.json +13 -0
- package/dist/registry/tooltip.test.json +13 -0
- package/dist/setupTests.d.ts +2 -0
- package/dist/setupTests.d.ts.map +1 -0
- package/dist/{vendor-ZhQmrf1h.mjs → vendor-CAF5bxO5.mjs} +2451 -2415
- package/dist/vendor-CAF5bxO5.mjs.map +1 -0
- package/dist/{vendor-CMSUBoIg.js → vendor-Hw1BQGd3.js} +17 -17
- package/dist/vendor-Hw1BQGd3.js.map +1 -0
- package/eslint.config.mjs +8 -81
- package/package.json +36 -38
- package/src/App.tsx +37 -7
- package/src/components/docs/Footer.tsx +51 -30
- package/src/components/docs/PropsTable.tsx +43 -0
- package/src/components/docs/Sidebar.tsx +42 -71
- package/src/components/docs/index.ts +1 -0
- package/src/components/ui/accordion.test.tsx +86 -0
- package/src/components/ui/alert-dialog.test.tsx +89 -0
- package/src/components/ui/alert.test.tsx +33 -0
- package/src/components/ui/aspect-ratio.test.tsx +34 -0
- package/src/components/ui/avatar.test.tsx +33 -0
- package/src/components/ui/badge.test.tsx +24 -0
- package/src/components/ui/breadcrumb.test.tsx +55 -0
- package/src/components/ui/button.test.tsx +62 -0
- package/src/components/ui/calendar.test.tsx +23 -0
- package/src/components/ui/calendar.tsx +14 -10
- package/src/components/ui/card.test.tsx +35 -0
- package/src/components/ui/carousel.test.tsx +37 -0
- package/src/components/ui/chart.test.tsx +62 -0
- package/src/components/ui/checkbox.test.tsx +30 -0
- package/src/components/ui/collapsible.test.tsx +51 -0
- package/src/components/ui/command.test.tsx +79 -0
- package/src/components/ui/context-menu.test.tsx +37 -0
- package/src/components/ui/dialog.test.tsx +66 -0
- package/src/components/ui/drawer.test.tsx +68 -0
- package/src/components/ui/dropdown-menu.test.tsx +93 -0
- package/src/components/ui/form.test.tsx +85 -0
- package/src/components/ui/hover-card.test.tsx +48 -0
- package/src/components/ui/input.test.tsx +33 -0
- package/src/components/ui/label.test.tsx +27 -0
- package/src/components/ui/menubar.test.tsx +92 -0
- package/src/components/ui/navigation-menu.test.tsx +53 -0
- package/src/components/ui/pagination.test.tsx +57 -0
- package/src/components/ui/popover.test.tsx +31 -0
- package/src/components/ui/progress.test.tsx +18 -0
- package/src/components/ui/progress.tsx +1 -0
- package/src/components/ui/radio-group.test.tsx +39 -0
- package/src/components/ui/resizable.test.tsx +23 -0
- package/src/components/ui/scroll-area.test.tsx +15 -0
- package/src/components/ui/select.test.tsx +42 -0
- package/src/components/ui/separator.test.tsx +16 -0
- package/src/components/ui/sheet.test.tsx +48 -0
- package/src/components/ui/skeleton.test.tsx +13 -0
- package/src/components/ui/slider.test.tsx +18 -0
- package/src/components/ui/sonner.test.tsx +13 -0
- package/src/components/ui/switch.test.tsx +22 -0
- package/src/components/ui/table.test.tsx +29 -0
- package/src/components/ui/tabs.test.tsx +43 -0
- package/src/components/ui/textarea.test.tsx +21 -0
- package/src/components/ui/theme-toggle.tsx +108 -0
- package/src/components/ui/toast.test.tsx +42 -0
- package/src/components/ui/toggle-group.test.tsx +40 -0
- package/src/components/ui/toggle.test.tsx +21 -0
- package/src/components/ui/tooltip.test.tsx +25 -0
- package/src/globals.css +39 -34
- package/src/index.ts +2 -0
- package/src/lib/tokens.ts +54 -0
- package/src/pages/ColorTokensDocs.tsx +181 -0
- package/src/pages/GettingStarted.tsx +55 -35
- package/src/pages/components/AccordionDocs.tsx +109 -0
- package/src/pages/components/AlertDialogDocs.tsx +88 -0
- package/src/pages/components/AlertDocs.tsx +20 -0
- package/src/pages/components/AspectRatioDocs.tsx +21 -0
- package/src/pages/components/AvatarDocs.tsx +48 -0
- package/src/pages/components/BadgeDocs.tsx +20 -0
- package/src/pages/components/BreadcrumbDocs.tsx +33 -0
- package/src/pages/components/ButtonDocs.tsx +43 -0
- package/src/pages/components/CalendarDocs.tsx +43 -0
- package/src/pages/components/CardDocs.tsx +20 -0
- package/src/pages/components/CarouselDocs.tsx +31 -0
- package/src/pages/components/ChartDocs.tsx +131 -101
- package/src/pages/components/CheckboxDocs.tsx +58 -0
- package/src/pages/components/CollapsibleDocs.tsx +51 -0
- package/src/pages/components/CommandDocs.tsx +109 -0
- package/src/pages/components/ContextMenuDocs.tsx +65 -0
- package/src/pages/components/DialogDocs.tsx +98 -11
- package/src/pages/components/DrawerDocs.tsx +210 -15
- package/src/pages/components/DropdownMenuDocs.tsx +273 -11
- package/src/pages/components/FormDocs.tsx +149 -70
- package/src/pages/components/HoverCardDocs.tsx +82 -5
- package/src/pages/components/InputDocs.tsx +51 -20
- package/src/pages/components/LabelDocs.tsx +40 -9
- package/src/pages/components/MenubarDocs.tsx +191 -18
- package/src/pages/components/NavigationMenuDocs.tsx +147 -49
- package/src/pages/components/PaginationDocs.tsx +27 -2
- package/src/pages/components/PopoverDocs.tsx +124 -2
- package/src/pages/components/ProgressDocs.tsx +54 -24
- package/src/pages/components/RadioGroupDocs.tsx +95 -1
- package/src/pages/components/ResizableDocs.tsx +102 -75
- package/src/pages/components/ScrollAreaDocs.tsx +64 -51
- package/src/pages/components/SelectDocs.tsx +119 -48
- package/src/pages/components/SeparatorDocs.tsx +37 -2
- package/src/pages/components/SheetDocs.tsx +112 -38
- package/src/pages/components/SkeletonDocs.tsx +16 -20
- package/src/pages/components/SliderDocs.tsx +96 -10
- package/src/pages/components/SonnerDocs.tsx +89 -61
- package/src/pages/components/SwitchDocs.tsx +65 -10
- package/src/pages/components/TableDocs.tsx +89 -14
- package/src/pages/components/TabsDocs.tsx +149 -37
- package/src/pages/components/TextareaDocs.tsx +38 -32
- package/src/pages/components/ThemeToggleDocs.tsx +50 -0
- package/src/pages/components/ToastDocs.tsx +104 -65
- package/src/pages/components/ToggleDocs.tsx +55 -38
- package/src/pages/components/ToggleGroupDocs.tsx +96 -58
- package/src/pages/components/TooltipDocs.tsx +112 -3
- package/src/pages/index.ts +2 -0
- package/src/setupTests.ts +47 -0
- package/temp.md +292 -0
- package/vitest.config.ts +4 -0
- package/dist/vendor-CMSUBoIg.js.map +0 -1
- package/dist/vendor-ZhQmrf1h.mjs.map +0 -1
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { render, screen, waitFor } from '@testing-library/react';
|
|
2
|
+
import userEvent from '@testing-library/user-event';
|
|
3
|
+
import { describe, expect, it } from 'vitest';
|
|
4
|
+
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from './accordion';
|
|
5
|
+
|
|
6
|
+
describe('Accordion', () => {
|
|
7
|
+
it('renders correctly', () => {
|
|
8
|
+
render(
|
|
9
|
+
<Accordion type="single" collapsible>
|
|
10
|
+
<AccordionItem value="item-1">
|
|
11
|
+
<AccordionTrigger>Trigger 1</AccordionTrigger>
|
|
12
|
+
<AccordionContent>Content 1</AccordionContent>
|
|
13
|
+
</AccordionItem>
|
|
14
|
+
</Accordion>,
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
expect(screen.getByText('Trigger 1')).toBeInTheDocument();
|
|
18
|
+
// Content should not be visible initially
|
|
19
|
+
expect(screen.queryByText('Content 1')).not.toBeInTheDocument();
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('expands when clicked', async () => {
|
|
23
|
+
render(
|
|
24
|
+
<Accordion type="single" collapsible>
|
|
25
|
+
<AccordionItem value="item-1">
|
|
26
|
+
<AccordionTrigger>Trigger 1</AccordionTrigger>
|
|
27
|
+
<AccordionContent>Content 1</AccordionContent>
|
|
28
|
+
</AccordionItem>
|
|
29
|
+
</Accordion>,
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
const trigger = screen.getByText('Trigger 1');
|
|
33
|
+
await userEvent.click(trigger);
|
|
34
|
+
|
|
35
|
+
await waitFor(() => {
|
|
36
|
+
expect(screen.getByText('Content 1')).toBeVisible();
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('collapses when clicked again', async () => {
|
|
41
|
+
render(
|
|
42
|
+
<Accordion type="single" collapsible defaultValue="item-1">
|
|
43
|
+
<AccordionItem value="item-1">
|
|
44
|
+
<AccordionTrigger>Trigger 1</AccordionTrigger>
|
|
45
|
+
<AccordionContent>Content 1</AccordionContent>
|
|
46
|
+
</AccordionItem>
|
|
47
|
+
</Accordion>,
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
// Initial state open
|
|
51
|
+
expect(screen.getByText('Content 1')).toBeVisible();
|
|
52
|
+
|
|
53
|
+
const trigger = screen.getByText('Trigger 1');
|
|
54
|
+
await userEvent.click(trigger);
|
|
55
|
+
|
|
56
|
+
await waitFor(() => {
|
|
57
|
+
expect(screen.queryByText('Content 1')).not.toBeInTheDocument();
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('handles single mode correctly', async () => {
|
|
62
|
+
render(
|
|
63
|
+
<Accordion type="single" collapsible>
|
|
64
|
+
<AccordionItem value="item-1">
|
|
65
|
+
<AccordionTrigger>Trigger 1</AccordionTrigger>
|
|
66
|
+
<AccordionContent>Content 1</AccordionContent>
|
|
67
|
+
</AccordionItem>
|
|
68
|
+
<AccordionItem value="item-2">
|
|
69
|
+
<AccordionTrigger>Trigger 2</AccordionTrigger>
|
|
70
|
+
<AccordionContent>Content 2</AccordionContent>
|
|
71
|
+
</AccordionItem>
|
|
72
|
+
</Accordion>,
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
// Click item 1
|
|
76
|
+
await userEvent.click(screen.getByText('Trigger 1'));
|
|
77
|
+
await waitFor(() => expect(screen.getByText('Content 1')).toBeVisible());
|
|
78
|
+
|
|
79
|
+
// Click item 2
|
|
80
|
+
await userEvent.click(screen.getByText('Trigger 2'));
|
|
81
|
+
await waitFor(() => expect(screen.getByText('Content 2')).toBeVisible());
|
|
82
|
+
|
|
83
|
+
// Item 1 should be closed
|
|
84
|
+
await waitFor(() => expect(screen.queryByText('Content 1')).not.toBeInTheDocument());
|
|
85
|
+
});
|
|
86
|
+
});
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { render, screen, waitFor } from '@testing-library/react';
|
|
2
|
+
import userEvent from '@testing-library/user-event';
|
|
3
|
+
import { describe, expect, it } from 'vitest';
|
|
4
|
+
import {
|
|
5
|
+
AlertDialog,
|
|
6
|
+
AlertDialogAction,
|
|
7
|
+
AlertDialogCancel,
|
|
8
|
+
AlertDialogContent,
|
|
9
|
+
AlertDialogDescription,
|
|
10
|
+
AlertDialogFooter,
|
|
11
|
+
AlertDialogHeader,
|
|
12
|
+
AlertDialogTitle,
|
|
13
|
+
AlertDialogTrigger,
|
|
14
|
+
} from './alert-dialog';
|
|
15
|
+
|
|
16
|
+
describe('AlertDialog', () => {
|
|
17
|
+
it('renders correctly', async () => {
|
|
18
|
+
render(
|
|
19
|
+
<AlertDialog>
|
|
20
|
+
<AlertDialogTrigger>Open</AlertDialogTrigger>
|
|
21
|
+
<AlertDialogContent>
|
|
22
|
+
<AlertDialogHeader>
|
|
23
|
+
<AlertDialogTitle>Are you sure?</AlertDialogTitle>
|
|
24
|
+
<AlertDialogDescription>This action cannot be undone.</AlertDialogDescription>
|
|
25
|
+
</AlertDialogHeader>
|
|
26
|
+
<AlertDialogFooter>
|
|
27
|
+
<AlertDialogCancel>Cancel</AlertDialogCancel>
|
|
28
|
+
<AlertDialogAction>Continue</AlertDialogAction>
|
|
29
|
+
</AlertDialogFooter>
|
|
30
|
+
</AlertDialogContent>
|
|
31
|
+
</AlertDialog>,
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
expect(screen.getByText('Open')).toBeInTheDocument();
|
|
35
|
+
expect(screen.queryByText('Are you sure?')).not.toBeInTheDocument();
|
|
36
|
+
|
|
37
|
+
await userEvent.click(screen.getByText('Open'));
|
|
38
|
+
|
|
39
|
+
await waitFor(() => {
|
|
40
|
+
expect(screen.getByRole('alertdialog')).toBeInTheDocument();
|
|
41
|
+
expect(screen.getByText('Are you sure?')).toBeInTheDocument();
|
|
42
|
+
expect(screen.getByText('This action cannot be undone.')).toBeInTheDocument();
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('closes when cancel is clicked', async () => {
|
|
47
|
+
render(
|
|
48
|
+
<AlertDialog>
|
|
49
|
+
<AlertDialogTrigger>Open</AlertDialogTrigger>
|
|
50
|
+
<AlertDialogContent>
|
|
51
|
+
<AlertDialogHeader>
|
|
52
|
+
<AlertDialogTitle>Are you sure?</AlertDialogTitle>
|
|
53
|
+
</AlertDialogHeader>
|
|
54
|
+
<AlertDialogFooter>
|
|
55
|
+
<AlertDialogCancel>Cancel</AlertDialogCancel>
|
|
56
|
+
</AlertDialogFooter>
|
|
57
|
+
</AlertDialogContent>
|
|
58
|
+
</AlertDialog>,
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
await userEvent.click(screen.getByText('Open'));
|
|
62
|
+
await waitFor(() => expect(screen.getByRole('alertdialog')).toBeInTheDocument());
|
|
63
|
+
|
|
64
|
+
await userEvent.click(screen.getByText('Cancel'));
|
|
65
|
+
await waitFor(() => expect(screen.queryByRole('alertdialog')).not.toBeInTheDocument());
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('closes when action is clicked', async () => {
|
|
69
|
+
render(
|
|
70
|
+
<AlertDialog>
|
|
71
|
+
<AlertDialogTrigger>Open</AlertDialogTrigger>
|
|
72
|
+
<AlertDialogContent>
|
|
73
|
+
<AlertDialogHeader>
|
|
74
|
+
<AlertDialogTitle>Are you sure?</AlertDialogTitle>
|
|
75
|
+
</AlertDialogHeader>
|
|
76
|
+
<AlertDialogFooter>
|
|
77
|
+
<AlertDialogAction>Continue</AlertDialogAction>
|
|
78
|
+
</AlertDialogFooter>
|
|
79
|
+
</AlertDialogContent>
|
|
80
|
+
</AlertDialog>,
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
await userEvent.click(screen.getByText('Open'));
|
|
84
|
+
await waitFor(() => expect(screen.getByRole('alertdialog')).toBeInTheDocument());
|
|
85
|
+
|
|
86
|
+
await userEvent.click(screen.getByText('Continue'));
|
|
87
|
+
await waitFor(() => expect(screen.queryByRole('alertdialog')).not.toBeInTheDocument());
|
|
88
|
+
});
|
|
89
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { render, screen } from '@testing-library/react';
|
|
2
|
+
import { describe, expect, it } from 'vitest';
|
|
3
|
+
import { Alert, AlertDescription, AlertTitle } from './alert';
|
|
4
|
+
|
|
5
|
+
describe('Alert', () => {
|
|
6
|
+
it('renders correctly', () => {
|
|
7
|
+
render(
|
|
8
|
+
<Alert>
|
|
9
|
+
<AlertTitle>Heads up!</AlertTitle>
|
|
10
|
+
<AlertDescription>You can add components to your app using the cli.</AlertDescription>
|
|
11
|
+
</Alert>,
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
const alert = screen.getByRole('alert');
|
|
15
|
+
expect(alert).toBeInTheDocument();
|
|
16
|
+
expect(screen.getByText('Heads up!')).toBeInTheDocument();
|
|
17
|
+
expect(screen.getByText('You can add components to your app using the cli.')).toBeInTheDocument();
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('renders destructive variant', () => {
|
|
21
|
+
render(
|
|
22
|
+
<Alert variant="destructive">
|
|
23
|
+
<AlertTitle>Error</AlertTitle>
|
|
24
|
+
<AlertDescription>Your session has expired.</AlertDescription>
|
|
25
|
+
</Alert>,
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
const alert = screen.getByRole('alert');
|
|
29
|
+
expect(alert).toBeInTheDocument();
|
|
30
|
+
expect(alert).toHaveClass('border-destructive/50');
|
|
31
|
+
expect(alert).toHaveClass('text-destructive');
|
|
32
|
+
});
|
|
33
|
+
});
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { render, screen } from '@testing-library/react';
|
|
2
|
+
import { describe, expect, it } from 'vitest';
|
|
3
|
+
import { AspectRatio } from './aspect-ratio';
|
|
4
|
+
|
|
5
|
+
describe('AspectRatio', () => {
|
|
6
|
+
it('renders correctly', () => {
|
|
7
|
+
const { container } = render(
|
|
8
|
+
<AspectRatio ratio={16 / 9}>
|
|
9
|
+
<img src="test.jpg" alt="test" />
|
|
10
|
+
</AspectRatio>,
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
const img = screen.getByRole('img');
|
|
14
|
+
expect(img).toBeInTheDocument();
|
|
15
|
+
|
|
16
|
+
// Radix AspectRatio renders a wrapper with padding-bottom based on ratio
|
|
17
|
+
// We can check if the wrapper style is applied
|
|
18
|
+
const wrapper = container.firstChild;
|
|
19
|
+
expect(wrapper).toHaveStyle({ paddingBottom: expect.stringMatching(/%$/) });
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('renders with custom ratio', () => {
|
|
23
|
+
const { container } = render(
|
|
24
|
+
<AspectRatio ratio={1 / 1}>
|
|
25
|
+
<div>Square</div>
|
|
26
|
+
</AspectRatio>,
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
expect(screen.getByText('Square')).toBeInTheDocument();
|
|
30
|
+
const wrapper = container.firstChild;
|
|
31
|
+
// 1/1 ratio should be 100% padding-bottom
|
|
32
|
+
expect(wrapper).toHaveStyle({ paddingBottom: '100%' });
|
|
33
|
+
});
|
|
34
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { render, screen } from '@testing-library/react';
|
|
2
|
+
import { describe, expect, it } from 'vitest';
|
|
3
|
+
import { Avatar, AvatarFallback, AvatarImage } from './avatar';
|
|
4
|
+
|
|
5
|
+
describe('Avatar', () => {
|
|
6
|
+
it('renders correctly', () => {
|
|
7
|
+
render(
|
|
8
|
+
<Avatar>
|
|
9
|
+
<AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" />
|
|
10
|
+
<AvatarFallback>CN</AvatarFallback>
|
|
11
|
+
</Avatar>,
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
// In JSDOM, image loading might not happen immediately or at all without mocking.
|
|
15
|
+
// However, the elements should be in the DOM.
|
|
16
|
+
// Radix conditionally renders Image or Fallback.
|
|
17
|
+
// By default, it might render Image and hide Fallback, or vice versa depending on loading.
|
|
18
|
+
|
|
19
|
+
// Let's check that the root is present
|
|
20
|
+
const avatar = screen.getByText('CN')?.parentElement || screen.getByRole('img').parentElement;
|
|
21
|
+
expect(avatar).toBeInTheDocument();
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('renders fallback when image is missing', () => {
|
|
25
|
+
render(
|
|
26
|
+
<Avatar>
|
|
27
|
+
<AvatarFallback>CN</AvatarFallback>
|
|
28
|
+
</Avatar>,
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
expect(screen.getByText('CN')).toBeInTheDocument();
|
|
32
|
+
});
|
|
33
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { render, screen } from '@testing-library/react';
|
|
2
|
+
import { describe, expect, it } from 'vitest';
|
|
3
|
+
import { Badge } from './badge';
|
|
4
|
+
|
|
5
|
+
describe('Badge', () => {
|
|
6
|
+
it('renders correctly', () => {
|
|
7
|
+
render(<Badge>Test Badge</Badge>);
|
|
8
|
+
expect(screen.getByText('Test Badge')).toBeInTheDocument();
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it('renders variants', () => {
|
|
12
|
+
const { rerender, getByText } = render(<Badge variant="default">Default</Badge>);
|
|
13
|
+
expect(getByText('Default')).toHaveClass('bg-primary');
|
|
14
|
+
|
|
15
|
+
rerender(<Badge variant="secondary">Secondary</Badge>);
|
|
16
|
+
expect(getByText('Secondary')).toHaveClass('bg-secondary');
|
|
17
|
+
|
|
18
|
+
rerender(<Badge variant="destructive">Destructive</Badge>);
|
|
19
|
+
expect(getByText('Destructive')).toHaveClass('bg-destructive');
|
|
20
|
+
|
|
21
|
+
rerender(<Badge variant="outline">Outline</Badge>);
|
|
22
|
+
expect(getByText('Outline')).toHaveClass('text-foreground');
|
|
23
|
+
});
|
|
24
|
+
});
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { render, screen } from '@testing-library/react';
|
|
2
|
+
import { describe, expect, it } from 'vitest';
|
|
3
|
+
import {
|
|
4
|
+
Breadcrumb,
|
|
5
|
+
BreadcrumbItem,
|
|
6
|
+
BreadcrumbLink,
|
|
7
|
+
BreadcrumbList,
|
|
8
|
+
BreadcrumbPage,
|
|
9
|
+
BreadcrumbSeparator,
|
|
10
|
+
} from './breadcrumb';
|
|
11
|
+
|
|
12
|
+
describe('Breadcrumb', () => {
|
|
13
|
+
it('renders correctly', () => {
|
|
14
|
+
render(
|
|
15
|
+
<Breadcrumb>
|
|
16
|
+
<BreadcrumbList>
|
|
17
|
+
<BreadcrumbItem>
|
|
18
|
+
<BreadcrumbLink href="/">Home</BreadcrumbLink>
|
|
19
|
+
</BreadcrumbItem>
|
|
20
|
+
<BreadcrumbSeparator />
|
|
21
|
+
<BreadcrumbItem>
|
|
22
|
+
<BreadcrumbPage>Page</BreadcrumbPage>
|
|
23
|
+
</BreadcrumbItem>
|
|
24
|
+
</BreadcrumbList>
|
|
25
|
+
</Breadcrumb>,
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
const nav = screen.getByRole('navigation');
|
|
29
|
+
expect(nav).toBeInTheDocument();
|
|
30
|
+
expect(nav).toHaveAttribute('aria-label', 'breadcrumb');
|
|
31
|
+
|
|
32
|
+
const links = screen.getAllByRole('link');
|
|
33
|
+
expect(links).toHaveLength(2); // Link and Page (span role="link")
|
|
34
|
+
expect(links[0]).toHaveAttribute('href', '/');
|
|
35
|
+
expect(links[1]).toHaveTextContent('Page');
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('renders custom separator', () => {
|
|
39
|
+
render(
|
|
40
|
+
<Breadcrumb>
|
|
41
|
+
<BreadcrumbList>
|
|
42
|
+
<BreadcrumbItem>
|
|
43
|
+
<BreadcrumbLink>Home</BreadcrumbLink>
|
|
44
|
+
</BreadcrumbItem>
|
|
45
|
+
<BreadcrumbSeparator>/</BreadcrumbSeparator>
|
|
46
|
+
<BreadcrumbItem>
|
|
47
|
+
<BreadcrumbPage>Page</BreadcrumbPage>
|
|
48
|
+
</BreadcrumbItem>
|
|
49
|
+
</BreadcrumbList>
|
|
50
|
+
</Breadcrumb>,
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
expect(screen.getByText('/')).toBeInTheDocument();
|
|
54
|
+
});
|
|
55
|
+
});
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { render, screen } from '@testing-library/react';
|
|
2
|
+
import userEvent from '@testing-library/user-event';
|
|
3
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
4
|
+
import { Button } from './button';
|
|
5
|
+
|
|
6
|
+
describe('Button', () => {
|
|
7
|
+
it('renders correctly', () => {
|
|
8
|
+
render(<Button>Click me</Button>);
|
|
9
|
+
expect(screen.getByRole('button', { name: /click me/i })).toBeInTheDocument();
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it('handles click events', async () => {
|
|
13
|
+
const handleClick = vi.fn();
|
|
14
|
+
render(<Button onClick={handleClick}>Click me</Button>);
|
|
15
|
+
|
|
16
|
+
await userEvent.click(screen.getByRole('button', { name: /click me/i }));
|
|
17
|
+
expect(handleClick).toHaveBeenCalledTimes(1);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('can be disabled', () => {
|
|
21
|
+
render(<Button disabled>Click me</Button>);
|
|
22
|
+
expect(screen.getByRole('button', { name: /click me/i })).toBeDisabled();
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('supports asChild prop', () => {
|
|
26
|
+
render(
|
|
27
|
+
<Button asChild>
|
|
28
|
+
<a href="/test">Link Button</a>
|
|
29
|
+
</Button>,
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
const link = screen.getByRole('link', { name: /link button/i });
|
|
33
|
+
expect(link).toBeInTheDocument();
|
|
34
|
+
expect(link).toHaveAttribute('href', '/test');
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
describe('Variants', () => {
|
|
38
|
+
const variants = ['default', 'destructive', 'outline', 'secondary', 'ghost', 'link'] as const;
|
|
39
|
+
|
|
40
|
+
variants.forEach((variant) => {
|
|
41
|
+
it(`renders ${variant} variant`, () => {
|
|
42
|
+
render(<Button variant={variant}>{variant}</Button>);
|
|
43
|
+
const button = screen.getByRole('button', { name: variant });
|
|
44
|
+
expect(button).toBeInTheDocument();
|
|
45
|
+
// We could check for specific classes here, but that might make tests too brittle
|
|
46
|
+
// checking the role and content presence is a good baseline
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
describe('Sizes', () => {
|
|
52
|
+
const sizes = ['default', 'sm', 'lg', 'icon'] as const;
|
|
53
|
+
|
|
54
|
+
sizes.forEach((size) => {
|
|
55
|
+
it(`renders ${size} size`, () => {
|
|
56
|
+
render(<Button size={size}>{size}</Button>);
|
|
57
|
+
const button = screen.getByRole('button', { name: size });
|
|
58
|
+
expect(button).toBeInTheDocument();
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { render, screen } from '@testing-library/react';
|
|
2
|
+
import { describe, expect, it } from 'vitest';
|
|
3
|
+
import { Calendar } from './calendar';
|
|
4
|
+
|
|
5
|
+
describe('Calendar', () => {
|
|
6
|
+
it('renders correctly', () => {
|
|
7
|
+
// Mock date to consistent rendering
|
|
8
|
+
const date = new Date(2023, 0, 1); // Jan 1, 2023
|
|
9
|
+
|
|
10
|
+
render(<Calendar mode="single" selected={date} month={date} />);
|
|
11
|
+
|
|
12
|
+
expect(screen.getByText('January 2023')).toBeInTheDocument();
|
|
13
|
+
const days = screen.getAllByText('1');
|
|
14
|
+
expect(days.length).toBeGreaterThan(0);
|
|
15
|
+
expect(screen.getByText('Su')).toBeInTheDocument(); // Sunday header
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('renders with class name', () => {
|
|
19
|
+
const { container } = render(<Calendar className="test-class" />);
|
|
20
|
+
// DayPicker renders a div with the class
|
|
21
|
+
expect(container.firstChild).toHaveClass('test-class');
|
|
22
|
+
});
|
|
23
|
+
});
|
|
@@ -23,9 +23,10 @@ function Calendar({
|
|
|
23
23
|
<DayPicker
|
|
24
24
|
showOutsideDays={showOutsideDays}
|
|
25
25
|
className={cn(
|
|
26
|
-
'bg-background group/calendar p-3 [--cell-size:
|
|
26
|
+
'bg-background group/calendar p-3 [--cell-size:2.5rem] [[data-slot=card-content]_&]:bg-transparent [[data-slot=popover-content]_&]:bg-transparent',
|
|
27
27
|
String.raw`rtl:**:[.rdp-button\_next>svg]:rotate-180`,
|
|
28
28
|
String.raw`rtl:**:[.rdp-button\_previous>svg]:rotate-180`,
|
|
29
|
+
'relative',
|
|
29
30
|
className,
|
|
30
31
|
)}
|
|
31
32
|
captionLayout={captionLayout}
|
|
@@ -37,19 +38,22 @@ function Calendar({
|
|
|
37
38
|
root: cn('w-fit', defaultClassNames.root),
|
|
38
39
|
months: cn('relative flex flex-col gap-4 md:flex-row', defaultClassNames.months),
|
|
39
40
|
month: cn('flex w-full flex-col gap-4', defaultClassNames.month),
|
|
40
|
-
nav: cn(
|
|
41
|
+
nav: cn(
|
|
42
|
+
'absolute inset-x-0 top-2 flex items-center justify-between pointer-events-none px-2',
|
|
43
|
+
defaultClassNames.nav,
|
|
44
|
+
),
|
|
41
45
|
button_previous: cn(
|
|
42
46
|
buttonVariants({ variant: buttonVariant }),
|
|
43
|
-
'h-
|
|
47
|
+
'h-7 w-7 select-none p-0 aria-disabled:opacity-50 pointer-events-auto',
|
|
44
48
|
defaultClassNames.button_previous,
|
|
45
49
|
),
|
|
46
50
|
button_next: cn(
|
|
47
51
|
buttonVariants({ variant: buttonVariant }),
|
|
48
|
-
'h-
|
|
52
|
+
'h-7 w-7 select-none p-0 aria-disabled:opacity-50 pointer-events-auto',
|
|
49
53
|
defaultClassNames.button_next,
|
|
50
54
|
),
|
|
51
55
|
month_caption: cn(
|
|
52
|
-
'flex h-[--cell-size] w-full items-center justify-center
|
|
56
|
+
'flex h-[--cell-size] w-full items-center justify-center text-sm font-medium',
|
|
53
57
|
defaultClassNames.month_caption,
|
|
54
58
|
),
|
|
55
59
|
dropdowns: cn(
|
|
@@ -68,17 +72,17 @@ function Calendar({
|
|
|
68
72
|
: '[&>svg]:text-muted-foreground flex h-8 items-center gap-1 rounded-md pl-2 pr-1 text-sm [&>svg]:size-3.5',
|
|
69
73
|
defaultClassNames.caption_label,
|
|
70
74
|
),
|
|
71
|
-
table: 'w-full border-collapse',
|
|
75
|
+
table: 'w-full border-collapse grow',
|
|
72
76
|
weekdays: cn('flex', defaultClassNames.weekdays),
|
|
73
77
|
weekday: cn(
|
|
74
|
-
'text-muted-foreground flex-1 select-none rounded-md text-[0.8rem] font-normal',
|
|
78
|
+
'text-muted-foreground pt-1 flex-1 select-none rounded-md text-[0.8rem] font-normal uppercase',
|
|
75
79
|
defaultClassNames.weekday,
|
|
76
80
|
),
|
|
77
|
-
week: cn('
|
|
81
|
+
week: cn('flex w-full mt-2', defaultClassNames.week),
|
|
78
82
|
week_number_header: cn('w-[--cell-size] select-none', defaultClassNames.week_number_header),
|
|
79
83
|
week_number: cn('text-muted-foreground select-none text-[0.8rem]', defaultClassNames.week_number),
|
|
80
84
|
day: cn(
|
|
81
|
-
'group/day relative aspect-square h-
|
|
85
|
+
'group/day relative flex aspect-square h-10 w-10 select-none items-center justify-center p-0 text-center [&:first-child[data-selected=true]_button]:rounded-l-md [&:last-child[data-selected=true]_button]:rounded-r-md',
|
|
82
86
|
defaultClassNames.day,
|
|
83
87
|
),
|
|
84
88
|
range_start: cn('bg-accent rounded-l-md', defaultClassNames.range_start),
|
|
@@ -144,7 +148,7 @@ function CalendarDayButton({ className, day, modifiers, ...props }: React.Compon
|
|
|
144
148
|
data-range-end={modifiers.range_end}
|
|
145
149
|
data-range-middle={modifiers.range_middle}
|
|
146
150
|
className={cn(
|
|
147
|
-
'data-[selected-single=true]:bg-primary data-[selected-single=true]:text-primary-foreground data-[range-middle=true]:bg-accent data-[range-middle=true]:text-accent-foreground data-[range-start=true]:bg-primary data-[range-start=true]:text-primary-foreground data-[range-end=true]:bg-primary data-[range-end=true]:text-primary-foreground group-data-[focused=true]/day:border-ring group-data-[focused=true]/day:ring-ring/50 flex aspect-square h-
|
|
151
|
+
'data-[selected-single=true]:bg-primary data-[selected-single=true]:text-primary-foreground data-[range-middle=true]:bg-accent data-[range-middle=true]:text-accent-foreground data-[range-start=true]:bg-primary data-[range-start=true]:text-primary-foreground data-[range-end=true]:bg-primary data-[range-end=true]:text-primary-foreground group-data-[focused=true]/day:border-ring group-data-[focused=true]/day:ring-ring/50 flex aspect-square h-full w-full min-w-[--cell-size] items-center justify-center font-normal leading-none data-[range-end=true]:rounded-md data-[range-middle=true]:rounded-none data-[range-start=true]:rounded-md group-data-[focused=true]/day:relative group-data-[focused=true]/day:z-10 group-data-[focused=true]/day:ring-[3px] [&>span]:text-xs [&>span]:opacity-70',
|
|
148
152
|
defaultClassNames.day,
|
|
149
153
|
className,
|
|
150
154
|
)}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { render, screen } from '@testing-library/react';
|
|
2
|
+
import { describe, expect, it } from 'vitest';
|
|
3
|
+
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from './card';
|
|
4
|
+
|
|
5
|
+
describe('Card', () => {
|
|
6
|
+
it('renders correctly', () => {
|
|
7
|
+
render(
|
|
8
|
+
<Card>
|
|
9
|
+
<CardHeader>
|
|
10
|
+
<CardTitle>Title</CardTitle>
|
|
11
|
+
<CardDescription>Description</CardDescription>
|
|
12
|
+
</CardHeader>
|
|
13
|
+
<CardContent>Content</CardContent>
|
|
14
|
+
<CardFooter>Footer</CardFooter>
|
|
15
|
+
</Card>,
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
expect(screen.getByText('Title')).toBeInTheDocument();
|
|
19
|
+
expect(screen.getByText('Description')).toBeInTheDocument();
|
|
20
|
+
expect(screen.getByText('Content')).toBeInTheDocument();
|
|
21
|
+
expect(screen.getByText('Footer')).toBeInTheDocument();
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('renders with class names', () => {
|
|
25
|
+
const { container } = render(<Card className="test-class" />);
|
|
26
|
+
expect(container.firstChild).toHaveClass(
|
|
27
|
+
'test-class',
|
|
28
|
+
'rounded-xl',
|
|
29
|
+
'border',
|
|
30
|
+
'bg-card',
|
|
31
|
+
'text-card-foreground',
|
|
32
|
+
'shadow',
|
|
33
|
+
);
|
|
34
|
+
});
|
|
35
|
+
});
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { render, screen } from '@testing-library/react';
|
|
2
|
+
import { describe, expect, it } from 'vitest';
|
|
3
|
+
import { Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious } from './carousel';
|
|
4
|
+
|
|
5
|
+
describe('Carousel', () => {
|
|
6
|
+
it('renders correctly', () => {
|
|
7
|
+
render(
|
|
8
|
+
<Carousel aria-label="carousel">
|
|
9
|
+
<CarouselContent>
|
|
10
|
+
<CarouselItem>Slide 1</CarouselItem>
|
|
11
|
+
<CarouselItem>Slide 2</CarouselItem>
|
|
12
|
+
<CarouselItem>Slide 3</CarouselItem>
|
|
13
|
+
</CarouselContent>
|
|
14
|
+
<CarouselPrevious />
|
|
15
|
+
<CarouselNext />
|
|
16
|
+
</Carousel>,
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
expect(screen.getByRole('region', { name: 'carousel' })).toBeInTheDocument();
|
|
20
|
+
expect(screen.getByText('Slide 1')).toBeInTheDocument();
|
|
21
|
+
expect(screen.getByText('Slide 2')).toBeInTheDocument();
|
|
22
|
+
expect(screen.getByText('Slide 3')).toBeInTheDocument();
|
|
23
|
+
expect(screen.getByRole('button', { name: 'Previous slide' })).toBeInTheDocument();
|
|
24
|
+
expect(screen.getByRole('button', { name: 'Next slide' })).toBeInTheDocument();
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('renders with orientation vertical', () => {
|
|
28
|
+
render(
|
|
29
|
+
<Carousel orientation="vertical" aria-label="carousel">
|
|
30
|
+
<CarouselContent>
|
|
31
|
+
<CarouselItem>Slide 1</CarouselItem>
|
|
32
|
+
</CarouselContent>
|
|
33
|
+
</Carousel>,
|
|
34
|
+
);
|
|
35
|
+
expect(screen.getByRole('region', { name: 'carousel' })).toBeInTheDocument();
|
|
36
|
+
});
|
|
37
|
+
});
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { render, screen } from '@testing-library/react';
|
|
2
|
+
import { Bar, BarChart, CartesianGrid, XAxis } from 'recharts';
|
|
3
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
4
|
+
import { ChartContainer, ChartTooltip, ChartTooltipContent } from './chart';
|
|
5
|
+
|
|
6
|
+
// Mock Recharts ResponsiveContainer to avoid ResizeObserver issues and render children immediately
|
|
7
|
+
vi.mock('recharts', async (importOriginal) => {
|
|
8
|
+
const original = await importOriginal();
|
|
9
|
+
return {
|
|
10
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
11
|
+
...(original as any),
|
|
12
|
+
ResponsiveContainer: ({ children }: { children: React.ReactNode }) => (
|
|
13
|
+
<div style={{ width: 500, height: 300 }}>{children}</div>
|
|
14
|
+
),
|
|
15
|
+
};
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
const chartConfig = {
|
|
19
|
+
desktop: {
|
|
20
|
+
label: 'Desktop',
|
|
21
|
+
color: '#2563eb',
|
|
22
|
+
},
|
|
23
|
+
mobile: {
|
|
24
|
+
label: 'Mobile',
|
|
25
|
+
color: '#60a5fa',
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const chartData = [
|
|
30
|
+
{ month: 'January', desktop: 186, mobile: 80 },
|
|
31
|
+
{ month: 'February', desktop: 305, mobile: 200 },
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
describe('Chart', () => {
|
|
35
|
+
it('renders correctly', () => {
|
|
36
|
+
render(
|
|
37
|
+
<ChartContainer config={chartConfig} className="min-h-[200px] w-full">
|
|
38
|
+
<BarChart accessibilityLayer data={chartData} width={500} height={300}>
|
|
39
|
+
<CartesianGrid vertical={false} />
|
|
40
|
+
<XAxis
|
|
41
|
+
dataKey="month"
|
|
42
|
+
tickLine={false}
|
|
43
|
+
tickMargin={10}
|
|
44
|
+
axisLine={false}
|
|
45
|
+
tickFormatter={(value) => value.slice(0, 3)}
|
|
46
|
+
/>
|
|
47
|
+
<ChartTooltip content={<ChartTooltipContent />} />
|
|
48
|
+
<Bar dataKey="desktop" fill="var(--color-desktop)" radius={4} />
|
|
49
|
+
<Bar dataKey="mobile" fill="var(--color-mobile)" radius={4} />
|
|
50
|
+
</BarChart>
|
|
51
|
+
</ChartContainer>,
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
// Recharts renders SVGs. We can check if the container renders.
|
|
55
|
+
// The accessibilityLayer prop on BarChart adds role="application" or similar?
|
|
56
|
+
// Let's check for the chart container.
|
|
57
|
+
// The ChartContainer adds data-chart attribute.
|
|
58
|
+
// But we can check for text.
|
|
59
|
+
expect(screen.getByText('Jan')).toBeInTheDocument();
|
|
60
|
+
expect(screen.getByText('Feb')).toBeInTheDocument();
|
|
61
|
+
});
|
|
62
|
+
});
|