gongxiangp2/components/upload/TaskPageUploader.upload.test.tsx

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()
})
})