@moontra/moonui 2.0.8 → 2.0.9
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/package.json +9 -2
- package/src/__tests__/use-intersection-observer.test.tsx +216 -0
- package/src/__tests__/use-local-storage.test.tsx +174 -0
- package/src/__tests__/use-pro-access.test.tsx +183 -0
- package/src/components/ui/__tests__/accordion.test.tsx +571 -0
- package/src/components/ui/__tests__/alert.test.tsx +484 -0
- package/src/components/ui/__tests__/aspect-ratio.test.tsx +492 -0
- package/src/components/ui/__tests__/avatar.test.tsx +382 -0
- package/src/components/ui/__tests__/badge.test.tsx +364 -0
- package/src/components/ui/__tests__/breadcrumb.test.tsx +687 -0
- package/src/components/ui/__tests__/button.test.tsx +91 -0
- package/src/components/ui/__tests__/card.test.tsx +104 -0
- package/src/components/ui/__tests__/checkbox.test.tsx +591 -0
- package/src/components/ui/__tests__/collapsible.test.tsx +592 -0
- package/src/components/ui/__tests__/color-picker.test.tsx +365 -0
- package/src/components/ui/__tests__/command.test.tsx +677 -0
- package/src/components/ui/__tests__/data-table.test.tsx +256 -0
- package/src/components/ui/__tests__/date-picker.test.tsx +320 -0
- package/src/components/ui/__tests__/dialog.test.tsx +764 -0
- package/src/components/ui/__tests__/input.test.tsx +318 -0
- package/src/components/ui/__tests__/label.test.tsx +103 -0
- package/src/components/ui/__tests__/popover.test.tsx +637 -0
- package/src/components/ui/__tests__/progress.test.tsx +382 -0
- package/src/components/ui/__tests__/radio-group.test.tsx +555 -0
- package/src/components/ui/__tests__/select.test.tsx +705 -0
- package/src/components/ui/__tests__/skeleton.test.tsx +253 -0
- package/src/components/ui/__tests__/slider.test.tsx +493 -0
- package/src/components/ui/__tests__/switch.test.tsx +372 -0
- package/src/components/ui/__tests__/table.test.tsx +824 -0
- package/src/components/ui/__tests__/tabs.test.tsx +887 -0
- package/src/components/ui/__tests__/toast.test.tsx +458 -0
- package/src/components/ui/__tests__/tooltip.test.tsx +583 -0
- package/src/components/ui/accordion.tsx +63 -0
- package/src/components/ui/alert.tsx +130 -0
- package/src/components/ui/aspect-ratio.tsx +72 -0
- package/src/components/ui/avatar.tsx +135 -0
- package/src/components/ui/badge.tsx +225 -0
- package/src/components/ui/breadcrumb.tsx +207 -0
- package/src/components/ui/button.stories.tsx +162 -0
- package/src/components/ui/button.tsx +221 -0
- package/src/components/ui/calendar.tsx +262 -0
- package/src/components/ui/card.stories.tsx +208 -0
- package/src/components/ui/card.tsx +141 -0
- package/src/components/ui/checkbox.tsx +256 -0
- package/src/components/ui/collapsible.tsx +129 -0
- package/src/components/ui/color-picker.tsx +664 -0
- package/src/components/ui/command.tsx +218 -0
- package/src/components/ui/data-table.stories.tsx +509 -0
- package/src/components/ui/data-table.tsx +623 -0
- package/src/components/ui/date-picker.stories.tsx +321 -0
- package/src/components/ui/date-picker.tsx +603 -0
- package/src/components/ui/dialog.tsx +332 -0
- package/src/components/ui/dropdown-menu.tsx +200 -0
- package/src/components/ui/file-upload.tsx +400 -0
- package/src/components/ui/github-stars.tsx +201 -0
- package/src/components/ui/index.ts +12 -0
- package/src/components/ui/input.stories.tsx +255 -0
- package/src/components/ui/input.tsx +219 -0
- package/src/components/ui/label.tsx +26 -0
- package/src/components/ui/locked-component.tsx +215 -0
- package/src/components/ui/moon-logo.tsx +97 -0
- package/src/components/ui/pagination.tsx +116 -0
- package/src/components/ui/popover.tsx +183 -0
- package/src/components/ui/progress.tsx +182 -0
- package/src/components/ui/radio-group.tsx +243 -0
- package/src/components/ui/select.tsx +273 -0
- package/src/components/ui/separator.tsx +140 -0
- package/src/components/ui/simple-editor.tsx +652 -0
- package/src/components/ui/skeleton.tsx +351 -0
- package/src/components/ui/slider.tsx +351 -0
- package/src/components/ui/switch.tsx +83 -0
- package/src/components/ui/table.tsx +322 -0
- package/src/components/ui/tabs.tsx +195 -0
- package/src/components/ui/textarea.tsx +46 -0
- package/src/components/ui/toast.tsx +313 -0
- package/src/components/ui/toggle.tsx +47 -0
- package/src/components/ui/tooltip.tsx +152 -0
- package/src/docs/theme-system.md +1194 -0
- package/src/index.tsx +39 -0
- package/src/lib/micro-interactions.ts +255 -0
- package/src/lib/theme.tsx +398 -0
- package/src/lib/utils.ts +69 -0
- package/src/styles/design-system.css +365 -0
- package/src/styles/index.css +4 -0
- package/src/styles/tailwind.css +6 -0
- package/src/styles/tokens.css +453 -0
- package/src/use-intersection-observer.tsx +154 -0
- package/src/use-local-storage.tsx +71 -0
- package/src/use-paddle.ts +138 -0
- package/src/use-performance-optimizer.ts +379 -0
- package/src/use-pro-access.ts +141 -0
- package/src/use-scroll-animation.ts +221 -0
- package/src/use-subscription.ts +37 -0
- package/src/use-toast.ts +32 -0
|
@@ -0,0 +1,571 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { render, screen, fireEvent } from '@testing-library/react'
|
|
3
|
+
import '@testing-library/jest-dom'
|
|
4
|
+
import { Accordion, AccordionItem, AccordionTrigger, AccordionContent } from '../accordion'
|
|
5
|
+
|
|
6
|
+
describe('Accordion Components', () => {
|
|
7
|
+
describe('Accordion Component', () => {
|
|
8
|
+
it('renders correctly with default props', () => {
|
|
9
|
+
render(
|
|
10
|
+
<Accordion data-testid="accordion">
|
|
11
|
+
<AccordionItem value="item-1">
|
|
12
|
+
<AccordionTrigger>Test Trigger</AccordionTrigger>
|
|
13
|
+
<AccordionContent>Test Content</AccordionContent>
|
|
14
|
+
</AccordionItem>
|
|
15
|
+
</Accordion>
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
const accordion = screen.getByTestId('accordion')
|
|
19
|
+
expect(accordion).toBeInTheDocument()
|
|
20
|
+
expect(screen.getByText('Test Trigger')).toBeInTheDocument()
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
it('supports single type accordion', () => {
|
|
24
|
+
render(
|
|
25
|
+
<Accordion type="single" collapsible data-testid="accordion">
|
|
26
|
+
<AccordionItem value="item-1">
|
|
27
|
+
<AccordionTrigger>Item 1</AccordionTrigger>
|
|
28
|
+
<AccordionContent>Content 1</AccordionContent>
|
|
29
|
+
</AccordionItem>
|
|
30
|
+
<AccordionItem value="item-2">
|
|
31
|
+
<AccordionTrigger>Item 2</AccordionTrigger>
|
|
32
|
+
<AccordionContent>Content 2</AccordionContent>
|
|
33
|
+
</AccordionItem>
|
|
34
|
+
</Accordion>
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
const accordion = screen.getByTestId('accordion')
|
|
38
|
+
expect(accordion).toBeInTheDocument()
|
|
39
|
+
expect(screen.getByText('Item 1')).toBeInTheDocument()
|
|
40
|
+
expect(screen.getByText('Item 2')).toBeInTheDocument()
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
it('supports multiple type accordion', () => {
|
|
44
|
+
render(
|
|
45
|
+
<Accordion type="multiple" data-testid="accordion">
|
|
46
|
+
<AccordionItem value="item-1">
|
|
47
|
+
<AccordionTrigger>Item 1</AccordionTrigger>
|
|
48
|
+
<AccordionContent>Content 1</AccordionContent>
|
|
49
|
+
</AccordionItem>
|
|
50
|
+
<AccordionItem value="item-2">
|
|
51
|
+
<AccordionTrigger>Item 2</AccordionTrigger>
|
|
52
|
+
<AccordionContent>Content 2</AccordionContent>
|
|
53
|
+
</AccordionItem>
|
|
54
|
+
</Accordion>
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
const accordion = screen.getByTestId('accordion')
|
|
58
|
+
expect(accordion).toBeInTheDocument()
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
it('passes through HTML attributes', () => {
|
|
62
|
+
render(
|
|
63
|
+
<Accordion id="custom-accordion" data-custom="value" data-testid="accordion">
|
|
64
|
+
<AccordionItem value="item-1">
|
|
65
|
+
<AccordionTrigger>Test</AccordionTrigger>
|
|
66
|
+
<AccordionContent>Content</AccordionContent>
|
|
67
|
+
</AccordionItem>
|
|
68
|
+
</Accordion>
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
const accordion = screen.getByTestId('accordion')
|
|
72
|
+
expect(accordion).toHaveAttribute('id', 'custom-accordion')
|
|
73
|
+
expect(accordion).toHaveAttribute('data-custom', 'value')
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
it('handles controlled state', () => {
|
|
77
|
+
const TestComponent = () => {
|
|
78
|
+
const [value, setValue] = React.useState<string>('')
|
|
79
|
+
|
|
80
|
+
return (
|
|
81
|
+
<Accordion type="single" value={value} onValueChange={setValue} data-testid="accordion">
|
|
82
|
+
<AccordionItem value="item-1">
|
|
83
|
+
<AccordionTrigger>Item 1</AccordionTrigger>
|
|
84
|
+
<AccordionContent>Content 1</AccordionContent>
|
|
85
|
+
</AccordionItem>
|
|
86
|
+
</Accordion>
|
|
87
|
+
)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
render(<TestComponent />)
|
|
91
|
+
const accordion = screen.getByTestId('accordion')
|
|
92
|
+
expect(accordion).toBeInTheDocument()
|
|
93
|
+
})
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
describe('AccordionItem Component', () => {
|
|
97
|
+
it('renders correctly with default props', () => {
|
|
98
|
+
render(
|
|
99
|
+
<Accordion>
|
|
100
|
+
<AccordionItem value="item-1" data-testid="accordion-item">
|
|
101
|
+
<AccordionTrigger>Test Trigger</AccordionTrigger>
|
|
102
|
+
<AccordionContent>Test Content</AccordionContent>
|
|
103
|
+
</AccordionItem>
|
|
104
|
+
</Accordion>
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
const item = screen.getByTestId('accordion-item')
|
|
108
|
+
expect(item).toBeInTheDocument()
|
|
109
|
+
expect(item).toHaveAttribute('data-state', 'closed')
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
it('applies custom className', () => {
|
|
113
|
+
render(
|
|
114
|
+
<Accordion>
|
|
115
|
+
<AccordionItem value="item-1" className="custom-item" data-testid="accordion-item">
|
|
116
|
+
<AccordionTrigger>Test</AccordionTrigger>
|
|
117
|
+
<AccordionContent>Content</AccordionContent>
|
|
118
|
+
</AccordionItem>
|
|
119
|
+
</Accordion>
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
const item = screen.getByTestId('accordion-item')
|
|
123
|
+
expect(item).toHaveClass('custom-item')
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
it('has correct default styling', () => {
|
|
127
|
+
render(
|
|
128
|
+
<Accordion>
|
|
129
|
+
<AccordionItem value="item-1" data-testid="accordion-item">
|
|
130
|
+
<AccordionTrigger>Test</AccordionTrigger>
|
|
131
|
+
<AccordionContent>Content</AccordionContent>
|
|
132
|
+
</AccordionItem>
|
|
133
|
+
</Accordion>
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
const item = screen.getByTestId('accordion-item')
|
|
137
|
+
expect(item).toHaveClass('border-b')
|
|
138
|
+
expect(item).toHaveClass('border-gray-200')
|
|
139
|
+
expect(item).toHaveClass('dark:border-gray-800')
|
|
140
|
+
})
|
|
141
|
+
|
|
142
|
+
it('forwards ref correctly', () => {
|
|
143
|
+
const ref = React.createRef<HTMLDivElement>()
|
|
144
|
+
render(
|
|
145
|
+
<Accordion>
|
|
146
|
+
<AccordionItem ref={ref} value="item-1" data-testid="accordion-item">
|
|
147
|
+
<AccordionTrigger>Test</AccordionTrigger>
|
|
148
|
+
<AccordionContent>Content</AccordionContent>
|
|
149
|
+
</AccordionItem>
|
|
150
|
+
</Accordion>
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
expect(ref.current).toBeInstanceOf(HTMLDivElement)
|
|
154
|
+
})
|
|
155
|
+
|
|
156
|
+
it('maintains displayName', () => {
|
|
157
|
+
expect(AccordionItem.displayName).toBe('AccordionItem')
|
|
158
|
+
})
|
|
159
|
+
|
|
160
|
+
it('passes through HTML attributes', () => {
|
|
161
|
+
render(
|
|
162
|
+
<Accordion>
|
|
163
|
+
<AccordionItem value="item-1" id="custom-item" data-custom="value" data-testid="accordion-item">
|
|
164
|
+
<AccordionTrigger>Test</AccordionTrigger>
|
|
165
|
+
<AccordionContent>Content</AccordionContent>
|
|
166
|
+
</AccordionItem>
|
|
167
|
+
</Accordion>
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
const item = screen.getByTestId('accordion-item')
|
|
171
|
+
expect(item).toHaveAttribute('id', 'custom-item')
|
|
172
|
+
expect(item).toHaveAttribute('data-custom', 'value')
|
|
173
|
+
})
|
|
174
|
+
})
|
|
175
|
+
|
|
176
|
+
describe('AccordionTrigger Component', () => {
|
|
177
|
+
it('renders correctly with default props', () => {
|
|
178
|
+
render(
|
|
179
|
+
<Accordion>
|
|
180
|
+
<AccordionItem value="item-1">
|
|
181
|
+
<AccordionTrigger data-testid="accordion-trigger">Test Trigger</AccordionTrigger>
|
|
182
|
+
<AccordionContent>Test Content</AccordionContent>
|
|
183
|
+
</AccordionItem>
|
|
184
|
+
</Accordion>
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
const trigger = screen.getByTestId('accordion-trigger')
|
|
188
|
+
expect(trigger).toBeInTheDocument()
|
|
189
|
+
expect(trigger).toHaveTextContent('Test Trigger')
|
|
190
|
+
expect(trigger).toHaveAttribute('type', 'button')
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
it('applies custom className', () => {
|
|
194
|
+
render(
|
|
195
|
+
<Accordion>
|
|
196
|
+
<AccordionItem value="item-1">
|
|
197
|
+
<AccordionTrigger className="custom-trigger" data-testid="accordion-trigger">Test</AccordionTrigger>
|
|
198
|
+
<AccordionContent>Content</AccordionContent>
|
|
199
|
+
</AccordionItem>
|
|
200
|
+
</Accordion>
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
const trigger = screen.getByTestId('accordion-trigger')
|
|
204
|
+
expect(trigger).toHaveClass('custom-trigger')
|
|
205
|
+
})
|
|
206
|
+
|
|
207
|
+
it('has correct default styling', () => {
|
|
208
|
+
render(
|
|
209
|
+
<Accordion>
|
|
210
|
+
<AccordionItem value="item-1">
|
|
211
|
+
<AccordionTrigger data-testid="accordion-trigger">Test</AccordionTrigger>
|
|
212
|
+
<AccordionContent>Content</AccordionContent>
|
|
213
|
+
</AccordionItem>
|
|
214
|
+
</Accordion>
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
const trigger = screen.getByTestId('accordion-trigger')
|
|
218
|
+
expect(trigger).toHaveClass('flex')
|
|
219
|
+
expect(trigger).toHaveClass('flex-1')
|
|
220
|
+
expect(trigger).toHaveClass('items-center')
|
|
221
|
+
expect(trigger).toHaveClass('justify-between')
|
|
222
|
+
expect(trigger).toHaveClass('py-4')
|
|
223
|
+
expect(trigger).toHaveClass('font-medium')
|
|
224
|
+
})
|
|
225
|
+
|
|
226
|
+
it('renders chevron icon', () => {
|
|
227
|
+
render(
|
|
228
|
+
<Accordion>
|
|
229
|
+
<AccordionItem value="item-1">
|
|
230
|
+
<AccordionTrigger data-testid="accordion-trigger">Test</AccordionTrigger>
|
|
231
|
+
<AccordionContent>Content</AccordionContent>
|
|
232
|
+
</AccordionItem>
|
|
233
|
+
</Accordion>
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
const trigger = screen.getByTestId('accordion-trigger')
|
|
237
|
+
const chevron = trigger.querySelector('svg')
|
|
238
|
+
expect(chevron).toBeInTheDocument()
|
|
239
|
+
expect(chevron).toHaveClass('h-4')
|
|
240
|
+
expect(chevron).toHaveClass('w-4')
|
|
241
|
+
expect(chevron).toHaveClass('shrink-0')
|
|
242
|
+
})
|
|
243
|
+
|
|
244
|
+
it('handles click events', () => {
|
|
245
|
+
render(
|
|
246
|
+
<Accordion type="single" collapsible>
|
|
247
|
+
<AccordionItem value="item-1">
|
|
248
|
+
<AccordionTrigger data-testid="accordion-trigger">Test</AccordionTrigger>
|
|
249
|
+
<AccordionContent>Content</AccordionContent>
|
|
250
|
+
</AccordionItem>
|
|
251
|
+
</Accordion>
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
const trigger = screen.getByTestId('accordion-trigger')
|
|
255
|
+
fireEvent.click(trigger)
|
|
256
|
+
|
|
257
|
+
// Check if the item is now open
|
|
258
|
+
const item = trigger.closest('[data-state]')
|
|
259
|
+
expect(item).toHaveAttribute('data-state', 'open')
|
|
260
|
+
})
|
|
261
|
+
|
|
262
|
+
it('toggles chevron rotation when opened', () => {
|
|
263
|
+
render(
|
|
264
|
+
<Accordion type="single" collapsible>
|
|
265
|
+
<AccordionItem value="item-1">
|
|
266
|
+
<AccordionTrigger data-testid="accordion-trigger">Test</AccordionTrigger>
|
|
267
|
+
<AccordionContent>Content</AccordionContent>
|
|
268
|
+
</AccordionItem>
|
|
269
|
+
</Accordion>
|
|
270
|
+
)
|
|
271
|
+
|
|
272
|
+
const trigger = screen.getByTestId('accordion-trigger')
|
|
273
|
+
fireEvent.click(trigger)
|
|
274
|
+
|
|
275
|
+
// Check if chevron has rotation class
|
|
276
|
+
expect(trigger).toHaveClass('[&[data-state=open]>svg]:rotate-180')
|
|
277
|
+
})
|
|
278
|
+
|
|
279
|
+
it('forwards ref correctly', () => {
|
|
280
|
+
const ref = React.createRef<HTMLButtonElement>()
|
|
281
|
+
render(
|
|
282
|
+
<Accordion>
|
|
283
|
+
<AccordionItem value="item-1">
|
|
284
|
+
<AccordionTrigger ref={ref} data-testid="accordion-trigger">Test</AccordionTrigger>
|
|
285
|
+
<AccordionContent>Content</AccordionContent>
|
|
286
|
+
</AccordionItem>
|
|
287
|
+
</Accordion>
|
|
288
|
+
)
|
|
289
|
+
|
|
290
|
+
expect(ref.current).toBeInstanceOf(HTMLButtonElement)
|
|
291
|
+
})
|
|
292
|
+
|
|
293
|
+
it('passes through HTML attributes', () => {
|
|
294
|
+
render(
|
|
295
|
+
<Accordion>
|
|
296
|
+
<AccordionItem value="item-1">
|
|
297
|
+
<AccordionTrigger id="custom-trigger" data-custom="value" data-testid="accordion-trigger">Test</AccordionTrigger>
|
|
298
|
+
<AccordionContent>Content</AccordionContent>
|
|
299
|
+
</AccordionItem>
|
|
300
|
+
</Accordion>
|
|
301
|
+
)
|
|
302
|
+
|
|
303
|
+
const trigger = screen.getByTestId('accordion-trigger')
|
|
304
|
+
expect(trigger).toHaveAttribute('id', 'custom-trigger')
|
|
305
|
+
expect(trigger).toHaveAttribute('data-custom', 'value')
|
|
306
|
+
})
|
|
307
|
+
})
|
|
308
|
+
|
|
309
|
+
describe('AccordionContent Component', () => {
|
|
310
|
+
it('renders correctly when accordion is open', () => {
|
|
311
|
+
render(
|
|
312
|
+
<Accordion type="single" defaultValue="item-1">
|
|
313
|
+
<AccordionItem value="item-1">
|
|
314
|
+
<AccordionTrigger>Test Trigger</AccordionTrigger>
|
|
315
|
+
<AccordionContent data-testid="accordion-content">Test Content</AccordionContent>
|
|
316
|
+
</AccordionItem>
|
|
317
|
+
</Accordion>
|
|
318
|
+
)
|
|
319
|
+
|
|
320
|
+
const content = screen.getByTestId('accordion-content')
|
|
321
|
+
expect(content).toBeInTheDocument()
|
|
322
|
+
expect(content).toHaveTextContent('Test Content')
|
|
323
|
+
})
|
|
324
|
+
|
|
325
|
+
it('applies custom className', () => {
|
|
326
|
+
render(
|
|
327
|
+
<Accordion type="single" defaultValue="item-1">
|
|
328
|
+
<AccordionItem value="item-1">
|
|
329
|
+
<AccordionTrigger>Test</AccordionTrigger>
|
|
330
|
+
<AccordionContent className="custom-content" data-testid="accordion-content">Content</AccordionContent>
|
|
331
|
+
</AccordionItem>
|
|
332
|
+
</Accordion>
|
|
333
|
+
)
|
|
334
|
+
|
|
335
|
+
const content = screen.getByTestId('accordion-content')
|
|
336
|
+
expect(content).toHaveClass('custom-content')
|
|
337
|
+
})
|
|
338
|
+
|
|
339
|
+
it('has correct default styling', () => {
|
|
340
|
+
render(
|
|
341
|
+
<Accordion type="single" defaultValue="item-1">
|
|
342
|
+
<AccordionItem value="item-1">
|
|
343
|
+
<AccordionTrigger>Test</AccordionTrigger>
|
|
344
|
+
<AccordionContent data-testid="accordion-content">Content</AccordionContent>
|
|
345
|
+
</AccordionItem>
|
|
346
|
+
</Accordion>
|
|
347
|
+
)
|
|
348
|
+
|
|
349
|
+
const content = screen.getByTestId('accordion-content')
|
|
350
|
+
expect(content).toHaveClass('overflow-hidden')
|
|
351
|
+
expect(content).toHaveClass('text-sm')
|
|
352
|
+
expect(content).toHaveClass('text-gray-700')
|
|
353
|
+
expect(content).toHaveClass('dark:text-gray-300')
|
|
354
|
+
})
|
|
355
|
+
|
|
356
|
+
it('has animation classes', () => {
|
|
357
|
+
render(
|
|
358
|
+
<Accordion type="single" defaultValue="item-1">
|
|
359
|
+
<AccordionItem value="item-1">
|
|
360
|
+
<AccordionTrigger>Test</AccordionTrigger>
|
|
361
|
+
<AccordionContent data-testid="accordion-content">Content</AccordionContent>
|
|
362
|
+
</AccordionItem>
|
|
363
|
+
</Accordion>
|
|
364
|
+
)
|
|
365
|
+
|
|
366
|
+
const content = screen.getByTestId('accordion-content')
|
|
367
|
+
expect(content).toHaveClass('data-[state=closed]:animate-accordion-up')
|
|
368
|
+
expect(content).toHaveClass('data-[state=open]:animate-accordion-down')
|
|
369
|
+
})
|
|
370
|
+
|
|
371
|
+
it('renders content wrapper with correct styling', () => {
|
|
372
|
+
render(
|
|
373
|
+
<Accordion type="single" defaultValue="item-1">
|
|
374
|
+
<AccordionItem value="item-1">
|
|
375
|
+
<AccordionTrigger>Test</AccordionTrigger>
|
|
376
|
+
<AccordionContent data-testid="accordion-content">Test Content</AccordionContent>
|
|
377
|
+
</AccordionItem>
|
|
378
|
+
</Accordion>
|
|
379
|
+
)
|
|
380
|
+
|
|
381
|
+
const content = screen.getByTestId('accordion-content')
|
|
382
|
+
const wrapper = content.querySelector('div')
|
|
383
|
+
expect(wrapper).toBeInTheDocument()
|
|
384
|
+
expect(wrapper).toHaveClass('pb-4')
|
|
385
|
+
expect(wrapper).toHaveClass('pt-0')
|
|
386
|
+
expect(wrapper).toHaveTextContent('Test Content')
|
|
387
|
+
})
|
|
388
|
+
|
|
389
|
+
it('forwards ref correctly', () => {
|
|
390
|
+
const ref = React.createRef<HTMLDivElement>()
|
|
391
|
+
render(
|
|
392
|
+
<Accordion type="single" defaultValue="item-1">
|
|
393
|
+
<AccordionItem value="item-1">
|
|
394
|
+
<AccordionTrigger>Test</AccordionTrigger>
|
|
395
|
+
<AccordionContent ref={ref} data-testid="accordion-content">Content</AccordionContent>
|
|
396
|
+
</AccordionItem>
|
|
397
|
+
</Accordion>
|
|
398
|
+
)
|
|
399
|
+
|
|
400
|
+
expect(ref.current).toBeInstanceOf(HTMLDivElement)
|
|
401
|
+
})
|
|
402
|
+
|
|
403
|
+
it('passes through HTML attributes', () => {
|
|
404
|
+
render(
|
|
405
|
+
<Accordion type="single" defaultValue="item-1">
|
|
406
|
+
<AccordionItem value="item-1">
|
|
407
|
+
<AccordionTrigger>Test</AccordionTrigger>
|
|
408
|
+
<AccordionContent id="custom-content" data-custom="value" data-testid="accordion-content">Content</AccordionContent>
|
|
409
|
+
</AccordionItem>
|
|
410
|
+
</Accordion>
|
|
411
|
+
)
|
|
412
|
+
|
|
413
|
+
const content = screen.getByTestId('accordion-content')
|
|
414
|
+
expect(content).toHaveAttribute('id', 'custom-content')
|
|
415
|
+
expect(content).toHaveAttribute('data-custom', 'value')
|
|
416
|
+
})
|
|
417
|
+
})
|
|
418
|
+
|
|
419
|
+
describe('Complex Combinations', () => {
|
|
420
|
+
it('renders multiple accordion items', () => {
|
|
421
|
+
render(
|
|
422
|
+
<Accordion type="single" collapsible data-testid="accordion">
|
|
423
|
+
<AccordionItem value="item-1">
|
|
424
|
+
<AccordionTrigger>Item 1</AccordionTrigger>
|
|
425
|
+
<AccordionContent>Content 1</AccordionContent>
|
|
426
|
+
</AccordionItem>
|
|
427
|
+
<AccordionItem value="item-2">
|
|
428
|
+
<AccordionTrigger>Item 2</AccordionTrigger>
|
|
429
|
+
<AccordionContent>Content 2</AccordionContent>
|
|
430
|
+
</AccordionItem>
|
|
431
|
+
<AccordionItem value="item-3">
|
|
432
|
+
<AccordionTrigger>Item 3</AccordionTrigger>
|
|
433
|
+
<AccordionContent>Content 3</AccordionContent>
|
|
434
|
+
</AccordionItem>
|
|
435
|
+
</Accordion>
|
|
436
|
+
)
|
|
437
|
+
|
|
438
|
+
expect(screen.getByText('Item 1')).toBeInTheDocument()
|
|
439
|
+
expect(screen.getByText('Item 2')).toBeInTheDocument()
|
|
440
|
+
expect(screen.getByText('Item 3')).toBeInTheDocument()
|
|
441
|
+
})
|
|
442
|
+
|
|
443
|
+
it('handles single type accordion interaction', () => {
|
|
444
|
+
render(
|
|
445
|
+
<Accordion type="single" collapsible>
|
|
446
|
+
<AccordionItem value="item-1">
|
|
447
|
+
<AccordionTrigger data-testid="trigger-1">Item 1</AccordionTrigger>
|
|
448
|
+
<AccordionContent>Content 1</AccordionContent>
|
|
449
|
+
</AccordionItem>
|
|
450
|
+
<AccordionItem value="item-2">
|
|
451
|
+
<AccordionTrigger data-testid="trigger-2">Item 2</AccordionTrigger>
|
|
452
|
+
<AccordionContent>Content 2</AccordionContent>
|
|
453
|
+
</AccordionItem>
|
|
454
|
+
</Accordion>
|
|
455
|
+
)
|
|
456
|
+
|
|
457
|
+
const trigger1 = screen.getByTestId('trigger-1')
|
|
458
|
+
const trigger2 = screen.getByTestId('trigger-2')
|
|
459
|
+
|
|
460
|
+
// Open first item
|
|
461
|
+
fireEvent.click(trigger1)
|
|
462
|
+
expect(trigger1.closest('[data-state]')).toHaveAttribute('data-state', 'open')
|
|
463
|
+
|
|
464
|
+
// Open second item (should close first)
|
|
465
|
+
fireEvent.click(trigger2)
|
|
466
|
+
expect(trigger1.closest('[data-state]')).toHaveAttribute('data-state', 'closed')
|
|
467
|
+
expect(trigger2.closest('[data-state]')).toHaveAttribute('data-state', 'open')
|
|
468
|
+
})
|
|
469
|
+
|
|
470
|
+
it('handles multiple type accordion interaction', () => {
|
|
471
|
+
render(
|
|
472
|
+
<Accordion type="multiple">
|
|
473
|
+
<AccordionItem value="item-1">
|
|
474
|
+
<AccordionTrigger data-testid="trigger-1">Item 1</AccordionTrigger>
|
|
475
|
+
<AccordionContent>Content 1</AccordionContent>
|
|
476
|
+
</AccordionItem>
|
|
477
|
+
<AccordionItem value="item-2">
|
|
478
|
+
<AccordionTrigger data-testid="trigger-2">Item 2</AccordionTrigger>
|
|
479
|
+
<AccordionContent>Content 2</AccordionContent>
|
|
480
|
+
</AccordionItem>
|
|
481
|
+
</Accordion>
|
|
482
|
+
)
|
|
483
|
+
|
|
484
|
+
const trigger1 = screen.getByTestId('trigger-1')
|
|
485
|
+
const trigger2 = screen.getByTestId('trigger-2')
|
|
486
|
+
|
|
487
|
+
// Open both items
|
|
488
|
+
fireEvent.click(trigger1)
|
|
489
|
+
fireEvent.click(trigger2)
|
|
490
|
+
|
|
491
|
+
expect(trigger1.closest('[data-state]')).toHaveAttribute('data-state', 'open')
|
|
492
|
+
expect(trigger2.closest('[data-state]')).toHaveAttribute('data-state', 'open')
|
|
493
|
+
})
|
|
494
|
+
|
|
495
|
+
it('renders with all custom props', () => {
|
|
496
|
+
render(
|
|
497
|
+
<Accordion type="single" collapsible className="custom-accordion" data-testid="accordion">
|
|
498
|
+
<AccordionItem value="item-1" className="custom-item">
|
|
499
|
+
<AccordionTrigger className="custom-trigger">Custom Item</AccordionTrigger>
|
|
500
|
+
<AccordionContent className="custom-content">Custom Content</AccordionContent>
|
|
501
|
+
</AccordionItem>
|
|
502
|
+
</Accordion>
|
|
503
|
+
)
|
|
504
|
+
|
|
505
|
+
const accordion = screen.getByTestId('accordion')
|
|
506
|
+
expect(accordion).toHaveClass('custom-accordion')
|
|
507
|
+
|
|
508
|
+
const item = accordion.querySelector('[data-state]')
|
|
509
|
+
expect(item).toHaveClass('custom-item')
|
|
510
|
+
|
|
511
|
+
const trigger = screen.getByText('Custom Item')
|
|
512
|
+
expect(trigger).toHaveClass('custom-trigger')
|
|
513
|
+
})
|
|
514
|
+
})
|
|
515
|
+
|
|
516
|
+
describe('Edge Cases', () => {
|
|
517
|
+
it('handles empty accordion', () => {
|
|
518
|
+
render(<Accordion data-testid="accordion" />)
|
|
519
|
+
const accordion = screen.getByTestId('accordion')
|
|
520
|
+
expect(accordion).toBeInTheDocument()
|
|
521
|
+
})
|
|
522
|
+
|
|
523
|
+
it('handles accordion with no content', () => {
|
|
524
|
+
render(
|
|
525
|
+
<Accordion>
|
|
526
|
+
<AccordionItem value="item-1">
|
|
527
|
+
<AccordionTrigger>Empty Item</AccordionTrigger>
|
|
528
|
+
<AccordionContent></AccordionContent>
|
|
529
|
+
</AccordionItem>
|
|
530
|
+
</Accordion>
|
|
531
|
+
)
|
|
532
|
+
|
|
533
|
+
expect(screen.getByText('Empty Item')).toBeInTheDocument()
|
|
534
|
+
})
|
|
535
|
+
|
|
536
|
+
it('handles accordion with complex content', () => {
|
|
537
|
+
render(
|
|
538
|
+
<Accordion type="single" defaultValue="item-1">
|
|
539
|
+
<AccordionItem value="item-1">
|
|
540
|
+
<AccordionTrigger>Complex Item</AccordionTrigger>
|
|
541
|
+
<AccordionContent>
|
|
542
|
+
<div>
|
|
543
|
+
<p>Paragraph 1</p>
|
|
544
|
+
<p>Paragraph 2</p>
|
|
545
|
+
<button>Action Button</button>
|
|
546
|
+
</div>
|
|
547
|
+
</AccordionContent>
|
|
548
|
+
</AccordionItem>
|
|
549
|
+
</Accordion>
|
|
550
|
+
)
|
|
551
|
+
|
|
552
|
+
expect(screen.getByText('Paragraph 1')).toBeInTheDocument()
|
|
553
|
+
expect(screen.getByText('Paragraph 2')).toBeInTheDocument()
|
|
554
|
+
expect(screen.getByText('Action Button')).toBeInTheDocument()
|
|
555
|
+
})
|
|
556
|
+
|
|
557
|
+
it('handles disabled accordion item', () => {
|
|
558
|
+
render(
|
|
559
|
+
<Accordion>
|
|
560
|
+
<AccordionItem value="item-1" disabled>
|
|
561
|
+
<AccordionTrigger data-testid="disabled-trigger">Disabled Item</AccordionTrigger>
|
|
562
|
+
<AccordionContent>Content</AccordionContent>
|
|
563
|
+
</AccordionItem>
|
|
564
|
+
</Accordion>
|
|
565
|
+
)
|
|
566
|
+
|
|
567
|
+
const trigger = screen.getByTestId('disabled-trigger')
|
|
568
|
+
expect(trigger).toBeDisabled()
|
|
569
|
+
})
|
|
570
|
+
})
|
|
571
|
+
})
|