|
|
@@ -0,0 +1,282 @@
|
|
|
+import { render, fireEvent } from '@testing-library/react'
|
|
|
+import {
|
|
|
+ Dialog,
|
|
|
+ DialogContent,
|
|
|
+ DialogHeader,
|
|
|
+ DialogTitle,
|
|
|
+ DialogDescription,
|
|
|
+ DialogFooter
|
|
|
+} from '@/components/ui/dialog'
|
|
|
+
|
|
|
+describe('Dialog 组件', () => {
|
|
|
+ const mockOnOpenChange = jest.fn()
|
|
|
+
|
|
|
+ beforeEach(() => {
|
|
|
+ jest.clearAllMocks()
|
|
|
+ })
|
|
|
+
|
|
|
+ describe('Dialog 主组件', () => {
|
|
|
+ it('应该渲染对话框当 open 为 true 时', () => {
|
|
|
+ const { getByText } = render(
|
|
|
+ <Dialog open={true} onOpenChange={mockOnOpenChange}>
|
|
|
+ <div>对话框内容</div>
|
|
|
+ </Dialog>
|
|
|
+ )
|
|
|
+
|
|
|
+ expect(getByText('对话框内容')).toBeTruthy()
|
|
|
+ })
|
|
|
+
|
|
|
+ it('不应该渲染对话框当 open 为 false 时', () => {
|
|
|
+ const { queryByText } = render(
|
|
|
+ <Dialog open={false} onOpenChange={mockOnOpenChange}>
|
|
|
+ <div>对话框内容</div>
|
|
|
+ </Dialog>
|
|
|
+ )
|
|
|
+
|
|
|
+ expect(queryByText('对话框内容')).toBeNull()
|
|
|
+ })
|
|
|
+
|
|
|
+ it('应该调用 onOpenChange(false) 当点击背景遮罩时', () => {
|
|
|
+ const { container } = render(
|
|
|
+ <Dialog open={true} onOpenChange={mockOnOpenChange}>
|
|
|
+ <div>对话框内容</div>
|
|
|
+ </Dialog>
|
|
|
+ )
|
|
|
+
|
|
|
+ // 找到背景遮罩元素
|
|
|
+ const backdrop = container.querySelector('.fixed')
|
|
|
+ expect(backdrop).toBeTruthy()
|
|
|
+
|
|
|
+ if (backdrop) {
|
|
|
+ fireEvent.click(backdrop)
|
|
|
+ expect(mockOnOpenChange).toHaveBeenCalledWith(false)
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ it('不应该调用 onOpenChange 当点击内容区域时', () => {
|
|
|
+ const { getByText } = render(
|
|
|
+ <Dialog open={true} onOpenChange={mockOnOpenChange}>
|
|
|
+ <div>对话框内容</div>
|
|
|
+ </Dialog>
|
|
|
+ )
|
|
|
+
|
|
|
+ const content = getByText('对话框内容')
|
|
|
+ fireEvent.click(content)
|
|
|
+
|
|
|
+ expect(mockOnOpenChange).not.toHaveBeenCalled()
|
|
|
+ })
|
|
|
+
|
|
|
+ it('应该应用正确的样式类名', () => {
|
|
|
+ const { container } = render(
|
|
|
+ <Dialog open={true} onOpenChange={mockOnOpenChange}>
|
|
|
+ <div>对话框内容</div>
|
|
|
+ </Dialog>
|
|
|
+ )
|
|
|
+
|
|
|
+ const backdrop = container.querySelector('.fixed')
|
|
|
+ const content = container.querySelector('.bg-white')
|
|
|
+
|
|
|
+ expect(backdrop).toBeTruthy()
|
|
|
+ expect(content).toBeTruthy()
|
|
|
+ expect(backdrop).toHaveClass('fixed', 'inset-0', 'z-50', 'flex', 'items-center', 'justify-center', 'bg-black/50')
|
|
|
+ expect(content).toHaveClass('bg-white', 'rounded-lg', 'shadow-lg', 'max-w-md', 'w-full', 'mx-4')
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ describe('DialogContent 组件', () => {
|
|
|
+ it('应该渲染内容并应用类名', () => {
|
|
|
+ const { getByText, container } = render(
|
|
|
+ <DialogContent className="custom-class">
|
|
|
+ 对话框内容
|
|
|
+ </DialogContent>
|
|
|
+ )
|
|
|
+
|
|
|
+ const content = getByText('对话框内容')
|
|
|
+ expect(content).toBeTruthy()
|
|
|
+
|
|
|
+ // 直接检查包含内容的div元素
|
|
|
+ const contentDiv = container.querySelector('div')
|
|
|
+ expect(contentDiv).toBeTruthy()
|
|
|
+ expect(contentDiv).toHaveClass('p-6', 'custom-class')
|
|
|
+ })
|
|
|
+
|
|
|
+ it('应该使用默认类名', () => {
|
|
|
+ const { getByText, container } = render(
|
|
|
+ <DialogContent>
|
|
|
+ 对话框内容
|
|
|
+ </DialogContent>
|
|
|
+ )
|
|
|
+
|
|
|
+ const content = getByText('对话框内容')
|
|
|
+ expect(content).toBeTruthy()
|
|
|
+
|
|
|
+ // 直接检查包含内容的div元素
|
|
|
+ const contentDiv = container.querySelector('div')
|
|
|
+ expect(contentDiv).toBeTruthy()
|
|
|
+ expect(contentDiv).toHaveClass('p-6')
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ describe('DialogHeader 组件', () => {
|
|
|
+ it('应该渲染头部并应用类名', () => {
|
|
|
+ const { getByText, container } = render(
|
|
|
+ <DialogHeader className="custom-header">
|
|
|
+ 对话框头部
|
|
|
+ </DialogHeader>
|
|
|
+ )
|
|
|
+
|
|
|
+ const header = getByText('对话框头部')
|
|
|
+ expect(header).toBeTruthy()
|
|
|
+
|
|
|
+ // 直接检查包含头部的div元素
|
|
|
+ const headerDiv = container.querySelector('div')
|
|
|
+ expect(headerDiv).toBeTruthy()
|
|
|
+ expect(headerDiv).toHaveClass('mb-4', 'custom-header')
|
|
|
+ })
|
|
|
+
|
|
|
+ it('应该使用默认类名', () => {
|
|
|
+ const { getByText, container } = render(
|
|
|
+ <DialogHeader>
|
|
|
+ 对话框头部
|
|
|
+ </DialogHeader>
|
|
|
+ )
|
|
|
+
|
|
|
+ const header = getByText('对话框头部')
|
|
|
+ expect(header).toBeTruthy()
|
|
|
+
|
|
|
+ // 直接检查包含头部的div元素
|
|
|
+ const headerDiv = container.querySelector('div')
|
|
|
+ expect(headerDiv).toBeTruthy()
|
|
|
+ expect(headerDiv).toHaveClass('mb-4')
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ describe('DialogTitle 组件', () => {
|
|
|
+ it('应该渲染标题并应用类名', () => {
|
|
|
+ const { getByText } = render(
|
|
|
+ <DialogTitle className="custom-title">
|
|
|
+ 对话框标题
|
|
|
+ </DialogTitle>
|
|
|
+ )
|
|
|
+
|
|
|
+ const title = getByText('对话框标题')
|
|
|
+ expect(title).toBeTruthy()
|
|
|
+ expect(title).toHaveClass('text-lg', 'font-semibold', 'text-gray-900', 'custom-title')
|
|
|
+ })
|
|
|
+
|
|
|
+ it('应该使用默认类名', () => {
|
|
|
+ const { getByText } = render(
|
|
|
+ <DialogTitle>
|
|
|
+ 对话框标题
|
|
|
+ </DialogTitle>
|
|
|
+ )
|
|
|
+
|
|
|
+ const title = getByText('对话框标题')
|
|
|
+ expect(title).toHaveClass('text-lg', 'font-semibold', 'text-gray-900')
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ describe('DialogDescription 组件', () => {
|
|
|
+ it('应该渲染描述并应用类名', () => {
|
|
|
+ const { getByText } = render(
|
|
|
+ <DialogDescription className="custom-desc">
|
|
|
+ 对话框描述
|
|
|
+ </DialogDescription>
|
|
|
+ )
|
|
|
+
|
|
|
+ const description = getByText('对话框描述')
|
|
|
+ expect(description).toBeTruthy()
|
|
|
+ expect(description).toHaveClass('text-sm', 'text-gray-600', 'custom-desc')
|
|
|
+ })
|
|
|
+
|
|
|
+ it('应该使用默认类名', () => {
|
|
|
+ const { getByText } = render(
|
|
|
+ <DialogDescription>
|
|
|
+ 对话框描述
|
|
|
+ </DialogDescription>
|
|
|
+ )
|
|
|
+
|
|
|
+ const description = getByText('对话框描述')
|
|
|
+ expect(description).toHaveClass('text-sm', 'text-gray-600')
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ describe('DialogFooter 组件', () => {
|
|
|
+ it('应该渲染底部并应用类名', () => {
|
|
|
+ const { getByText, container } = render(
|
|
|
+ <DialogFooter className="custom-footer">
|
|
|
+ 对话框底部
|
|
|
+ </DialogFooter>
|
|
|
+ )
|
|
|
+
|
|
|
+ const footer = getByText('对话框底部')
|
|
|
+ expect(footer).toBeTruthy()
|
|
|
+
|
|
|
+ // 直接检查包含底部的div元素
|
|
|
+ const footerDiv = container.querySelector('div')
|
|
|
+ expect(footerDiv).toBeTruthy()
|
|
|
+ expect(footerDiv).toHaveClass('flex', 'justify-end', 'space-x-2', 'custom-footer')
|
|
|
+ })
|
|
|
+
|
|
|
+ it('应该使用默认类名', () => {
|
|
|
+ const { getByText, container } = render(
|
|
|
+ <DialogFooter>
|
|
|
+ 对话框底部
|
|
|
+ </DialogFooter>
|
|
|
+ )
|
|
|
+
|
|
|
+ const footer = getByText('对话框底部')
|
|
|
+ expect(footer).toBeTruthy()
|
|
|
+
|
|
|
+ // 直接检查包含底部的div元素
|
|
|
+ const footerDiv = container.querySelector('div')
|
|
|
+ expect(footerDiv).toBeTruthy()
|
|
|
+ expect(footerDiv).toHaveClass('flex', 'justify-end', 'space-x-2')
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ describe('完整对话框示例', () => {
|
|
|
+ it('应该渲染完整的对话框结构', () => {
|
|
|
+ const { getByText } = render(
|
|
|
+ <Dialog open={true} onOpenChange={mockOnOpenChange}>
|
|
|
+ <DialogContent>
|
|
|
+ <DialogHeader>
|
|
|
+ <DialogTitle>确认操作</DialogTitle>
|
|
|
+ <DialogDescription>
|
|
|
+ 您确定要执行此操作吗?
|
|
|
+ </DialogDescription>
|
|
|
+ </DialogHeader>
|
|
|
+ <DialogFooter>
|
|
|
+ <button>取消</button>
|
|
|
+ <button>确认</button>
|
|
|
+ </DialogFooter>
|
|
|
+ </DialogContent>
|
|
|
+ </Dialog>
|
|
|
+ )
|
|
|
+
|
|
|
+ expect(getByText('确认操作')).toBeTruthy()
|
|
|
+ expect(getByText('您确定要执行此操作吗?')).toBeTruthy()
|
|
|
+ expect(getByText('取消')).toBeTruthy()
|
|
|
+ expect(getByText('确认')).toBeTruthy()
|
|
|
+ })
|
|
|
+
|
|
|
+ it('应该正确处理事件冒泡', () => {
|
|
|
+ const { getByText } = render(
|
|
|
+ <Dialog open={true} onOpenChange={mockOnOpenChange}>
|
|
|
+ <DialogContent>
|
|
|
+ <DialogHeader>
|
|
|
+ <DialogTitle>测试事件</DialogTitle>
|
|
|
+ </DialogHeader>
|
|
|
+ <button onClick={() => {}}>测试按钮</button>
|
|
|
+ </DialogContent>
|
|
|
+ </Dialog>
|
|
|
+ )
|
|
|
+
|
|
|
+ const button = getByText('测试按钮')
|
|
|
+ fireEvent.click(button)
|
|
|
+
|
|
|
+ // 点击按钮不应该触发对话框关闭
|
|
|
+ expect(mockOnOpenChange).not.toHaveBeenCalled()
|
|
|
+ })
|
|
|
+ })
|
|
|
+})
|