Skip to content
This repository has been archived by the owner on Sep 18, 2023. It is now read-only.

Commit

Permalink
feat(components): add MultiDropzone component (#94)
Browse files Browse the repository at this point in the history
  • Loading branch information
sbolel authored Jul 17, 2023
1 parent 2ea7c82 commit 8229b31
Show file tree
Hide file tree
Showing 9 changed files with 1,208 additions and 0 deletions.
72 changes: 72 additions & 0 deletions src/components/MultiDropzone/MultiDropzone.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import type { StoryObj, Meta } from '@storybook/react'
import { useArgs } from '@storybook/client-api'
import MultiDropzone from '@/components/MultiDropzone/MultiDropzone'

type Story = StoryObj<typeof MultiDropzone>

export default {
title: 'Upload-UI/Components/MultiDropzone',
component: MultiDropzone,
argTypes: {
uploadedFiles: {
control: 'object',
},
onFileSelect: {
control: 'function',
},
uploading: {
control: 'boolean',
},
onRemoveFile: {
control: 'function',
},
},
args: {
uploadedFiles: [],
uploading: false,
onFileSelect: () => null,
onRemoveFile: () => null,
},
render: (args) => <MultiDropzone {...args} />,
} as Meta<typeof MultiDropzone>

export const Default: Story = {
args: {
uploadedFiles: [],
uploading: false,
},
}

export const Playground = ({ ...args }) => {
const [{ uploadedFiles }, updateArgs] = useArgs()

const onFileSelect = (files: File[]) => {
updateArgs({
uploadedFiles: files.map((file) => ({
id: file.name,
name: file.name,
progress: 0,
previewUrl: URL.createObjectURL(file),
})),
})
}

const onRemoveFile = (name: string) => {
updateArgs({
uploadedFiles: uploadedFiles.filter((file: File) => file.name !== name),
})
}

return (
<MultiDropzone
{...args}
uploading={false}
uploadedFiles={uploadedFiles}
onRemoveFile={onRemoveFile}
onFileSelect={onFileSelect}
accept={{
json: ['.json'],
}}
/>
)
}
125 changes: 125 additions & 0 deletions src/components/MultiDropzone/MultiDropzone.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import { render, fireEvent, screen, waitFor } from '@testing-library/react'
import { act } from 'react-dom/test-utils'
import MultiDropzone from '@/components/MultiDropzone/MultiDropzone'

describe('MultiDropzone', () => {
const onFileSelect = jest.fn()
const onRemoveFile = jest.fn()

it('renders without crashing', () => {
const { container } = render(
<MultiDropzone
onFileSelect={() => ({})}
onRemoveFile={() => ({})}
uploadedFiles={[]}
uploading={false}
/>
)
expect(container.firstChild).toBeInTheDocument()
})

it('calls onFileSelect when a file is dropped', () => {
const handleFileSelect = jest.fn()
render(
<MultiDropzone
onFileSelect={handleFileSelect}
onRemoveFile={() => ({})}
uploadedFiles={[]}
uploading={false}
/>
)
const file = new File(['hello'], 'hello.png', { type: 'image/png' })
const dataTransfer = {
files: [file],
items: [
{
kind: 'file',
type: file.type,
getAsFile: () => file,
},
],
types: ['Files'],
}
act(() => {
fireEvent.drop(
screen.getByLabelText('Drag and Drop File Selection'),
dataTransfer
)
waitFor(() => {
expect(handleFileSelect).toHaveBeenCalledWith([file])
})
})
})

it('calls onRemoveFile when a file is removed', () => {
const handleRemoveFile = jest.fn()
render(
<MultiDropzone
onFileSelect={() => ({})}
onRemoveFile={handleRemoveFile}
uploadedFiles={[{ id: '1', name: 'hello.png', progress: 0 }]}
uploading={false}
/>
)
fireEvent.click(screen.getByRole('button', { name: /file-action/i }))
expect(handleRemoveFile).toHaveBeenCalledWith('1')
})

it('displays uploaded files', () => {
render(
<MultiDropzone
onFileSelect={onFileSelect}
onRemoveFile={onRemoveFile}
uploadedFiles={[{ id: '1', name: 'hello.png', progress: 0 }]}
uploading={false}
/>
)
const uploadedFile = screen.getByText('hello.png')
expect(uploadedFile).toBeInTheDocument()
})

it('displays an error message when a file exceeds the maxSize', () => {
render(
<MultiDropzone
onFileSelect={() => ({})}
onRemoveFile={() => ({})}
uploadedFiles={[
{
id: '1',
name: 'hello.png',
progress: 0,
error: 'File is too large.',
},
]}
maxSize={10}
maxFiles={1}
uploading={false}
/>
)
// Create a mock file larger than maxSize
const file = new File([new Array(1024).join('a')], 'hello.png', {
type: 'image/png',
})
// Create a mock DataTransfer object with file larger than maxSize
const dataTransfer = {
files: [file],
items: [
{
kind: 'file',
type: file.type,
getAsFile: () => file,
},
],
types: ['json'],
}
act(() => {
fireEvent.drop(
screen.getByLabelText('Drag and Drop File Selection'),
dataTransfer
)
waitFor(() => {
expect(screen.getByText(/File is too large./i)).toBeInTheDocument()
})
})
})
})
Loading

0 comments on commit 8229b31

Please sign in to comment.