245 lines
6.9 KiB
TypeScript
245 lines
6.9 KiB
TypeScript
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 <img {...rest} />
|
|
},
|
|
}))
|
|
|
|
jest.mock('@/components/AudioVisualizer', () => ({
|
|
__esModule: true,
|
|
default: () => <div data-testid="audio-visualizer" />,
|
|
}))
|
|
|
|
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<HTMLAudioElement>(),
|
|
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(<MaterialCard {...defaultProps} />)
|
|
|
|
expect(screen.getByText('AI生成')).toBeInTheDocument()
|
|
})
|
|
|
|
test('非 AI 导入素材不显示 AI生成 标签', () => {
|
|
render(
|
|
<MaterialCard
|
|
{...defaultProps}
|
|
material={{
|
|
...baseMaterial,
|
|
isAiGenerated: false,
|
|
}}
|
|
/>,
|
|
)
|
|
|
|
expect(screen.queryByText('AI生成')).not.toBeInTheDocument()
|
|
})
|
|
|
|
test('任务-详情应优先显示出图方式标签', () => {
|
|
render(
|
|
<MaterialCard
|
|
{...defaultProps}
|
|
material={{
|
|
...baseMaterial,
|
|
materialType: '任务-详情',
|
|
taskDetailSourceType: '实拍',
|
|
}}
|
|
/>,
|
|
)
|
|
|
|
expect(screen.getByText('实拍')).toBeInTheDocument()
|
|
expect(screen.queryByText('AI生成')).not.toBeInTheDocument()
|
|
})
|
|
|
|
test('任务-详情未设置出图方式时应显示未设置', () => {
|
|
render(
|
|
<MaterialCard
|
|
{...defaultProps}
|
|
material={{
|
|
...baseMaterial,
|
|
materialType: '任务-详情',
|
|
isAiGenerated: false,
|
|
taskDetailSourceType: null,
|
|
}}
|
|
/>,
|
|
)
|
|
|
|
expect(screen.getByText('未设置')).toBeInTheDocument()
|
|
})
|
|
|
|
test('15天策略隐藏源地址时仍显示视频转码进度', () => {
|
|
render(
|
|
<MaterialCard
|
|
{...defaultProps}
|
|
material={{
|
|
...baseMaterial,
|
|
materialType: '淘系-逛逛视频',
|
|
previewUrl: '',
|
|
videoSourceUrl: undefined,
|
|
videoProcessingStatus: 'pending',
|
|
videoPreviewBlocked: true,
|
|
videoPreviewRemainingDays: 15,
|
|
}}
|
|
/>,
|
|
)
|
|
|
|
expect(screen.getByRole('status')).toHaveTextContent('等待中')
|
|
expect(screen.getByRole('progressbar')).toHaveAttribute('aria-valuenow', '5')
|
|
expect(screen.getByText('15天后可查看详情')).toBeInTheDocument()
|
|
})
|
|
|
|
test('视频卡片初始只加载封面,悬停时才挂载视频预览', () => {
|
|
const { container } = render(
|
|
<MaterialCard
|
|
{...defaultProps}
|
|
material={{
|
|
...baseMaterial,
|
|
materialType: '淘系-逛逛视频',
|
|
videoCoverUrl: 'https://example.com/video-cover.jpg',
|
|
videoPreviewClipUrl: 'https://example.com/video-preview.mp4',
|
|
videoProcessingStatus: 'done',
|
|
}}
|
|
/>,
|
|
)
|
|
|
|
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(<MaterialCard {...defaultProps} />)
|
|
|
|
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(
|
|
<MaterialCard
|
|
{...defaultProps}
|
|
material={{
|
|
...baseMaterial,
|
|
materialType: '淘系-逛逛视频',
|
|
videoPreviewBlocked: true,
|
|
videoPreviewRemainingDays: 12,
|
|
}}
|
|
/>,
|
|
)
|
|
|
|
fireEvent.click(screen.getByRole('button', { name: '分享' }))
|
|
|
|
expect(defaultProps.onShare).toHaveBeenCalledWith('material-1')
|
|
expect(defaultProps.showToast).not.toHaveBeenCalled()
|
|
})
|
|
|
|
test('接口未返回并发上限时按当前单任务策略展示', () => {
|
|
render(
|
|
<MaterialCard
|
|
{...defaultProps}
|
|
material={{
|
|
...baseMaterial,
|
|
materialType: '淘系-逛逛视频',
|
|
previewUrl: '',
|
|
videoProcessingStatus: 'processing',
|
|
transcodeQueueProcessingIds: ['material-1'],
|
|
transcodeQueueWaitingTotal: 1,
|
|
}}
|
|
/>,
|
|
)
|
|
|
|
expect(screen.getByRole('status')).toHaveTextContent('1/1并发')
|
|
})
|
|
|
|
test('15天遮罩下的转码失败仍可见且可以重试', () => {
|
|
render(
|
|
<MaterialCard
|
|
{...defaultProps}
|
|
material={{
|
|
...baseMaterial,
|
|
materialType: '抖音-千川素材',
|
|
previewUrl: '',
|
|
videoSourceUrl: undefined,
|
|
videoProcessingStatus: 'failed',
|
|
transcodeLastError: '转码失败:源文件暂时不可读',
|
|
videoPreviewBlocked: true,
|
|
videoPreviewRemainingDays: 15,
|
|
}}
|
|
/>,
|
|
)
|
|
|
|
expect(screen.getByRole('status')).toHaveTextContent('转码失败,请稍后重试')
|
|
fireEvent.click(screen.getByRole('button', { name: '重试转码' }))
|
|
expect(defaultProps.onRetryTranscode).toHaveBeenCalledWith('material-1')
|
|
})
|
|
|
|
})
|