import { createRef } from 'react' import { fireEvent, render, screen } from '@testing-library/react' import MaterialCard, { type Material } from '@/components/home/MaterialCard' jest.mock('next/image', () => ({ __esModule: true, default: (props: any) => { const { priority, fill, unoptimized, sizes, ...rest } = props return }, })) jest.mock('@/components/AudioVisualizer', () => ({ __esModule: true, default: () =>
, })) describe('MaterialCard', () => { const baseMaterial: Material = { id: 'material-1', productModel: 'SPU-001', categoryName: '旗舰店', sceneName: '客厅', platformName: '天猫', productCategoryName: '沙发', materialType: '任务-AI原图', renderer: '', authorName: '张三', previewUrl: 'https://example.com/preview.jpg', zipFileName: 'sample.zip', zipFileSize: 1024, downloadCount: 0, likeCount: 0, isLiked: false, isFavorited: false, isAiGenerated: true, userId: 'user-1', createdAt: '2026-03-25T08:00:00.000Z', } const defaultProps = { material: baseMaterial, session: null, playingAudioId: null, audioElement: null, audioProgress: 0, audioCurrentTime: 0, audioDuration: 0, audioRef: createRef(), downloadingId: null, downloadProgress: 0, themeColor: '#111827', onAudioPlay: jest.fn(), onDownload: jest.fn(), onLike: jest.fn(), onFavorite: jest.fn(), onShare: jest.fn(), onEdit: jest.fn(), onDelete: jest.fn(), onClick: jest.fn(), onRetryTranscode: jest.fn(), showToast: jest.fn(), } beforeEach(() => { jest.clearAllMocks() }) test('AI 导入素材应显示 AI生成 标签', () => { render() expect(screen.getByText('AI生成')).toBeInTheDocument() }) test('非 AI 导入素材不显示 AI生成 标签', () => { render( , ) expect(screen.queryByText('AI生成')).not.toBeInTheDocument() }) test('任务-详情应优先显示出图方式标签', () => { render( , ) expect(screen.getByText('实拍')).toBeInTheDocument() expect(screen.queryByText('AI生成')).not.toBeInTheDocument() }) test('任务-详情未设置出图方式时应显示未设置', () => { render( , ) expect(screen.getByText('未设置')).toBeInTheDocument() }) test('15天策略隐藏源地址时仍显示视频转码进度,提示保留且没有整图蒙版', () => { const { container } = render( , ) expect(screen.getByRole('status')).toHaveTextContent('等待中') expect(screen.getByRole('progressbar')).toHaveAttribute('aria-valuenow', '5') const previewArea = container.querySelector('[data-material-link="true"]') const notice = screen.getByText('15天后可查看详情') expect(previewArea).not.toBeNull() expect(previewArea).toContainElement(notice) expect(notice).toHaveAttribute('data-video-preview-notice', 'true') expect(notice.parentElement).not.toHaveClass('bg-[#fafafa]/55') }) test('视频卡片初始只加载封面,悬停时才挂载视频预览', () => { const { container } = render( , ) const previewArea = container.querySelector('[data-material-link="true"]') expect(previewArea).not.toBeNull() expect(screen.getByAltText('SPU-001 视频封面')).toHaveAttribute( 'src', 'https://example.com/video-cover.jpg', ) expect(screen.queryByLabelText('SPU-001 视频预览')).not.toBeInTheDocument() fireEvent.mouseEnter(previewArea!) expect(screen.getByLabelText('SPU-001 视频预览')).toHaveAttribute( 'src', 'https://example.com/video-preview.mp4', ) fireEvent.mouseLeave(previewArea!) expect(screen.queryByLabelText('SPU-001 视频预览')).not.toBeInTheDocument() expect(screen.getByAltText('SPU-001 视频封面')).toBeInTheDocument() }) test('普通素材恢复 400px 高预览区并铺满容器', () => { const { container } = render() const previewArea = container.querySelector('[data-material-link="true"]') expect(previewArea).toHaveClass('h-[400px]') expect(previewArea).not.toHaveClass('aspect-[4/3]') expect(screen.getByAltText('客厅')).toHaveClass('object-cover') }) test('15天保护期内仍可复制分享链接', () => { render( , ) fireEvent.click(screen.getByRole('button', { name: '分享' })) expect(defaultProps.onShare).toHaveBeenCalledWith('material-1') expect(defaultProps.showToast).not.toHaveBeenCalled() }) test('接口未返回并发上限时按当前单任务策略展示', () => { render( , ) expect(screen.getByRole('status')).toHaveTextContent('1/1并发') }) test('15天遮罩下的转码失败仍可见且可以重试', () => { render( , ) expect(screen.getByRole('status')).toHaveTextContent('转码失败,请稍后重试') fireEvent.click(screen.getByRole('button', { name: '重试转码' })) expect(defaultProps.onRetryTranscode).toHaveBeenCalledWith('material-1') }) })