Skip to content

Commit

Permalink
@uppy/xhr-upload: allow custom error message in onAfterResponse (#5578)
Browse files Browse the repository at this point in the history
  • Loading branch information
Murderlon authored Jan 7, 2025
1 parent e567bb8 commit f3a750d
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 24 deletions.
31 changes: 20 additions & 11 deletions packages/@uppy/utils/src/fetcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,16 @@ export function fetcher(
// eslint-disable-next-line no-async-promise-executor
return new Promise(async (resolve, reject) => {
const xhr = new XMLHttpRequest()
const onError = (error: Error) => {
if (shouldRetry(xhr) && retryCount < retries) {
setTimeout(() => {
requestWithRetry(retryCount + 1).then(resolve, reject)
}, delay(retryCount))
} else {
timer.done()
reject(error)
}
}

xhr.open(method, url, true)
xhr.withCredentials = withCredentials
Expand All @@ -99,7 +109,15 @@ export function fetcher(
})

xhr.onload = async () => {
await onAfterResponse(xhr, retryCount)
try {
await onAfterResponse(xhr, retryCount)
} catch (err) {
// This is important as we need to emit the xhr
// over the upload-error event.
err.request = xhr
onError(err)
return
}

if (xhr.status >= 200 && xhr.status < 300) {
timer.done()
Expand All @@ -114,16 +132,7 @@ export function fetcher(
}
}

xhr.onerror = () => {
if (shouldRetry(xhr) && retryCount < retries) {
setTimeout(() => {
requestWithRetry(retryCount + 1).then(resolve, reject)
}, delay(retryCount))
} else {
timer.done()
reject(new NetworkError(xhr.statusText, xhr))
}
}
xhr.onerror = () => onError(new NetworkError(xhr.statusText, xhr))

xhr.upload.onprogress = (event: ProgressEvent) => {
timer.progress()
Expand Down
10 changes: 9 additions & 1 deletion packages/@uppy/xhr-upload/src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,14 @@ describe('XHRUpload', () => {
id: 'XHRUpload',
endpoint: 'https://fake-endpoint.uppy.io',
shouldRetry,
async onAfterResponse(xhr) {
if (xhr.status === 400) {
// We want to test that we can define our own error message
throw new Error(JSON.parse(xhr.responseText).message)
}
},
})

const id = core.addFile({
type: 'image/png',
source: 'test',
Expand All @@ -95,7 +102,7 @@ describe('XHRUpload', () => {

await Promise.all([
core.upload(),
event.then(([file, , response]) => {
event.then(([file, error, response]) => {
const newFile = core.getFile(id)
// error and response are set inside upload-error in core.
// When we subscribe to upload-error it is emitted before
Expand All @@ -107,6 +114,7 @@ describe('XHRUpload', () => {
// might have changed in the meantime
expect(file).toEqual(newFile)
expect(response).toBeInstanceOf(XMLHttpRequest)
expect(error.message).toEqual('Oh no')
}),
])

Expand Down
22 changes: 10 additions & 12 deletions packages/@uppy/xhr-upload/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ declare module '@uppy/core' {
}

function buildResponseError(
xhr: XMLHttpRequest,
xhr?: XMLHttpRequest,
err?: string | Error | NetworkError,
) {
let error = err
Expand Down Expand Up @@ -255,17 +255,15 @@ export default class XHRUpload<
if (error.name === 'AbortError') {
return undefined
}
if (error instanceof NetworkError) {
const request = error.request!

for (const file of files) {
this.uppy.emit(
'upload-error',
this.uppy.getFile(file.id),
buildResponseError(request, error),
request,
)
}
const request = error.request as XMLHttpRequest | undefined

for (const file of files) {
this.uppy.emit(
'upload-error',
this.uppy.getFile(file.id),
buildResponseError(request, error),
request,
)
}

throw error
Expand Down

0 comments on commit f3a750d

Please sign in to comment.