311 lines
10 KiB
TypeScript
311 lines
10 KiB
TypeScript
/* eslint-disable @next/next/no-img-element, jsx-a11y/alt-text */
|
||
import { fireEvent, render, screen, waitFor } from '@testing-library/react'
|
||
|
||
import BatchFileList from './BatchFileList'
|
||
import { BatchVideoList } from './SpecialBatchUploadUI'
|
||
|
||
function createPngFile(name: string, width = 1920, height = 1080) {
|
||
const bytes = new Uint8Array(24)
|
||
bytes.set([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a])
|
||
const view = new DataView(bytes.buffer)
|
||
view.setUint32(16, width)
|
||
view.setUint32(20, height)
|
||
return new File([bytes], name, { type: 'image/png' })
|
||
}
|
||
|
||
jest.mock('next/image', () => ({
|
||
__esModule: true,
|
||
default: (props: any) => {
|
||
const { fill, unoptimized, sizes, ...rest } = props
|
||
return <img {...rest} />
|
||
},
|
||
}))
|
||
|
||
test('无法从视频文件名确认 SPU 时直接显示可恢复的填写提示', () => {
|
||
render(
|
||
<BatchFileList
|
||
batchFiles={[{
|
||
id: 'video-missing-spu',
|
||
file: new File(['video'], '抖音素材-624-456.mp4', { type: 'video/mp4' }),
|
||
expanded: true,
|
||
productModel: '',
|
||
categoryName: '通用',
|
||
sceneName: '通用',
|
||
platformName: '',
|
||
productCategoryName: '',
|
||
}]}
|
||
materialType="抖音-千川素材"
|
||
categories={[]}
|
||
scenes={[]}
|
||
platforms={[]}
|
||
productCategories={[]}
|
||
renderer=""
|
||
batchPreviewDragging={{}}
|
||
onToggleExpand={jest.fn()}
|
||
onDelete={jest.fn()}
|
||
onUpdateProductModel={jest.fn()}
|
||
onUpdatePreviewImage={jest.fn()}
|
||
onRemovePreviewImage={jest.fn()}
|
||
onUpdateCategory={jest.fn()}
|
||
onUpdateScene={jest.fn()}
|
||
onUpdatePlatform={jest.fn()}
|
||
onUpdateProductCategory={jest.fn()}
|
||
onUpdateRenderer={jest.fn()}
|
||
onExitBatchMode={jest.fn()}
|
||
onPreviewDragEnter={jest.fn()}
|
||
onPreviewDragLeave={jest.fn()}
|
||
onValidationError={jest.fn()}
|
||
/>,
|
||
)
|
||
|
||
expect(screen.getByText(/未识别到 SPU,请填写/)).toBeInTheDocument()
|
||
const input = screen.getByRole('textbox', { name: 'SPU型号 *' })
|
||
expect(input).toHaveAttribute('aria-invalid', 'true')
|
||
expect(input).toHaveAccessibleDescription(/文件名不是完整、合规的 SPU/)
|
||
})
|
||
|
||
test('用户输入只自动转大写,非法字符保留并显示错误', () => {
|
||
const onUpdateProductModel = jest.fn()
|
||
render(
|
||
<BatchVideoList
|
||
files={[{
|
||
file: new File(['video'], 'video.mp4', { type: 'video/mp4' }),
|
||
productModel: 'DF-A3DZ0008 中文',
|
||
}]}
|
||
productCategories={[]}
|
||
onUpdateProductModel={onUpdateProductModel}
|
||
onUpdatePreviewImage={jest.fn()}
|
||
onRemovePreviewImage={jest.fn()}
|
||
onDelete={jest.fn()}
|
||
/>,
|
||
)
|
||
|
||
const input = screen.getByRole('textbox', { name: /SPU型号/ })
|
||
expect(input).toHaveValue('DF-A3DZ0008 中文')
|
||
expect(input).toHaveAttribute('aria-invalid', 'true')
|
||
expect(input).toHaveAccessibleDescription(/只能使用字母、数字/)
|
||
|
||
fireEvent.change(input, { target: { value: 'df-a3dz0008 中文' } })
|
||
expect(onUpdateProductModel).toHaveBeenCalledWith(0, 'df-a3dz0008 中文')
|
||
})
|
||
|
||
test('批量视频的每个文件都提供独立的选填预览图入口', async () => {
|
||
const onUpdatePreviewImage = jest.fn().mockResolvedValue(undefined)
|
||
render(
|
||
<BatchFileList
|
||
batchFiles={[{
|
||
id: 'video-1',
|
||
file: new File(['video'], 'SPU001.mp4', { type: 'video/mp4' }),
|
||
expanded: true,
|
||
productModel: 'SPU001',
|
||
categoryName: '通用',
|
||
sceneName: '通用',
|
||
platformName: '',
|
||
productCategoryName: '',
|
||
}]}
|
||
materialType="淘系-逛逛视频"
|
||
categories={[]}
|
||
scenes={[]}
|
||
platforms={[]}
|
||
productCategories={[]}
|
||
renderer=""
|
||
batchPreviewDragging={{}}
|
||
onToggleExpand={jest.fn()}
|
||
onDelete={jest.fn()}
|
||
onUpdateProductModel={jest.fn()}
|
||
onUpdatePreviewImage={onUpdatePreviewImage}
|
||
onRemovePreviewImage={jest.fn()}
|
||
onUpdateCategory={jest.fn()}
|
||
onUpdateScene={jest.fn()}
|
||
onUpdatePlatform={jest.fn()}
|
||
onUpdateProductCategory={jest.fn()}
|
||
onUpdateRenderer={jest.fn()}
|
||
onExitBatchMode={jest.fn()}
|
||
onPreviewDragEnter={jest.fn()}
|
||
onPreviewDragLeave={jest.fn()}
|
||
onValidationError={jest.fn()}
|
||
/>,
|
||
)
|
||
|
||
expect(screen.getByText('视频预览图')).toBeInTheDocument()
|
||
expect(screen.getByText('(选填)')).toBeInTheDocument()
|
||
expect(screen.queryByText('预览图片 *')).not.toBeInTheDocument()
|
||
|
||
const input = screen.getByLabelText(/视频预览图/) as HTMLInputElement
|
||
const cover = createPngFile('SPU001-cover.png')
|
||
fireEvent.change(input, { target: { files: [cover] } })
|
||
|
||
await waitFor(() => expect(onUpdatePreviewImage).toHaveBeenCalledWith(0, cover))
|
||
})
|
||
|
||
test('淘系-逛逛视频专用批量列表也提供独立的选填预览图入口', async () => {
|
||
const onUpdatePreviewImage = jest.fn().mockResolvedValue(undefined)
|
||
render(
|
||
<BatchVideoList
|
||
files={[{
|
||
file: new File(['video'], 'SPU002.mp4', { type: 'video/mp4' }),
|
||
productModel: 'SPU002',
|
||
}]}
|
||
productCategories={[]}
|
||
onUpdateProductModel={jest.fn()}
|
||
onUpdatePreviewImage={onUpdatePreviewImage}
|
||
onRemovePreviewImage={jest.fn()}
|
||
onValidationError={jest.fn()}
|
||
onDelete={jest.fn()}
|
||
/>,
|
||
)
|
||
|
||
expect(screen.getByText('视频预览图')).toBeInTheDocument()
|
||
expect(screen.getByText('(选填)')).toBeInTheDocument()
|
||
|
||
const input = screen.getByLabelText(/视频预览图/) as HTMLInputElement
|
||
const cover = createPngFile('SPU002-cover.png')
|
||
fireEvent.change(input, { target: { files: [cover] } })
|
||
|
||
await waitFor(() => expect(onUpdatePreviewImage).toHaveBeenCalledWith(0, cover))
|
||
})
|
||
|
||
test('通用和专用批量入口都在创建预览前拒绝超大像素图片', async () => {
|
||
const hugeCover = createPngFile('huge-cover.png', 10_000, 7_000)
|
||
const generalUpdate = jest.fn()
|
||
const generalError = jest.fn()
|
||
const generalView = render(
|
||
<BatchFileList
|
||
batchFiles={[{
|
||
id: 'video-huge-general',
|
||
file: new File(['video'], 'SPU-HUGE-1.mp4', { type: 'video/mp4' }),
|
||
expanded: true,
|
||
productModel: 'SPU-HUGE-1',
|
||
categoryName: '通用',
|
||
sceneName: '通用',
|
||
platformName: '',
|
||
productCategoryName: '',
|
||
}]}
|
||
materialType="淘系-逛逛视频"
|
||
categories={[]}
|
||
scenes={[]}
|
||
platforms={[]}
|
||
productCategories={[]}
|
||
renderer=""
|
||
batchPreviewDragging={{}}
|
||
onToggleExpand={jest.fn()}
|
||
onDelete={jest.fn()}
|
||
onUpdateProductModel={jest.fn()}
|
||
onUpdatePreviewImage={generalUpdate}
|
||
onRemovePreviewImage={jest.fn()}
|
||
onUpdateCategory={jest.fn()}
|
||
onUpdateScene={jest.fn()}
|
||
onUpdatePlatform={jest.fn()}
|
||
onUpdateProductCategory={jest.fn()}
|
||
onUpdateRenderer={jest.fn()}
|
||
onExitBatchMode={jest.fn()}
|
||
onPreviewDragEnter={jest.fn()}
|
||
onPreviewDragLeave={jest.fn()}
|
||
onValidationError={generalError}
|
||
/>,
|
||
)
|
||
|
||
fireEvent.change(screen.getByLabelText(/视频预览图/), {
|
||
target: { files: [hugeCover] },
|
||
})
|
||
await waitFor(() => expect(generalError).toHaveBeenLastCalledWith(
|
||
expect.stringContaining('像素总量超过 60,000,000'),
|
||
))
|
||
expect(generalUpdate).not.toHaveBeenCalled()
|
||
generalView.unmount()
|
||
|
||
const specialUpdate = jest.fn()
|
||
const specialError = jest.fn()
|
||
render(
|
||
<BatchVideoList
|
||
files={[{
|
||
file: new File(['video'], 'SPU-HUGE-2.mp4', { type: 'video/mp4' }),
|
||
productModel: 'SPU-HUGE-2',
|
||
}]}
|
||
productCategories={[]}
|
||
onUpdateProductModel={jest.fn()}
|
||
onUpdatePreviewImage={specialUpdate}
|
||
onRemovePreviewImage={jest.fn()}
|
||
onValidationError={specialError}
|
||
onDelete={jest.fn()}
|
||
/>,
|
||
)
|
||
|
||
fireEvent.change(screen.getByLabelText(/视频预览图/), {
|
||
target: { files: [hugeCover] },
|
||
})
|
||
await waitFor(() => expect(specialError).toHaveBeenLastCalledWith(
|
||
expect.stringContaining('像素总量超过 60,000,000'),
|
||
))
|
||
expect(specialUpdate).not.toHaveBeenCalled()
|
||
})
|
||
|
||
test('上传期间锁定通用批量视频的元数据和删除操作', () => {
|
||
render(
|
||
<BatchFileList
|
||
batchFiles={[{
|
||
id: 'video-disabled-1',
|
||
file: new File(['video'], 'SPU003.mp4', { type: 'video/mp4' }),
|
||
expanded: true,
|
||
productModel: 'SPU003',
|
||
categoryName: '通用',
|
||
sceneName: '通用',
|
||
platformName: '',
|
||
productCategoryName: '',
|
||
}]}
|
||
materialType="淘系-逛逛视频"
|
||
categories={[]}
|
||
scenes={[]}
|
||
platforms={[]}
|
||
productCategories={[]}
|
||
renderer=""
|
||
disabled
|
||
batchPreviewDragging={{}}
|
||
onToggleExpand={jest.fn()}
|
||
onDelete={jest.fn()}
|
||
onUpdateProductModel={jest.fn()}
|
||
onUpdatePreviewImage={jest.fn()}
|
||
onRemovePreviewImage={jest.fn()}
|
||
onUpdateCategory={jest.fn()}
|
||
onUpdateScene={jest.fn()}
|
||
onUpdatePlatform={jest.fn()}
|
||
onUpdateProductCategory={jest.fn()}
|
||
onUpdateRenderer={jest.fn()}
|
||
onExitBatchMode={jest.fn()}
|
||
onPreviewDragEnter={jest.fn()}
|
||
onPreviewDragLeave={jest.fn()}
|
||
onValidationError={jest.fn()}
|
||
/>,
|
||
)
|
||
|
||
expect(screen.getByRole('textbox', { name: 'SPU型号 *' })).toBeDisabled()
|
||
expect(screen.getByRole('button', { name: '删除' })).toBeDisabled()
|
||
expect(screen.getByRole('button', { name: '退出批量模式' })).toBeDisabled()
|
||
expect(screen.getByLabelText(/视频预览图/)).toBeDisabled()
|
||
})
|
||
|
||
test('上传期间锁定专用批量视频的 SPU、品类和删除操作', () => {
|
||
render(
|
||
<BatchVideoList
|
||
files={[{
|
||
file: new File(['video'], 'SPU004.mp4', { type: 'video/mp4' }),
|
||
productModel: 'SPU004',
|
||
productCategoryName: '沙发',
|
||
}]}
|
||
productCategories={[{ id: 'category-1', name: '沙发' }]}
|
||
disabled
|
||
onUpdateProductModel={jest.fn()}
|
||
onUpdateProductCategory={jest.fn()}
|
||
onUpdatePreviewImage={jest.fn()}
|
||
onRemovePreviewImage={jest.fn()}
|
||
onValidationError={jest.fn()}
|
||
onDelete={jest.fn()}
|
||
/>,
|
||
)
|
||
|
||
expect(screen.getByPlaceholderText('SPU型号')).toBeDisabled()
|
||
expect(screen.getByRole('combobox', { name: '品类(可选)' })).toBeDisabled()
|
||
expect(screen.getByRole('button', { name: '删除' })).toBeDisabled()
|
||
expect(screen.getByLabelText(/视频预览图/)).toBeDisabled()
|
||
})
|