246 lines
7.1 KiB
TypeScript
246 lines
7.1 KiB
TypeScript
/**
|
|
* 文件上传组件测试
|
|
*/
|
|
|
|
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
|
import { mount } from '@vue/test-utils'
|
|
import { ElUpload, ElButton } from 'element-plus'
|
|
import FileUpload from '@/components/upload/FileUpload.vue'
|
|
|
|
// 模拟 Element Plus 组件
|
|
vi.mock('element-plus', () => ({
|
|
ElUpload: {
|
|
name: 'ElUpload',
|
|
template: '<div class="el-upload"><slot /></div>',
|
|
props: ['action', 'headers', 'data', 'multiple', 'accept', 'limit', 'fileList', 'beforeUpload', 'onProgress', 'onSuccess', 'onError', 'onRemove', 'onExceed', 'autoUpload', 'showFileList', 'drag', 'disabled']
|
|
},
|
|
ElButton: {
|
|
name: 'ElButton',
|
|
template: '<button class="el-button"><slot /></button>',
|
|
props: ['type', 'disabled']
|
|
},
|
|
ElIcon: {
|
|
name: 'ElIcon',
|
|
template: '<i class="el-icon"><slot /></i>'
|
|
},
|
|
ElProgress: {
|
|
name: 'ElProgress',
|
|
template: '<div class="el-progress"></div>',
|
|
props: ['percentage', 'status', 'strokeWidth']
|
|
}
|
|
}))
|
|
|
|
// 模拟图标组件
|
|
vi.mock('@element-plus/icons-vue', () => ({
|
|
UploadFilled: { name: 'UploadFilled' },
|
|
Upload: { name: 'Upload' },
|
|
Document: { name: 'Document' },
|
|
Picture: { name: 'Picture' }
|
|
}))
|
|
|
|
// 模拟认证状态
|
|
vi.mock('@/stores/auth', () => ({
|
|
useAuthStore: () => ({
|
|
token: 'mock-token'
|
|
})
|
|
}))
|
|
|
|
// 模拟配置
|
|
vi.mock('@/config/constants', () => ({
|
|
UPLOAD_CONFIG: {
|
|
DEFAULT_UPLOAD_URL: '/api/upload',
|
|
IMAGE_TYPES: ['image/jpeg', 'image/png', 'image/gif'],
|
|
DOCUMENT_TYPES: ['application/pdf', 'application/msword'],
|
|
VIDEO_TYPES: ['video/mp4', 'video/avi'],
|
|
AUDIO_TYPES: ['audio/mp3', 'audio/wav']
|
|
}
|
|
}))
|
|
|
|
// 模拟格式化工具
|
|
vi.mock('@/utils/format', () => ({
|
|
formatFileSize: (size: number) => `${size} B`
|
|
}))
|
|
|
|
describe('FileUpload', () => {
|
|
let wrapper: any
|
|
|
|
beforeEach(() => {
|
|
wrapper = mount(FileUpload, {
|
|
props: {
|
|
action: '/api/upload',
|
|
multiple: false,
|
|
accept: 'image/*',
|
|
limit: 5,
|
|
maxSize: 1024 * 1024, // 1MB
|
|
autoUpload: true
|
|
}
|
|
})
|
|
})
|
|
|
|
afterEach(() => {
|
|
wrapper?.unmount()
|
|
})
|
|
|
|
it('should render correctly', () => {
|
|
expect(wrapper.exists()).toBe(true)
|
|
expect(wrapper.find('.file-upload').exists()).toBe(true)
|
|
})
|
|
|
|
it('should render upload button when not drag mode', () => {
|
|
expect(wrapper.find('.el-button').exists()).toBe(true)
|
|
expect(wrapper.find('.upload-dragger').exists()).toBe(false)
|
|
})
|
|
|
|
it('should render drag area when drag mode is enabled', async () => {
|
|
await wrapper.setProps({ drag: true })
|
|
expect(wrapper.find('.upload-dragger').exists()).toBe(true)
|
|
})
|
|
|
|
it('should show upload hint', () => {
|
|
expect(wrapper.find('.upload-tip').exists()).toBe(true)
|
|
})
|
|
|
|
it('should emit events correctly', async () => {
|
|
const file = new File(['test'], 'test.txt', { type: 'text/plain' })
|
|
|
|
// 模拟文件上传成功
|
|
await wrapper.vm.handleSuccess({ url: 'http://example.com/file.txt' }, { uid: '1', name: 'test.txt' })
|
|
|
|
expect(wrapper.emitted('success')).toBeTruthy()
|
|
})
|
|
|
|
it('should validate file type', () => {
|
|
const validFile = new File(['test'], 'test.jpg', { type: 'image/jpeg' })
|
|
const invalidFile = new File(['test'], 'test.txt', { type: 'text/plain' })
|
|
|
|
// 设置接受的文件类型
|
|
wrapper.vm.acceptTypes = 'image/jpeg,image/png'
|
|
|
|
expect(wrapper.vm.isValidFileType(validFile)).toBe(true)
|
|
expect(wrapper.vm.isValidFileType(invalidFile)).toBe(false)
|
|
})
|
|
|
|
it('should validate file size', async () => {
|
|
const smallFile = new File(['small'], 'small.txt', { type: 'text/plain' })
|
|
Object.defineProperty(smallFile, 'size', { value: 500 })
|
|
|
|
const largeFile = new File(['large'], 'large.txt', { type: 'text/plain' })
|
|
Object.defineProperty(largeFile, 'size', { value: 2 * 1024 * 1024 }) // 2MB
|
|
|
|
// 测试文件大小验证
|
|
const result1 = await wrapper.vm.handleBeforeUpload(smallFile)
|
|
expect(result1).toBe(true)
|
|
|
|
const result2 = await wrapper.vm.handleBeforeUpload(largeFile)
|
|
expect(result2).toBe(false)
|
|
})
|
|
|
|
it('should handle upload progress', () => {
|
|
const progressEvent = { percent: 50 }
|
|
const file = { uid: '1', name: 'test.txt' }
|
|
|
|
wrapper.vm.handleProgress(progressEvent, file)
|
|
|
|
expect(wrapper.vm.uploadPercent).toBe(50)
|
|
expect(wrapper.emitted('progress')).toBeTruthy()
|
|
})
|
|
|
|
it('should handle upload error', () => {
|
|
const error = new Error('Upload failed')
|
|
const file = { uid: '1', name: 'test.txt' }
|
|
|
|
wrapper.vm.handleError(error, file)
|
|
|
|
expect(wrapper.vm.uploadStatus).toBe('exception')
|
|
expect(wrapper.emitted('error')).toBeTruthy()
|
|
})
|
|
|
|
it('should handle file removal', () => {
|
|
const file = { uid: '1', name: 'test.txt' }
|
|
|
|
wrapper.vm.handleRemove(file)
|
|
|
|
expect(wrapper.emitted('remove')).toBeTruthy()
|
|
})
|
|
|
|
it('should handle exceed limit', () => {
|
|
wrapper.vm.handleExceed()
|
|
|
|
// 应该显示警告消息(这里我们只能检查方法是否被调用)
|
|
expect(true).toBe(true) // 占位断言
|
|
})
|
|
|
|
it('should clear files', () => {
|
|
wrapper.vm.fileList = [
|
|
{ uid: '1', name: 'test1.txt' },
|
|
{ uid: '2', name: 'test2.txt' }
|
|
]
|
|
|
|
wrapper.vm.clearFiles()
|
|
|
|
expect(wrapper.vm.fileList).toEqual([])
|
|
})
|
|
|
|
it('should compute upload headers correctly', () => {
|
|
const headers = wrapper.vm.uploadHeaders
|
|
|
|
expect(headers).toHaveProperty('Authorization')
|
|
expect(headers.Authorization).toBe('Bearer mock-token')
|
|
expect(headers['X-Requested-With']).toBe('XMLHttpRequest')
|
|
})
|
|
|
|
it('should compute upload data correctly', async () => {
|
|
await wrapper.setProps({
|
|
fileType: 'image',
|
|
data: { category: 'avatar' }
|
|
})
|
|
|
|
const data = wrapper.vm.uploadData
|
|
|
|
expect(data.type).toBe('image')
|
|
expect(data.category).toBe('avatar')
|
|
})
|
|
|
|
it('should compute accept types correctly', async () => {
|
|
await wrapper.setProps({ fileType: 'image' })
|
|
expect(wrapper.vm.acceptTypes).toBe('image/jpeg,image/png,image/gif')
|
|
|
|
await wrapper.setProps({ fileType: 'document' })
|
|
expect(wrapper.vm.acceptTypes).toBe('application/pdf,application/msword')
|
|
|
|
await wrapper.setProps({ accept: 'custom/*' })
|
|
expect(wrapper.vm.acceptTypes).toBe('custom/*')
|
|
})
|
|
|
|
it('should compute upload hint correctly', async () => {
|
|
await wrapper.setProps({
|
|
fileType: 'image',
|
|
limit: 3,
|
|
maxSize: 1024 * 1024
|
|
})
|
|
|
|
const hint = wrapper.vm.uploadHint
|
|
|
|
expect(hint).toContain('最多3个文件')
|
|
expect(hint).toContain('JPG、PNG、GIF')
|
|
expect(hint).toContain('1024 B') // 模拟的格式化结果
|
|
})
|
|
|
|
it('should handle disabled state', async () => {
|
|
await wrapper.setProps({ disabled: true })
|
|
|
|
expect(wrapper.find('.el-button').attributes('disabled')).toBeDefined()
|
|
})
|
|
|
|
it('should handle custom button text and type', async () => {
|
|
await wrapper.setProps({
|
|
buttonText: 'Custom Upload',
|
|
buttonType: 'success'
|
|
})
|
|
|
|
const button = wrapper.find('.el-button')
|
|
expect(button.text()).toContain('Custom Upload')
|
|
expect(button.attributes('type')).toBe('success')
|
|
})
|
|
})
|