189 lines
6.4 KiB
TypeScript
189 lines
6.4 KiB
TypeScript
import { createEvent, fireEvent, render, screen } from '@testing-library/react'
|
||
import userEvent from '@testing-library/user-event'
|
||
|
||
import ProductPackageUploader from '@/components/upload/ProductPackageUploader'
|
||
|
||
jest.mock('@/components/upload/DetailImageSorter', () => ({
|
||
__esModule: true,
|
||
default: () => <div data-testid="detail-image-sorter" />,
|
||
}))
|
||
|
||
jest.mock('@/components/upload/UploadForm', () => ({
|
||
__esModule: true,
|
||
default: () => <div data-testid="upload-form" />,
|
||
}))
|
||
|
||
jest.mock('@/components/upload/category-handlers', () => ({
|
||
addCategory: jest.fn(),
|
||
addScene: jest.fn(),
|
||
}))
|
||
|
||
const defaultProps = {
|
||
onSuccess: jest.fn(),
|
||
onCancel: jest.fn(),
|
||
categories: [],
|
||
scenes: [],
|
||
platforms: [],
|
||
productCategories: [],
|
||
onRefreshCategories: jest.fn().mockResolvedValue(undefined),
|
||
onRefreshScenes: jest.fn().mockResolvedValue(undefined),
|
||
}
|
||
|
||
describe('ProductPackageUploader', () => {
|
||
const originalFetch = global.fetch
|
||
|
||
beforeEach(() => {
|
||
jest.clearAllMocks()
|
||
global.fetch = jest.fn().mockResolvedValue({
|
||
ok: true,
|
||
json: async () => [
|
||
{
|
||
id: 'requester-1',
|
||
username: 'operator-a',
|
||
displayName: '运营甲',
|
||
},
|
||
],
|
||
}) as jest.Mock
|
||
|
||
Object.defineProperty(URL, 'createObjectURL', {
|
||
configurable: true,
|
||
writable: true,
|
||
value: jest.fn(() => 'blob:mock'),
|
||
})
|
||
|
||
Object.defineProperty(URL, 'revokeObjectURL', {
|
||
configurable: true,
|
||
writable: true,
|
||
value: jest.fn(),
|
||
})
|
||
})
|
||
|
||
afterAll(() => {
|
||
global.fetch = originalFetch
|
||
})
|
||
|
||
test('任务-详情源文件选择框支持 psb/tif/tiff', async () => {
|
||
const user = userEvent.setup()
|
||
render(<ProductPackageUploader {...defaultProps} />)
|
||
await screen.findByPlaceholderText('搜索发起本次出图需求的运营人员')
|
||
|
||
const input = screen.getByLabelText(/PSD源文件/) as HTMLInputElement
|
||
expect(input.accept).toBe('.psd,.psb,.tif,.tiff,.zip,.rar,.7z')
|
||
|
||
const files = [
|
||
new File(['a'], 'sample.psb', { type: 'application/octet-stream' }),
|
||
new File(['b'], 'sample.tif', { type: 'image/tiff' }),
|
||
new File(['c'], 'sample.tiff', { type: 'image/tiff' }),
|
||
]
|
||
|
||
await user.upload(input, files)
|
||
|
||
expect(screen.getByText('sample.psb')).toBeInTheDocument()
|
||
expect(screen.getByText('sample.tif')).toBeInTheDocument()
|
||
expect(screen.getByText('sample.tiff')).toBeInTheDocument()
|
||
})
|
||
|
||
test('空的任务-详情源文件会被直接拦截并提示', async () => {
|
||
const user = userEvent.setup()
|
||
render(<ProductPackageUploader {...defaultProps} />)
|
||
await screen.findByPlaceholderText('搜索发起本次出图需求的运营人员')
|
||
|
||
const input = screen.getByLabelText(/PSD源文件/) as HTMLInputElement
|
||
const emptyFile = new File([], 'empty.psd', { type: 'application/octet-stream' })
|
||
|
||
await user.upload(input, emptyFile)
|
||
|
||
expect(screen.getByText('以下文件为空,无法上传:empty.psd')).toBeInTheDocument()
|
||
expect(screen.queryByText('empty.psd')).not.toBeInTheDocument()
|
||
})
|
||
|
||
test('应提供任务详情出图方式选择项,且默认未设置', async () => {
|
||
render(<ProductPackageUploader {...defaultProps} />)
|
||
await screen.findByPlaceholderText('搜索发起本次出图需求的运营人员')
|
||
|
||
const select = screen.getByLabelText(/出图方式/) as HTMLSelectElement
|
||
expect(select.value).toBe('')
|
||
expect(screen.getByRole('option', { name: '未设置' })).toBeInTheDocument()
|
||
expect(screen.getByRole('option', { name: '实拍' })).toBeInTheDocument()
|
||
expect(screen.getByRole('option', { name: '渲染' })).toBeInTheDocument()
|
||
expect(screen.getByRole('option', { name: 'AI' })).toBeInTheDocument()
|
||
})
|
||
|
||
test('应提供必填的需求运营搜索框并允许选择人员', async () => {
|
||
const user = userEvent.setup()
|
||
render(<ProductPackageUploader {...defaultProps} />)
|
||
|
||
const input = await screen.findByPlaceholderText('搜索发起本次出图需求的运营人员')
|
||
await user.click(input)
|
||
await user.type(input, '运营甲')
|
||
await user.click(screen.getByRole('button', { name: /运营甲/ }))
|
||
|
||
expect(input).toHaveValue('运营甲 (operator-a)')
|
||
expect(screen.getByText('记录发起本次出图需求的运营人员,与素材上传人可以不同。')).toBeInTheDocument()
|
||
})
|
||
|
||
test('未选择需求运营时提交应被前端拦截', async () => {
|
||
const user = userEvent.setup()
|
||
render(<ProductPackageUploader {...defaultProps} />)
|
||
|
||
await screen.findByPlaceholderText('搜索发起本次出图需求的运营人员')
|
||
await user.click(screen.getByRole('button', { name: '提交' }))
|
||
|
||
expect(screen.getByText('请选择需求运营人员')).toBeInTheDocument()
|
||
expect(global.fetch).toHaveBeenCalledTimes(1)
|
||
})
|
||
|
||
test('文件经过主图上传框内部按钮时应保持拖拽高亮', async () => {
|
||
render(<ProductPackageUploader {...defaultProps} />)
|
||
await screen.findByPlaceholderText('搜索发起本次出图需求的运营人员')
|
||
|
||
const input = screen.getByLabelText('主图') as HTMLInputElement
|
||
const dropZone = input.parentElement as HTMLDivElement
|
||
const addButton = dropZone.querySelector('button')
|
||
|
||
expect(addButton).not.toBeNull()
|
||
|
||
Object.defineProperty(dropZone, 'getBoundingClientRect', {
|
||
configurable: true,
|
||
value: () => ({
|
||
x: 0,
|
||
y: 0,
|
||
top: 0,
|
||
right: 100,
|
||
bottom: 100,
|
||
left: 0,
|
||
width: 100,
|
||
height: 100,
|
||
toJSON: () => ({}),
|
||
}),
|
||
})
|
||
|
||
fireEvent.dragEnter(dropZone, {
|
||
clientX: 20,
|
||
clientY: 20,
|
||
dataTransfer: { files: [], types: ['Files'] },
|
||
})
|
||
expect(dropZone).toHaveClass('border-blue-500')
|
||
|
||
const internalDragLeave = createEvent.dragLeave(dropZone)
|
||
Object.defineProperties(internalDragLeave, {
|
||
clientX: { value: 50 },
|
||
clientY: { value: 50 },
|
||
relatedTarget: { value: addButton },
|
||
dataTransfer: { value: { files: [], types: ['Files'] } },
|
||
})
|
||
fireEvent(dropZone, internalDragLeave)
|
||
expect(dropZone).toHaveClass('border-blue-500')
|
||
|
||
const outerDragLeave = createEvent.dragLeave(dropZone)
|
||
Object.defineProperties(outerDragLeave, {
|
||
clientX: { value: 120 },
|
||
clientY: { value: 50 },
|
||
relatedTarget: { value: document.body },
|
||
dataTransfer: { value: { files: [], types: ['Files'] } },
|
||
})
|
||
fireEvent(dropZone, outerDragLeave)
|
||
expect(dropZone).not.toHaveClass('border-blue-500')
|
||
})
|
||
})
|