@moontra/moonui 2.0.7 → 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 +26 -19
  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,637 @@
1
+ import React from 'react'
2
+ import { render, screen, fireEvent } from '@testing-library/react'
3
+ import '@testing-library/jest-dom'
4
+ import {
5
+ Popover,
6
+ PopoverTrigger,
7
+ PopoverContent,
8
+ PopoverAnchor,
9
+ PopoverClose,
10
+ PopoverSeparator,
11
+ PopoverHeader,
12
+ PopoverFooter,
13
+ popoverContentVariants,
14
+ } from '../popover'
15
+
16
+ // Mock Radix UI Popover components
17
+ jest.mock('@radix-ui/react-popover', () => {
18
+ const mockForwardRef = (component: any) => {
19
+ const forwardedComponent = (props: any) => component(props, null)
20
+ forwardedComponent.displayName = component.displayName || component.name
21
+ return forwardedComponent
22
+ }
23
+
24
+ return {
25
+ Root: ({ children, ...props }: any) => <div data-testid="popover-root" {...props}>{children}</div>,
26
+ Trigger: mockForwardRef(({ children, ...props }: any, ref: any) => (
27
+ <button ref={ref} data-testid="popover-trigger" {...props}>{children}</button>
28
+ )),
29
+ Content: mockForwardRef(({ children, className, onInteractOutside, ...props }: any, ref: any) => (
30
+ <div
31
+ ref={ref}
32
+ data-testid="popover-content"
33
+ className={className}
34
+ onClick={(e) => onInteractOutside?.(e)}
35
+ {...props}
36
+ >
37
+ {children}
38
+ </div>
39
+ )),
40
+ Anchor: mockForwardRef(({ children, ...props }: any, ref: any) => (
41
+ <div ref={ref} data-testid="popover-anchor" {...props}>{children}</div>
42
+ )),
43
+ Close: mockForwardRef(({ children, ...props }: any, ref: any) => (
44
+ <button ref={ref} data-testid="popover-close" {...props}>{children}</button>
45
+ )),
46
+ }
47
+ })
48
+
49
+ describe('Popover Components', () => {
50
+ describe('Popover Component', () => {
51
+ it('renders correctly with default props', () => {
52
+ render(
53
+ <Popover>
54
+ <PopoverTrigger>Open</PopoverTrigger>
55
+ <PopoverContent>Content</PopoverContent>
56
+ </Popover>
57
+ )
58
+
59
+ // Popover Root doesn't render a DOM element, just manages state
60
+ expect(screen.getByTestId('popover-trigger')).toBeInTheDocument()
61
+ expect(screen.getByTestId('popover-content')).toBeInTheDocument()
62
+ })
63
+
64
+ it('passes through HTML attributes', () => {
65
+ render(
66
+ <Popover data-custom="test" aria-label="Custom popover">
67
+ <PopoverTrigger>Open</PopoverTrigger>
68
+ </Popover>
69
+ )
70
+
71
+ const popover = screen.getByTestId('popover-root')
72
+ expect(popover).toHaveAttribute('data-custom', 'test')
73
+ expect(popover).toHaveAttribute('aria-label', 'Custom popover')
74
+ })
75
+ })
76
+
77
+ describe('PopoverTrigger Component', () => {
78
+ it('renders correctly with default props', () => {
79
+ render(
80
+ <Popover>
81
+ <PopoverTrigger>Open Popover</PopoverTrigger>
82
+ </Popover>
83
+ )
84
+
85
+ const trigger = screen.getByTestId('popover-trigger')
86
+ expect(trigger).toBeInTheDocument()
87
+ expect(trigger).toHaveTextContent('Open Popover')
88
+ })
89
+
90
+ it('handles click events', () => {
91
+ const onClick = jest.fn()
92
+ render(
93
+ <Popover>
94
+ <PopoverTrigger onClick={onClick}>Open</PopoverTrigger>
95
+ </Popover>
96
+ )
97
+
98
+ const trigger = screen.getByTestId('popover-trigger')
99
+ fireEvent.click(trigger)
100
+
101
+ expect(onClick).toHaveBeenCalled()
102
+ })
103
+
104
+ it('passes through HTML attributes', () => {
105
+ render(
106
+ <Popover>
107
+ <PopoverTrigger data-custom="test" aria-label="Open popover">
108
+ Open
109
+ </PopoverTrigger>
110
+ </Popover>
111
+ )
112
+
113
+ const trigger = screen.getByTestId('popover-trigger')
114
+ expect(trigger).toHaveAttribute('data-custom', 'test')
115
+ expect(trigger).toHaveAttribute('aria-label', 'Open popover')
116
+ })
117
+ })
118
+
119
+ describe('PopoverContent Component', () => {
120
+ it('renders correctly with default props', () => {
121
+ render(
122
+ <Popover>
123
+ <PopoverContent>Popover content</PopoverContent>
124
+ </Popover>
125
+ )
126
+
127
+ const content = screen.getByTestId('popover-content')
128
+ expect(content).toBeInTheDocument()
129
+ expect(content).toHaveTextContent('Popover content')
130
+ })
131
+
132
+ it('applies custom className', () => {
133
+ render(
134
+ <Popover>
135
+ <PopoverContent className="custom-class">Content</PopoverContent>
136
+ </Popover>
137
+ )
138
+
139
+ const content = screen.getByTestId('popover-content')
140
+ expect(content).toHaveClass('custom-class')
141
+ })
142
+
143
+ it('renders default variant correctly', () => {
144
+ render(
145
+ <Popover>
146
+ <PopoverContent variant="default">Content</PopoverContent>
147
+ </Popover>
148
+ )
149
+
150
+ const content = screen.getByTestId('popover-content')
151
+ expect(content).toBeInTheDocument()
152
+ })
153
+
154
+ it('renders destructive variant correctly', () => {
155
+ render(
156
+ <Popover>
157
+ <PopoverContent variant="destructive">Content</PopoverContent>
158
+ </Popover>
159
+ )
160
+
161
+ const content = screen.getByTestId('popover-content')
162
+ expect(content).toBeInTheDocument()
163
+ })
164
+
165
+ it('renders outline variant correctly', () => {
166
+ render(
167
+ <Popover>
168
+ <PopoverContent variant="outline">Content</PopoverContent>
169
+ </Popover>
170
+ )
171
+
172
+ const content = screen.getByTestId('popover-content')
173
+ expect(content).toBeInTheDocument()
174
+ })
175
+
176
+ it('renders subtle variant correctly', () => {
177
+ render(
178
+ <Popover>
179
+ <PopoverContent variant="subtle">Content</PopoverContent>
180
+ </Popover>
181
+ )
182
+
183
+ const content = screen.getByTestId('popover-content')
184
+ expect(content).toBeInTheDocument()
185
+ })
186
+
187
+ it('renders sm size correctly', () => {
188
+ render(
189
+ <Popover>
190
+ <PopoverContent size="sm">Content</PopoverContent>
191
+ </Popover>
192
+ )
193
+
194
+ const content = screen.getByTestId('popover-content')
195
+ expect(content).toBeInTheDocument()
196
+ })
197
+
198
+ it('renders default size correctly', () => {
199
+ render(
200
+ <Popover>
201
+ <PopoverContent size="default">Content</PopoverContent>
202
+ </Popover>
203
+ )
204
+
205
+ const content = screen.getByTestId('popover-content')
206
+ expect(content).toBeInTheDocument()
207
+ })
208
+
209
+ it('renders lg size correctly', () => {
210
+ render(
211
+ <Popover>
212
+ <PopoverContent size="lg">Content</PopoverContent>
213
+ </Popover>
214
+ )
215
+
216
+ const content = screen.getByTestId('popover-content')
217
+ expect(content).toBeInTheDocument()
218
+ })
219
+
220
+ it('renders different radius options correctly', () => {
221
+ const radiusOptions = ['none', 'sm', 'default', 'lg', 'full'] as const
222
+
223
+ radiusOptions.forEach((radius) => {
224
+ render(
225
+ <Popover>
226
+ <PopoverContent radius={radius} data-testid={`content-${radius}`}>
227
+ Content
228
+ </PopoverContent>
229
+ </Popover>
230
+ )
231
+
232
+ expect(screen.getByTestId(`content-${radius}`)).toBeInTheDocument()
233
+ })
234
+ })
235
+
236
+ it('renders different shadow options correctly', () => {
237
+ const shadowOptions = ['none', 'sm', 'default', 'md', 'lg', 'xl'] as const
238
+
239
+ shadowOptions.forEach((shadow) => {
240
+ render(
241
+ <Popover>
242
+ <PopoverContent shadow={shadow} data-testid={`content-${shadow}`}>
243
+ Content
244
+ </PopoverContent>
245
+ </Popover>
246
+ )
247
+
248
+ expect(screen.getByTestId(`content-${shadow}`)).toBeInTheDocument()
249
+ })
250
+ })
251
+
252
+ it('handles backdrop prop', () => {
253
+ render(
254
+ <Popover>
255
+ <PopoverContent backdrop={true}>Content</PopoverContent>
256
+ </Popover>
257
+ )
258
+
259
+ const content = screen.getByTestId('popover-content')
260
+ expect(content).toBeInTheDocument()
261
+ })
262
+
263
+ it('handles overlayBackdrop prop', () => {
264
+ render(
265
+ <Popover>
266
+ <PopoverContent overlayBackdrop={true}>Content</PopoverContent>
267
+ </Popover>
268
+ )
269
+
270
+ const content = screen.getByTestId('popover-content')
271
+ expect(content).toBeInTheDocument()
272
+ // Overlay backdrop creates a div with fixed positioning
273
+ expect(document.querySelector('.fixed.inset-0')).toBeInTheDocument()
274
+ })
275
+
276
+ it('handles closeOnInteractOutside prop', () => {
277
+ const onInteractOutside = jest.fn()
278
+ render(
279
+ <Popover>
280
+ <PopoverContent closeOnInteractOutside={false}>
281
+ Content
282
+ </PopoverContent>
283
+ </Popover>
284
+ )
285
+
286
+ const content = screen.getByTestId('popover-content')
287
+ fireEvent.click(content)
288
+
289
+ // Should prevent default when closeOnInteractOutside is false
290
+ expect(content).toBeInTheDocument()
291
+ })
292
+
293
+ it('forwards ref correctly', () => {
294
+ const ref = React.createRef<HTMLDivElement>()
295
+ render(
296
+ <Popover>
297
+ <PopoverContent ref={ref}>Content</PopoverContent>
298
+ </Popover>
299
+ )
300
+
301
+ expect(ref.current).toBeInstanceOf(HTMLDivElement)
302
+ })
303
+
304
+ it('maintains displayName', () => {
305
+ expect(PopoverContent.displayName).toBeDefined()
306
+ })
307
+
308
+ it('passes through HTML attributes', () => {
309
+ render(
310
+ <Popover>
311
+ <PopoverContent data-custom="test" aria-label="Popover content">
312
+ Content
313
+ </PopoverContent>
314
+ </Popover>
315
+ )
316
+
317
+ const content = screen.getByTestId('popover-content')
318
+ expect(content).toHaveAttribute('data-custom', 'test')
319
+ expect(content).toHaveAttribute('aria-label', 'Popover content')
320
+ })
321
+ })
322
+
323
+ describe('PopoverAnchor Component', () => {
324
+ it('renders correctly with default props', () => {
325
+ render(
326
+ <Popover>
327
+ <PopoverAnchor>Anchor</PopoverAnchor>
328
+ </Popover>
329
+ )
330
+
331
+ const anchor = screen.getByTestId('popover-anchor')
332
+ expect(anchor).toBeInTheDocument()
333
+ expect(anchor).toHaveTextContent('Anchor')
334
+ })
335
+
336
+ it('passes through HTML attributes', () => {
337
+ render(
338
+ <Popover>
339
+ <PopoverAnchor data-custom="test">Anchor</PopoverAnchor>
340
+ </Popover>
341
+ )
342
+
343
+ const anchor = screen.getByTestId('popover-anchor')
344
+ expect(anchor).toHaveAttribute('data-custom', 'test')
345
+ })
346
+ })
347
+
348
+ describe('PopoverClose Component', () => {
349
+ it('renders correctly with default props', () => {
350
+ render(
351
+ <Popover>
352
+ <PopoverClose>Close</PopoverClose>
353
+ </Popover>
354
+ )
355
+
356
+ const close = screen.getByTestId('popover-close')
357
+ expect(close).toBeInTheDocument()
358
+ expect(close).toHaveTextContent('Close')
359
+ })
360
+
361
+ it('handles click events', () => {
362
+ const onClick = jest.fn()
363
+ render(
364
+ <Popover>
365
+ <PopoverClose onClick={onClick}>Close</PopoverClose>
366
+ </Popover>
367
+ )
368
+
369
+ const close = screen.getByTestId('popover-close')
370
+ fireEvent.click(close)
371
+
372
+ expect(onClick).toHaveBeenCalled()
373
+ })
374
+
375
+ it('passes through HTML attributes', () => {
376
+ render(
377
+ <Popover>
378
+ <PopoverClose data-custom="test" aria-label="Close popover">
379
+ Close
380
+ </PopoverClose>
381
+ </Popover>
382
+ )
383
+
384
+ const close = screen.getByTestId('popover-close')
385
+ expect(close).toHaveAttribute('data-custom', 'test')
386
+ expect(close).toHaveAttribute('aria-label', 'Close popover')
387
+ })
388
+ })
389
+
390
+ describe('PopoverSeparator Component', () => {
391
+ it('renders correctly with default props', () => {
392
+ render(<PopoverSeparator data-testid="popover-separator" />)
393
+
394
+ const separator = screen.getByTestId('popover-separator')
395
+ expect(separator).toBeInTheDocument()
396
+ expect(separator).toHaveClass('my-2', 'h-px', 'bg-border')
397
+ })
398
+
399
+ it('applies custom className', () => {
400
+ render(<PopoverSeparator className="custom-separator" data-testid="separator" />)
401
+
402
+ const separator = screen.getByTestId('separator')
403
+ expect(separator).toHaveClass('custom-separator')
404
+ expect(separator).toHaveClass('my-2', 'h-px', 'bg-border')
405
+ })
406
+
407
+ it('maintains displayName', () => {
408
+ expect(PopoverSeparator.displayName).toBe('PopoverSeparator')
409
+ })
410
+
411
+ it('passes through HTML attributes', () => {
412
+ render(<PopoverSeparator data-custom="test" data-testid="separator" />)
413
+
414
+ const separator = screen.getByTestId('separator')
415
+ expect(separator).toHaveAttribute('data-custom', 'test')
416
+ })
417
+ })
418
+
419
+ describe('PopoverHeader Component', () => {
420
+ it('renders correctly with default props', () => {
421
+ render(<PopoverHeader data-testid="popover-header">Header</PopoverHeader>)
422
+
423
+ const header = screen.getByTestId('popover-header')
424
+ expect(header).toBeInTheDocument()
425
+ expect(header).toHaveTextContent('Header')
426
+ expect(header).toHaveClass('-mx-4', '-mt-4', 'mb-3', 'px-4', 'pt-4', 'pb-3', 'border-b', 'border-border')
427
+ })
428
+
429
+ it('applies custom className', () => {
430
+ render(<PopoverHeader className="custom-header" data-testid="header">Header</PopoverHeader>)
431
+
432
+ const header = screen.getByTestId('header')
433
+ expect(header).toHaveClass('custom-header')
434
+ expect(header).toHaveClass('-mx-4', '-mt-4', 'mb-3')
435
+ })
436
+
437
+ it('maintains displayName', () => {
438
+ expect(PopoverHeader.displayName).toBe('PopoverHeader')
439
+ })
440
+
441
+ it('passes through HTML attributes', () => {
442
+ render(<PopoverHeader data-custom="test" data-testid="header">Header</PopoverHeader>)
443
+
444
+ const header = screen.getByTestId('header')
445
+ expect(header).toHaveAttribute('data-custom', 'test')
446
+ })
447
+ })
448
+
449
+ describe('PopoverFooter Component', () => {
450
+ it('renders correctly with default props', () => {
451
+ render(<PopoverFooter data-testid="popover-footer">Footer</PopoverFooter>)
452
+
453
+ const footer = screen.getByTestId('popover-footer')
454
+ expect(footer).toBeInTheDocument()
455
+ expect(footer).toHaveTextContent('Footer')
456
+ expect(footer).toHaveClass('-mx-4', '-mb-4', 'mt-3', 'px-4', 'pt-3', 'pb-4', 'border-t', 'border-border')
457
+ })
458
+
459
+ it('applies custom className', () => {
460
+ render(<PopoverFooter className="custom-footer" data-testid="footer">Footer</PopoverFooter>)
461
+
462
+ const footer = screen.getByTestId('footer')
463
+ expect(footer).toHaveClass('custom-footer')
464
+ expect(footer).toHaveClass('-mx-4', '-mb-4', 'mt-3')
465
+ })
466
+
467
+ it('maintains displayName', () => {
468
+ expect(PopoverFooter.displayName).toBe('PopoverFooter')
469
+ })
470
+
471
+ it('passes through HTML attributes', () => {
472
+ render(<PopoverFooter data-custom="test" data-testid="footer">Footer</PopoverFooter>)
473
+
474
+ const footer = screen.getByTestId('footer')
475
+ expect(footer).toHaveAttribute('data-custom', 'test')
476
+ })
477
+ })
478
+
479
+ describe('Variant Functions', () => {
480
+ it('popoverContentVariants function works correctly', () => {
481
+ const variants = popoverContentVariants({
482
+ variant: 'destructive',
483
+ size: 'lg',
484
+ radius: 'full',
485
+ shadow: 'xl'
486
+ })
487
+
488
+ expect(typeof variants).toBe('string')
489
+ expect(variants.length).toBeGreaterThan(0)
490
+ })
491
+ })
492
+
493
+ describe('Complex Combinations', () => {
494
+ it('renders complete popover with all components', () => {
495
+ render(
496
+ <Popover>
497
+ <PopoverTrigger>Open</PopoverTrigger>
498
+ <PopoverAnchor>Anchor</PopoverAnchor>
499
+ <PopoverContent>
500
+ <PopoverHeader>Header</PopoverHeader>
501
+ <div>Content</div>
502
+ <PopoverSeparator />
503
+ <PopoverFooter>
504
+ Footer
505
+ <PopoverClose>Close</PopoverClose>
506
+ </PopoverFooter>
507
+ </PopoverContent>
508
+ </Popover>
509
+ )
510
+
511
+ expect(screen.getByTestId('popover-root')).toBeInTheDocument()
512
+ expect(screen.getByTestId('popover-trigger')).toBeInTheDocument()
513
+ expect(screen.getByTestId('popover-anchor')).toBeInTheDocument()
514
+ expect(screen.getByTestId('popover-content')).toBeInTheDocument()
515
+ expect(screen.getByTestId('popover-close')).toBeInTheDocument()
516
+ expect(screen.getByText('Header')).toBeInTheDocument()
517
+ expect(screen.getByText('Content')).toBeInTheDocument()
518
+ expect(screen.getByText('Footer')).toBeInTheDocument()
519
+ })
520
+
521
+ it('handles all content variants and sizes together', () => {
522
+ render(
523
+ <div>
524
+ <Popover>
525
+ <PopoverContent variant="destructive" size="sm" radius="none" shadow="xl">
526
+ Destructive Small
527
+ </PopoverContent>
528
+ </Popover>
529
+ <Popover>
530
+ <PopoverContent variant="outline" size="lg" radius="full" shadow="none">
531
+ Outline Large
532
+ </PopoverContent>
533
+ </Popover>
534
+ </div>
535
+ )
536
+
537
+ expect(screen.getByText('Destructive Small')).toBeInTheDocument()
538
+ expect(screen.getByText('Outline Large')).toBeInTheDocument()
539
+ })
540
+
541
+ it('handles backdrop and overlay combinations', () => {
542
+ render(
543
+ <Popover>
544
+ <PopoverContent backdrop={true} overlayBackdrop={true} closeOnInteractOutside={false}>
545
+ Complex Content
546
+ </PopoverContent>
547
+ </Popover>
548
+ )
549
+
550
+ expect(screen.getByText('Complex Content')).toBeInTheDocument()
551
+ expect(document.querySelector('.fixed.inset-0')).toBeInTheDocument()
552
+ })
553
+ })
554
+
555
+ describe('Edge Cases', () => {
556
+ it('handles empty popover', () => {
557
+ render(<Popover />)
558
+
559
+ expect(screen.getByTestId('popover-root')).toBeInTheDocument()
560
+ })
561
+
562
+ it('handles popover without content', () => {
563
+ render(
564
+ <Popover>
565
+ <PopoverTrigger>Open</PopoverTrigger>
566
+ </Popover>
567
+ )
568
+
569
+ expect(screen.getByTestId('popover-trigger')).toBeInTheDocument()
570
+ })
571
+
572
+ it('handles null and undefined children', () => {
573
+ render(
574
+ <Popover>
575
+ <PopoverContent>
576
+ {null}
577
+ {undefined}
578
+ <div>Valid content</div>
579
+ </PopoverContent>
580
+ </Popover>
581
+ )
582
+
583
+ expect(screen.getByText('Valid content')).toBeInTheDocument()
584
+ })
585
+
586
+ it('handles complex nested content', () => {
587
+ render(
588
+ <Popover>
589
+ <PopoverContent>
590
+ <PopoverHeader>
591
+ <h3>Complex Header</h3>
592
+ <p>With multiple elements</p>
593
+ </PopoverHeader>
594
+ <div>
595
+ <ul>
596
+ <li>Item 1</li>
597
+ <li>Item 2</li>
598
+ </ul>
599
+ </div>
600
+ <PopoverSeparator />
601
+ <PopoverFooter>
602
+ <button>Action 1</button>
603
+ <PopoverClose>Cancel</PopoverClose>
604
+ </PopoverFooter>
605
+ </PopoverContent>
606
+ </Popover>
607
+ )
608
+
609
+ expect(screen.getByText('Complex Header')).toBeInTheDocument()
610
+ expect(screen.getByText('With multiple elements')).toBeInTheDocument()
611
+ expect(screen.getByText('Item 1')).toBeInTheDocument()
612
+ expect(screen.getByText('Item 2')).toBeInTheDocument()
613
+ expect(screen.getByText('Action 1')).toBeInTheDocument()
614
+ expect(screen.getByText('Cancel')).toBeInTheDocument()
615
+ })
616
+
617
+ it('handles multiple popovers on same page', () => {
618
+ render(
619
+ <div>
620
+ <Popover>
621
+ <PopoverTrigger>First Trigger</PopoverTrigger>
622
+ <PopoverContent>First Content</PopoverContent>
623
+ </Popover>
624
+ <Popover>
625
+ <PopoverTrigger>Second Trigger</PopoverTrigger>
626
+ <PopoverContent>Second Content</PopoverContent>
627
+ </Popover>
628
+ </div>
629
+ )
630
+
631
+ expect(screen.getByText('First Trigger')).toBeInTheDocument()
632
+ expect(screen.getByText('First Content')).toBeInTheDocument()
633
+ expect(screen.getByText('Second Trigger')).toBeInTheDocument()
634
+ expect(screen.getByText('Second Content')).toBeInTheDocument()
635
+ })
636
+ })
637
+ })