mirror of
https://github.com/transloadit/uppy.git
synced 2026-07-17 16:50:22 +00:00
@uppy/xhr-upload: add browser tests (#6169)
Good to have actual browser tests for this uploader.
This commit is contained in:
parent
53f5b44f4b
commit
23cbd4a05a
6 changed files with 206 additions and 1 deletions
|
|
@ -8,7 +8,8 @@
|
|||
"scripts": {
|
||||
"build": "tsc --build tsconfig.build.json",
|
||||
"typecheck": "tsc --build",
|
||||
"test": "vitest run --environment=jsdom --silent='passed-only'"
|
||||
"test": "vitest run --silent='passed-only'",
|
||||
"test:e2e": "vitest run --project browser"
|
||||
},
|
||||
"keywords": [
|
||||
"file uploader",
|
||||
|
|
@ -44,8 +45,12 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@uppy/core": "workspace:^",
|
||||
"@uppy/dashboard": "workspace:^",
|
||||
"@vitest/browser": "^3.2.4",
|
||||
"jsdom": "^26.1.0",
|
||||
"msw": "^2.10.4",
|
||||
"nock": "^13.1.0",
|
||||
"playwright": "1.57.0",
|
||||
"typescript": "^5.8.3",
|
||||
"vitest": "^3.2.4"
|
||||
},
|
||||
|
|
|
|||
3
packages/@uppy/xhr-upload/src/mocks/browser.ts
Normal file
3
packages/@uppy/xhr-upload/src/mocks/browser.ts
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
import { setupWorker } from 'msw/browser'
|
||||
|
||||
export const worker = setupWorker()
|
||||
22
packages/@uppy/xhr-upload/src/test-extend.ts
Normal file
22
packages/@uppy/xhr-upload/src/test-extend.ts
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
import { test as testBase } from 'vitest'
|
||||
import { worker } from './mocks/browser.js'
|
||||
|
||||
export const test = testBase.extend<{ worker: typeof worker }>({
|
||||
worker: [
|
||||
// biome-ignore lint/correctness/noEmptyPattern: dunno
|
||||
async ({}, use) => {
|
||||
// Start the worker before the test.
|
||||
await worker.start()
|
||||
|
||||
// Expose the worker object on the test's context.
|
||||
await use(worker)
|
||||
|
||||
// Remove any request handlers added in individual test cases.
|
||||
// This prevents them from affecting unrelated tests.
|
||||
worker.resetHandlers()
|
||||
},
|
||||
{
|
||||
auto: true,
|
||||
},
|
||||
],
|
||||
})
|
||||
142
packages/@uppy/xhr-upload/src/xhrUpload.browser.test.ts
Normal file
142
packages/@uppy/xhr-upload/src/xhrUpload.browser.test.ts
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
import Uppy, { type UppyEventMap } from '@uppy/core'
|
||||
import Dashboard from '@uppy/dashboard'
|
||||
import { page, userEvent } from '@vitest/browser/context'
|
||||
import { HttpResponse, http } from 'msw'
|
||||
import { afterEach, beforeEach, describe, expect } from 'vitest'
|
||||
import '@uppy/core/css/style.css'
|
||||
import '@uppy/dashboard/css/style.css'
|
||||
import XHRUpload from './index.js'
|
||||
import { test } from './test-extend.js'
|
||||
|
||||
type UploadCompleteResult = Parameters<UppyEventMap<any, any>['complete']>[0]
|
||||
|
||||
type MockUploadRequest = {
|
||||
fieldNames: string[]
|
||||
fileNames: string[]
|
||||
}
|
||||
|
||||
let uppy: Uppy | undefined
|
||||
|
||||
function createUppy({ bundle = false }: { bundle?: boolean } = {}) {
|
||||
const target = document.createElement('div')
|
||||
document.body.appendChild(target)
|
||||
|
||||
uppy = new Uppy({ debug: true })
|
||||
.use(Dashboard, {
|
||||
target,
|
||||
inline: true,
|
||||
})
|
||||
.use(XHRUpload, {
|
||||
endpoint: 'http://localhost/upload',
|
||||
bundle,
|
||||
})
|
||||
|
||||
return uppy
|
||||
}
|
||||
|
||||
function createMockFile(name: string, size: number = 16) {
|
||||
return new File(['a'.repeat(size)], name, { type: 'text/plain' })
|
||||
}
|
||||
|
||||
function waitForUploadComplete(uppy: Uppy<any, any>) {
|
||||
return new Promise<UploadCompleteResult>((resolve) =>
|
||||
uppy.once('complete', resolve),
|
||||
)
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
document.body.innerHTML = ''
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
uppy?.destroy()
|
||||
uppy = undefined
|
||||
})
|
||||
|
||||
describe('XHRUpload browser mode', () => {
|
||||
test('uploads a file in non-bundle mode', async ({ worker }) => {
|
||||
const requests: MockUploadRequest[] = []
|
||||
worker.use(
|
||||
http.post('http://localhost/upload', async ({ request }) => {
|
||||
const formData = await request.formData()
|
||||
const uploadedFiles = Array.from(formData.entries()).filter(
|
||||
(entry): entry is [string, File] => entry[1] instanceof File,
|
||||
)
|
||||
|
||||
requests.push({
|
||||
fieldNames: uploadedFiles.map(([fieldName]) => fieldName),
|
||||
fileNames: uploadedFiles.map(([, file]) => file.name),
|
||||
})
|
||||
|
||||
return HttpResponse.json({ url: 'http://localhost/uploads/regular' })
|
||||
}),
|
||||
)
|
||||
|
||||
const uppy = createUppy()
|
||||
const completePromise = waitForUploadComplete(uppy)
|
||||
const fileInput = document.querySelector('.uppy-Dashboard-input')!
|
||||
|
||||
await userEvent.upload(fileInput, createMockFile('regular.txt'))
|
||||
await page.getByRole('button', { name: 'Upload 1 file' }).click()
|
||||
|
||||
const result = await completePromise
|
||||
|
||||
expect(result.failed).toHaveLength(0)
|
||||
expect(result.successful).toHaveLength(1)
|
||||
expect(requests).toHaveLength(1)
|
||||
expect(requests[0]).toEqual({
|
||||
fieldNames: ['file'],
|
||||
fileNames: ['regular.txt'],
|
||||
})
|
||||
expect(uppy.getFiles()[0].response?.uploadURL).toBe(
|
||||
'http://localhost/uploads/regular',
|
||||
)
|
||||
await expect
|
||||
.element(page.getByText('Complete', { exact: true }))
|
||||
.toBeVisible()
|
||||
})
|
||||
|
||||
test('uploads files in a single request with bundle: true', async ({
|
||||
worker,
|
||||
}) => {
|
||||
const requests: MockUploadRequest[] = []
|
||||
worker.use(
|
||||
http.post('http://localhost/upload', async ({ request }) => {
|
||||
const formData = await request.formData()
|
||||
const uploadedFiles = Array.from(formData.entries()).filter(
|
||||
(entry): entry is [string, File] => entry[1] instanceof File,
|
||||
)
|
||||
|
||||
requests.push({
|
||||
fieldNames: uploadedFiles.map(([fieldName]) => fieldName),
|
||||
fileNames: uploadedFiles.map(([, file]) => file.name),
|
||||
})
|
||||
|
||||
return HttpResponse.json({ url: 'http://localhost/uploads/bundled' })
|
||||
}),
|
||||
)
|
||||
|
||||
const uppy = createUppy({ bundle: true })
|
||||
const completePromise = waitForUploadComplete(uppy)
|
||||
const fileInput = document.querySelector('.uppy-Dashboard-input')!
|
||||
|
||||
await userEvent.upload(fileInput, [
|
||||
createMockFile('bundle-a.txt'),
|
||||
createMockFile('bundle-b.txt'),
|
||||
])
|
||||
await page.getByRole('button', { name: 'Upload 2 files' }).click()
|
||||
|
||||
const result = await completePromise
|
||||
|
||||
expect(result.failed).toHaveLength(0)
|
||||
expect(result.successful).toHaveLength(2)
|
||||
expect(requests).toHaveLength(1)
|
||||
const sortedFileNames = [...requests[0].fileNames].sort()
|
||||
expect(requests[0].fieldNames).toEqual(['files[]', 'files[]'])
|
||||
expect(sortedFileNames).toEqual(['bundle-a.txt', 'bundle-b.txt'])
|
||||
expect(uppy.getFiles().every((file) => file.response?.uploadURL)).toBe(true)
|
||||
await expect
|
||||
.element(page.getByText('Complete', { exact: true }))
|
||||
.toBeVisible()
|
||||
})
|
||||
})
|
||||
29
packages/@uppy/xhr-upload/vitest.config.ts
Normal file
29
packages/@uppy/xhr-upload/vitest.config.ts
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
import { defineConfig } from 'vitest/config'
|
||||
|
||||
export default defineConfig({
|
||||
test: {
|
||||
projects: [
|
||||
{
|
||||
test: {
|
||||
name: 'unit',
|
||||
include: [
|
||||
'src/**/*.test.{ts,tsx}',
|
||||
'!src/**/*.browser.test.{ts,tsx}',
|
||||
],
|
||||
environment: 'jsdom',
|
||||
},
|
||||
},
|
||||
{
|
||||
test: {
|
||||
name: 'browser',
|
||||
include: ['src/**/*.browser.test.{ts,tsx}'],
|
||||
browser: {
|
||||
enabled: true,
|
||||
provider: 'playwright',
|
||||
instances: [{ browser: 'chromium' }],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
|
|
@ -10480,9 +10480,13 @@ __metadata:
|
|||
dependencies:
|
||||
"@uppy/companion-client": "workspace:^"
|
||||
"@uppy/core": "workspace:^"
|
||||
"@uppy/dashboard": "workspace:^"
|
||||
"@uppy/utils": "workspace:^"
|
||||
"@vitest/browser": "npm:^3.2.4"
|
||||
jsdom: "npm:^26.1.0"
|
||||
msw: "npm:^2.10.4"
|
||||
nock: "npm:^13.1.0"
|
||||
playwright: "npm:1.57.0"
|
||||
typescript: "npm:^5.8.3"
|
||||
vitest: "npm:^3.2.4"
|
||||
peerDependencies:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue