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