117 lines
4.0 KiB
TypeScript
117 lines
4.0 KiB
TypeScript
import { changeField } from '@/test-utils/select'
|
|
import { fireEvent, render, screen, waitFor } from '@testing-library/react'
|
|
|
|
import TaskPageUploader from '@/components/upload/TaskPageUploader'
|
|
import { chunkUpload } from '@/lib/chunk-upload'
|
|
import { TASK_DETAIL_UPLOAD_LIMITS } from '@/lib/task-detail-upload-policy'
|
|
|
|
jest.mock('@/lib/chunk-upload', () => ({
|
|
chunkUpload: jest.fn(),
|
|
}))
|
|
|
|
const originalFetch = global.fetch
|
|
|
|
describe('TaskPageUploader upload contract', () => {
|
|
beforeEach(() => {
|
|
jest.clearAllMocks()
|
|
Object.defineProperty(URL, 'createObjectURL', {
|
|
configurable: true,
|
|
writable: true,
|
|
value: jest.fn(() => 'blob:task-page-preview'),
|
|
})
|
|
Object.defineProperty(URL, 'revokeObjectURL', {
|
|
configurable: true,
|
|
writable: true,
|
|
value: jest.fn(),
|
|
})
|
|
})
|
|
|
|
afterAll(() => {
|
|
global.fetch = originalFetch
|
|
})
|
|
|
|
test('应读取初始化接口顶层 materialId 并提交完成请求', async () => {
|
|
const fetchMock = jest
|
|
.fn()
|
|
.mockResolvedValueOnce({
|
|
ok: true,
|
|
json: async () => ({ success: true, materialId: 'material-task-page-1' }),
|
|
})
|
|
.mockResolvedValueOnce({
|
|
ok: true,
|
|
json: async () => ({ success: true, materialId: 'material-task-page-1' }),
|
|
})
|
|
global.fetch = fetchMock as unknown as typeof fetch
|
|
;(chunkUpload as jest.Mock).mockResolvedValue({ uploadId: 'upload-preview-1' })
|
|
|
|
const onSuccess = jest.fn()
|
|
const { container } = render(
|
|
<TaskPageUploader
|
|
onSuccess={onSuccess}
|
|
onCancel={jest.fn()}
|
|
categories={[{ id: 'category-1', name: '索菲亚' }]}
|
|
scenes={[{ id: 'scene-1', name: '书房' }]}
|
|
platforms={[]}
|
|
productCategories={[]}
|
|
onRefreshCategories={jest.fn()}
|
|
onRefreshScenes={jest.fn()}
|
|
/>,
|
|
)
|
|
|
|
changeField(screen.getByLabelText(/SPU型号/), { target: { value: 'SJ0371' } })
|
|
changeField(screen.getByLabelText(/使用店铺/), { target: { value: '索菲亚' } })
|
|
changeField(screen.getByLabelText(/场景类别/), { target: { value: '书房' } })
|
|
|
|
const imageInput = container.querySelector('input[type="file"][accept="image/*"]') as HTMLInputElement
|
|
const image = new File(['preview'], 'page-1.jpg', { type: 'image/jpeg' })
|
|
changeField(imageInput, { target: { files: [image] } })
|
|
fireEvent.click(screen.getByRole('button', { name: '提交' }))
|
|
|
|
await waitFor(() => expect(fetchMock).toHaveBeenCalledTimes(2))
|
|
|
|
expect(fetchMock.mock.calls[0][0]).toBe('/api/materials/upload/task-page/init')
|
|
expect(fetchMock.mock.calls[1][0]).toBe('/api/materials/upload/task-page/complete')
|
|
expect(JSON.parse(String(fetchMock.mock.calls[1][1]?.body))).toEqual(
|
|
expect.objectContaining({
|
|
materialId: 'material-task-page-1',
|
|
assets: {
|
|
main: [
|
|
expect.objectContaining({
|
|
uploadId: 'upload-preview-1',
|
|
fileName: 'page-1.jpg',
|
|
}),
|
|
],
|
|
},
|
|
}),
|
|
)
|
|
|
|
await waitFor(() => expect(onSuccess).toHaveBeenCalledTimes(1), { timeout: 2000 })
|
|
})
|
|
|
|
test('选择文件时应在上传前拒绝超过 100MB 的单张图片', () => {
|
|
const { container } = render(
|
|
<TaskPageUploader
|
|
onSuccess={jest.fn()}
|
|
onCancel={jest.fn()}
|
|
categories={[]}
|
|
scenes={[]}
|
|
platforms={[]}
|
|
productCategories={[]}
|
|
onRefreshCategories={jest.fn()}
|
|
onRefreshScenes={jest.fn()}
|
|
/>,
|
|
)
|
|
const imageInput = container.querySelector('input[type="file"][accept="image/*"]') as HTMLInputElement
|
|
const oversized = new File(['small fixture'], 'too-large.jpg', { type: 'image/jpeg' })
|
|
Object.defineProperty(oversized, 'size', {
|
|
configurable: true,
|
|
value: TASK_DETAIL_UPLOAD_LIMITS.maxSingleImageBytes + 1,
|
|
})
|
|
|
|
changeField(imageInput, { target: { files: [oversized] } })
|
|
|
|
expect(screen.getByText(/too-large\.jpg/)).toHaveTextContent('超过 100MB')
|
|
expect(screen.queryByAltText('预览图 1')).not.toBeInTheDocument()
|
|
})
|
|
})
|