mirror of
https://github.com/transloadit/uppy.git
synced 2026-07-21 01:15:35 +00:00
fixes #5946
Root Cause :
`createDropzone` used a single global `id` for the file input
(`'uppy-dropzone-file-input'`) Clicking any `<Dropzone />` did
`document.getElementById(<global-id>).click()`, which always targeted
the first input in the DOM, so files were added to the first Uppy
instance.
9bac4c8398/packages/%40uppy/components/src/hooks/dropzone.ts (L73-L77)
**Solutions :**
Simplest solution would have been to just make the input id unique per
Uppy instance using `ctx.uppy.getID()`, and click that specific input.
```typescript
const fileInputId = 'uppy-dropzone-file-input-' + ctx.uppy.getID()
```
**Caveats**:
If users don’t pass a custom id to `new Uppy()`, all instances default
to uppy, so ids still collide across instances.
Multiple Dropzones under one instance still share the same id.
Switched to a ref-based approach so clicks trigger the input directly,
without relying on `document.getElementById` lookups. It still falls
back to a DOM click for backward compatibility.
**StackBlitz Link :**
https://stackblitz.com/github/qxprakash/uppy/tree/debug_dropzone/examples/react?file=package.json&embed=1&view=editor&showSidebar=1&hideTerminal=1
**Update: Went for the ID based solution upon discussion with the team
as it's simpler.**
124 lines
4.1 KiB
TypeScript
124 lines
4.1 KiB
TypeScript
import { userEvent } from '@vitest/browser/context'
|
|
import { describe, expect, test } from 'vitest'
|
|
import { render } from 'vitest-browser-react'
|
|
import App from '../src/App'
|
|
|
|
const createMockFile = (name: string, type: string, size: number = 1024) => {
|
|
return new File(['test content'], name, { type })
|
|
}
|
|
|
|
describe('App', () => {
|
|
test('renders all main sections and upload button is initially disabled', async () => {
|
|
const screen = render(<App />)
|
|
|
|
await expect.element(screen.getByText('With list')).toBeInTheDocument()
|
|
await expect.element(screen.getByText('With grid')).toBeInTheDocument()
|
|
await expect
|
|
.element(screen.getByText('With custom dropzone'))
|
|
.toBeInTheDocument()
|
|
|
|
const uploadButton = screen.getByRole('button', { name: /upload/i })
|
|
await expect.element(uploadButton).toBeInTheDocument()
|
|
await expect.element(uploadButton).toBeDisabled()
|
|
})
|
|
|
|
test('can add and remove files and upload', async () => {
|
|
const screen = render(<App />)
|
|
|
|
const fileInput = document.getElementById(
|
|
'uppy-dropzone-file-input-uppy',
|
|
) as Element
|
|
await userEvent.upload(fileInput, createMockFile('test.txt', 'text/plain'))
|
|
|
|
// for list and grid
|
|
for (const element of screen.getByText('test.txt').elements()) {
|
|
await expect.element(element).toBeInTheDocument()
|
|
}
|
|
await screen.getByText('remove').first().click()
|
|
for (const element of screen.getByText('test.txt').elements()) {
|
|
await expect.element(element).not.toBeInTheDocument()
|
|
}
|
|
|
|
await userEvent.upload(fileInput, createMockFile('test.txt', 'text/plain'))
|
|
await screen.getByRole('button', { name: /upload/i }).click()
|
|
await expect
|
|
.element(screen.getByRole('button', { name: /complete/i }))
|
|
.toBeInTheDocument()
|
|
})
|
|
})
|
|
|
|
describe('ScreenCapture Component', () => {
|
|
test('renders with title, control buttons, and close functionality works', async () => {
|
|
const screen = render(<App />)
|
|
|
|
await screen.getByRole('button', { name: 'Screen Capture' }).click()
|
|
|
|
await expect
|
|
.element(screen.getByRole('heading', { name: 'Screen Capture' }))
|
|
.toBeInTheDocument()
|
|
|
|
await expect
|
|
.element(screen.getByRole('button', { name: 'Screenshot' }))
|
|
.toBeInTheDocument()
|
|
await expect
|
|
.element(screen.getByRole('button', { name: 'Record' }))
|
|
.toBeInTheDocument()
|
|
await expect
|
|
.element(screen.getByRole('button', { name: 'Stop' }))
|
|
.toBeInTheDocument()
|
|
await expect
|
|
.element(screen.getByRole('button', { name: 'Submit' }))
|
|
.toBeInTheDocument()
|
|
await expect
|
|
.element(screen.getByRole('button', { name: 'Discard' }))
|
|
.toBeInTheDocument()
|
|
|
|
const closeButton = screen.getByText('✕')
|
|
await closeButton.click()
|
|
})
|
|
})
|
|
|
|
describe('Webcam Component', () => {
|
|
test('renders with title, control buttons, and close functionality works', async () => {
|
|
const screen = render(<App />)
|
|
|
|
await screen.getByRole('button', { name: 'Webcam' }).click()
|
|
|
|
await expect
|
|
.element(screen.getByRole('heading', { name: 'Camera' }))
|
|
.toBeInTheDocument()
|
|
|
|
await expect
|
|
.element(screen.getByRole('button', { name: 'Snapshot' }))
|
|
.toBeInTheDocument()
|
|
await expect
|
|
.element(screen.getByRole('button', { name: 'Record' }))
|
|
.toBeInTheDocument()
|
|
await expect
|
|
.element(screen.getByRole('button', { name: 'Stop' }))
|
|
.toBeInTheDocument()
|
|
await expect
|
|
.element(screen.getByRole('button', { name: 'Submit' }))
|
|
.toBeInTheDocument()
|
|
await expect
|
|
.element(screen.getByRole('button', { name: 'Discard' }))
|
|
.toBeInTheDocument()
|
|
|
|
const closeButton = screen.getByText('✕')
|
|
await closeButton.click()
|
|
})
|
|
})
|
|
|
|
describe('RemoteSource Component', () => {
|
|
test('renders login button and login interaction works', async () => {
|
|
const screen = render(<App />)
|
|
|
|
await screen.getByRole('button', { name: 'Dropbox' }).click()
|
|
|
|
const loginButton = screen.getByRole('button', { name: 'Login' })
|
|
await expect.element(loginButton).toBeInTheDocument()
|
|
|
|
await loginButton.click()
|
|
await expect.element(loginButton).toBeInTheDocument()
|
|
})
|
|
})
|