gongxiangp2/components/upload/DedicatedImageUploaders.drag-drop.test.tsx
2026-07-24 18:15:27 +08:00

109 lines
3.7 KiB
TypeScript

import { createEvent, fireEvent, render, screen } from '@testing-library/react'
import AIOriginalUploader from '@/components/upload/AIOriginalUploader'
import RealPhotoUploader from '@/components/upload/RealPhotoUploader'
import TaskPageUploader from '@/components/upload/TaskPageUploader'
import ThreeDOriginalUploader from '@/components/upload/ThreeDOriginalUploader'
import VideoScreenshotUploader from '@/components/upload/VideoScreenshotUploader'
const defaultProps = {
onSuccess: jest.fn(),
onCancel: jest.fn(),
categories: [],
scenes: [],
platforms: [],
productCategories: [],
onRefreshCategories: jest.fn(),
onRefreshScenes: jest.fn(),
}
const uploaders = [
['AI 原图', AIOriginalUploader],
['实拍原图', RealPhotoUploader],
['3D 原图', ThreeDOriginalUploader],
['视频截图', VideoScreenshotUploader],
['任务页面', TaskPageUploader],
] as const
describe.each(uploaders)('%s拖拽上传', (_name, Uploader) => {
beforeEach(() => {
jest.clearAllMocks()
Object.defineProperty(URL, 'createObjectURL', {
configurable: true,
writable: true,
value: jest.fn(() => 'blob:preview'),
})
Object.defineProperty(URL, 'revokeObjectURL', {
configurable: true,
writable: true,
value: jest.fn(),
})
})
test('经过上传框内部按钮时应保持拖拽高亮', () => {
const { container } = render(<Uploader {...defaultProps} />)
const input = container.querySelector('input[type="file"][accept="image/*"][multiple]') as HTMLInputElement
const dropZone = input.parentElement as HTMLDivElement
const childButton = dropZone.querySelector('button') as HTMLButtonElement
Object.defineProperty(dropZone, 'getBoundingClientRect', {
configurable: true,
value: () => ({
x: 0,
y: 0,
top: 0,
right: 100,
bottom: 100,
left: 0,
width: 100,
height: 100,
toJSON: () => ({}),
}),
})
const dragData = {
clientX: 20,
clientY: 20,
dataTransfer: { files: [], types: ['Files'], dropEffect: 'none' },
}
fireEvent.dragEnter(dropZone, dragData)
fireEvent.dragOver(dropZone, dragData)
expect(dropZone).toHaveClass('border-blue-500')
const internalDragLeave = createEvent.dragLeave(dropZone)
Object.defineProperties(internalDragLeave, {
clientX: { value: 50 },
clientY: { value: 50 },
relatedTarget: { value: childButton },
dataTransfer: { value: { files: [], types: ['Files'], dropEffect: 'copy' } },
})
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'], dropEffect: 'copy' } },
})
fireEvent(dropZone, outerDragLeave)
expect(dropZone).not.toHaveClass('border-blue-500')
})
})
test('混合拖入有效图片和非法文件时应保留图片并显示错误', () => {
const { container } = render(<AIOriginalUploader {...defaultProps} />)
const input = container.querySelector('input[type="file"][accept="image/*"][multiple]') as HTMLInputElement
const dropZone = input.parentElement as HTMLDivElement
const image = new File(['image'], 'valid.png', { type: 'image/png' })
const invalid = new File(['text'], 'invalid.txt', { type: 'text/plain' })
fireEvent.drop(dropZone, {
dataTransfer: { files: [image, invalid], types: ['Files'], dropEffect: 'copy' },
})
expect(screen.getByAltText('原图 1')).toBeInTheDocument()
expect(screen.getByText(/invalid\.txt/)).toBeInTheDocument()
})