@datametria/vue-components
Version:
DATAMETRIA Vue.js 3 Component Library with Multi-Brand Theming - 51 components + 10 composables with theming support, WCAG 2.2 AA, dark mode, responsive system
291 lines (224 loc) • 9.01 kB
text/typescript
import { describe, it, expect, vi, beforeEach } from 'vitest'
import { mount } from '@vue/test-utils'
import DatametriaFileUpload from '../DatametriaFileUpload.vue'
import { datametriaTheme } from '../../theme/presets'
import { THEME_INJECTION_KEY } from '../../theme/constants'
const createWrapper = (props = {}, themeProps = {}) => {
return mount(DatametriaFileUpload, {
props,
global: {
plugins: [{
install(app) {
app.provide(THEME_INJECTION_KEY, datametriaTheme)
}
}]
}
})
}
// Mock File API
const createMockFile = (name: string, size: number, type: string) => {
const file = new File([''], name, { type })
Object.defineProperty(file, 'size', { value: size })
return file
}
describe('DatametriaFileUpload', () => {
beforeEach(() => {
vi.clearAllMocks()
})
it('renders correctly', () => {
const wrapper = createWrapper()
expect(wrapper.find('.dm-file-upload').exists()).toBe(true)
})
it('applies theme colors correctly', () => {
const wrapper = createWrapper()
expect(wrapper.find('.dm-file-upload').exists()).toBe(true)
})
it('displays upload area', () => {
const wrapper = createWrapper()
expect(wrapper.find('.dm-file-upload__area').exists()).toBe(true)
})
it('shows upload text and icon', () => {
const wrapper = createWrapper()
expect(wrapper.find('.dm-file-upload__icon').exists()).toBe(true)
expect(wrapper.find('.dm-file-upload__text').exists()).toBe(true)
})
it('handles file selection via input', async () => {
const wrapper = createWrapper()
const input = wrapper.find('.dm-file-upload__input')
const file = createMockFile('test.txt', 1024, 'text/plain')
Object.defineProperty(input.element, 'files', {
value: [file],
writable: false
})
await input.trigger('change')
const fileUpload = wrapper.findComponent(DatametriaFileUpload)
expect(fileUpload.emitted('update:modelValue')).toBeTruthy()
})
it('handles drag and drop', async () => {
const wrapper = createWrapper()
const dropArea = wrapper.find('.dm-file-upload__area')
const file = createMockFile('test.txt', 1024, 'text/plain')
const mockDataTransfer = {
files: [file]
}
await dropArea.trigger('drop', {
dataTransfer: mockDataTransfer
})
const fileUpload = wrapper.findComponent(DatametriaFileUpload)
expect(fileUpload.emitted('update:modelValue')).toBeTruthy()
})
it('shows drag over state', async () => {
const wrapper = createWrapper()
const dropArea = wrapper.find('.dm-file-upload__area')
await dropArea.trigger('dragenter')
await wrapper.vm.$nextTick()
expect(wrapper.find('.dm-file-upload__area--dragover').exists()).toBe(true)
await dropArea.trigger('dragleave', {
relatedTarget: document.body
})
await wrapper.vm.$nextTick()
expect(wrapper.find('.dm-file-upload__area--dragover').exists()).toBe(false)
})
it('supports multiple file selection', async () => {
const wrapper = createWrapper({ multiple: true })
const input = wrapper.find('.dm-file-upload__input')
expect(input.attributes('multiple')).toBeDefined()
const files = [
createMockFile('test1.txt', 1024, 'text/plain'),
createMockFile('test2.txt', 2048, 'text/plain')
]
Object.defineProperty(input.element, 'files', {
value: files,
writable: false
})
await input.trigger('change')
const fileUpload = wrapper.findComponent(DatametriaFileUpload)
expect(fileUpload.emitted('update:modelValue')).toBeTruthy()
})
it('validates file types', async () => {
const wrapper = createWrapper({ accept: '.txt,.pdf' })
const input = wrapper.find('.dm-file-upload__input')
expect(input.attributes('accept')).toBe('.txt,.pdf')
const invalidFile = createMockFile('test.jpg', 1024, 'image/jpeg')
Object.defineProperty(input.element, 'files', {
value: [invalidFile],
writable: false
})
await input.trigger('change')
await wrapper.vm.$nextTick()
expect(wrapper.text()).toContain('Invalid file type')
})
it('validates file size', async () => {
const wrapper = createWrapper({ maxSize: 1024 }) // 1KB
const input = wrapper.find('.dm-file-upload__input')
const largeFile = createMockFile('large.txt', 2048, 'text/plain') // 2KB
Object.defineProperty(input.element, 'files', {
value: [largeFile],
writable: false
})
await input.trigger('change')
await wrapper.vm.$nextTick()
expect(wrapper.text()).toContain('too large')
})
it('validates maximum number of files', async () => {
const wrapper = createWrapper({ multiple: true, maxFiles: 2 })
const input = wrapper.find('.dm-file-upload__input')
const files = [
createMockFile('test1.txt', 1024, 'text/plain'),
createMockFile('test2.txt', 1024, 'text/plain'),
createMockFile('test3.txt', 1024, 'text/plain')
]
Object.defineProperty(input.element, 'files', {
value: files,
writable: false
})
await input.trigger('change')
await wrapper.vm.$nextTick()
expect(wrapper.text()).toContain('Maximum 2 files')
})
it('shows file list when files are selected', async () => {
const wrapper = createWrapper({ multiple: true })
const input = wrapper.find('.dm-file-upload__input')
const files = [
createMockFile('test1.txt', 1024, 'text/plain'),
createMockFile('test2.txt', 2048, 'text/plain')
]
Object.defineProperty(input.element, 'files', {
value: files,
writable: false
})
await input.trigger('change')
expect(wrapper.find('.dm-file-upload__files').exists()).toBe(true)
expect(wrapper.findAll('.dm-file-upload__file')).toHaveLength(2)
})
it('allows file removal', async () => {
const wrapper = createWrapper({ multiple: true })
const input = wrapper.find('.dm-file-upload__input')
const files = [
createMockFile('test1.txt', 1024, 'text/plain'),
createMockFile('test2.txt', 2048, 'text/plain')
]
Object.defineProperty(input.element, 'files', {
value: files,
writable: false
})
await input.trigger('change')
const removeButton = wrapper.find('.dm-file-upload__remove')
await removeButton.trigger('click')
const fileUpload = wrapper.findComponent(DatametriaFileUpload)
expect(fileUpload.emitted('update:modelValue')).toBeTruthy()
})
it('supports disabled state', () => {
const wrapper = createWrapper({ disabled: true })
const input = wrapper.find('.dm-file-upload__input')
expect(input.attributes('disabled')).toBeDefined()
expect(wrapper.find('.dm-file-upload--disabled').exists()).toBe(true)
})
it('shows loading state during upload', () => {
const wrapper = createWrapper({ loading: true })
expect(wrapper.find('.dm-file-upload--loading').exists()).toBe(true)
expect(wrapper.find('.dm-file-upload__spinner').exists()).toBe(true)
})
it('shows upload progress', () => {
const wrapper = createWrapper({ progress: 50 })
const progressBar = wrapper.find('.dm-file-upload__progress-bar')
expect(progressBar.exists()).toBe(true)
expect(progressBar.attributes('style')).toContain('width: 50%')
})
it('supports custom upload text', () => {
const customText = 'Drop your files here'
const wrapper = createWrapper({ uploadText: customText })
expect(wrapper.find('.dm-file-upload__text').text()).toContain(customText)
})
it('supports custom error messages', () => {
const errorMessage = 'Upload failed'
const wrapper = createWrapper({ error: errorMessage })
expect(wrapper.find('.dm-file-upload__error').text()).toBe(errorMessage)
})
it('emits file-added event', async () => {
const wrapper = createWrapper()
const input = wrapper.find('.dm-file-upload__input')
const file = createMockFile('test.txt', 1024, 'text/plain')
Object.defineProperty(input.element, 'files', {
value: [file],
writable: false
})
await input.trigger('change')
const fileUpload = wrapper.findComponent(DatametriaFileUpload)
expect(fileUpload.emitted('file-added')).toBeTruthy()
})
it('emits file-removed event', async () => {
const wrapper = createWrapper({ multiple: true })
const input = wrapper.find('.dm-file-upload__input')
const files = [createMockFile('test.txt', 1024, 'text/plain')]
Object.defineProperty(input.element, 'files', {
value: files,
writable: false
})
await input.trigger('change')
const removeButton = wrapper.find('.dm-file-upload__remove')
await removeButton.trigger('click')
const fileUpload = wrapper.findComponent(DatametriaFileUpload)
expect(fileUpload.emitted('file-removed')).toBeTruthy()
})
})