@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,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
|
+
})
|