diff --git a/runner/src/server/plugins/engine/pageControllers/PageControllerBase.ts b/runner/src/server/plugins/engine/pageControllers/PageControllerBase.ts index 6885745b51..94cce40229 100644 --- a/runner/src/server/plugins/engine/pageControllers/PageControllerBase.ts +++ b/runner/src/server/plugins/engine/pageControllers/PageControllerBase.ts @@ -606,7 +606,7 @@ export class PageControllerBase { path: field.name, href: `#${field.name}`, name: field.name, - text: `The selected file must be smaller than ${config.maxFileSizeStringInMb}MB`, + text: `The selected files must be smaller than ${config.maxFileSizeStringInMb}MB`, }; }); diff --git a/runner/src/server/plugins/engine/pluginHandlers/files/prehandlers/handleUpload.ts b/runner/src/server/plugins/engine/pluginHandlers/files/prehandlers/handleUpload.ts index a775ff098c..af902d50a2 100644 --- a/runner/src/server/plugins/engine/pluginHandlers/files/prehandlers/handleUpload.ts +++ b/runner/src/server/plugins/engine/pluginHandlers/files/prehandlers/handleUpload.ts @@ -44,16 +44,13 @@ export async function handleUpload( } let response; - + const errors = new Set(); try { response = await uploadService.uploadDocuments(streams); } catch (err) { if (err.data?.res) { - const { error } = uploadService.parsedDocumentUploadResponse(err.data); - request.pre.errors = [ - ...request.pre.errors, - parsedError(fieldName, error), - ]; + response = uploadService.parsedDocumentUploadResponse(err.data); + errors.add(response.error); } else if (err.code === "EPIPE") { // ignore this error, it happens when the request is responded to by the doc upload service before the // body has finished being sent. A valid response is still received. @@ -63,10 +60,7 @@ export async function handleUpload( { ...loggerIdentifier, err }, `Error uploading document: ${err.message}` ); - request.pre.errors = [ - ...(h.request.pre.errors || []), - parsedError(fieldName, err), - ]; + errors.add(err); } } @@ -108,9 +102,13 @@ export async function handleUpload( loggerIdentifier, `Document upload API responded with an error ${error}` ); + errors.add(error); + } + + if(errors){ request.pre.errors = [ ...(request.pre.errors || []), - parsedError(fieldName, error), + ...Array.from(errors).map(e => parsedError(fieldName, String(e))) ]; } } diff --git a/runner/src/server/services/upload/uploadService.ts b/runner/src/server/services/upload/uploadService.ts index a1e3122f56..9cddda3232 100644 --- a/runner/src/server/services/upload/uploadService.ts +++ b/runner/src/server/services/upload/uploadService.ts @@ -26,10 +26,11 @@ const parsedError = (key: string, error?: string) => { }; const ERRORS = { - fileSizeError: 'The selected file for "%s" is too large', + fileSizeError: 'The selected files are too large', fileTypeError: "Invalid file type. Upload a PNG, JPG or PDF", - virusError: 'The selected file for "%s" contained a virus', - default: "There was an error uploading your file", + fileCountError: 'You have selected too many files', + virusError: 'The selected files contained a virus', + default: "There was an error uploading your files", }; export class UploadService { @@ -60,7 +61,7 @@ export class UploadService { .join(", "); const lastAcceptedTypeName = acceptedTypeNames.slice(-1); - return `The selected file for "%s" must be a ${acceptedTypesNameWithoutLast} or ${lastAcceptedTypeName}`; + return `The selected files must be a ${acceptedTypesNameWithoutLast} or ${lastAcceptedTypeName}`; } get fileSizeLimit() { @@ -127,7 +128,18 @@ export class UploadService { } parsedDocumentUploadResponse({ res, payload }) { - const warning = payload?.toString?.(); + const payloadString = payload?.toString?.(); + let payloadJson: any; + let warning: string | undefined; + let errorCode: string | undefined; + + try { + payloadJson = payloadString ? JSON.parse(payloadString) : undefined; + errorCode = payloadJson?.errorCode; + warning = payloadJson?.warning; + } catch (e) { + warning = payloadString; + } let error: string | undefined; let location: string | undefined; switch (res.statusCode) { @@ -138,7 +150,15 @@ export class UploadService { error = ERRORS.fileTypeError; break; case 413: - error = ERRORS.fileSizeError; + if(errorCode === "TOO_MANY_FILES") { + if (payloadJson?.maxFilesPerUpload) { + error = `You can only select up to ${payloadJson?.maxFilesPerUpload} files at the same time`; + } else { + error = ERRORS.fileCountError; + } + } else { + error = ERRORS.fileSizeError; + } break; case 422: error = ERRORS.virusError; diff --git a/runner/test/cases/server/upload.test.js b/runner/test/cases/server/upload.test.js index 981a16b305..f669eeed9c 100644 --- a/runner/test/cases/server/upload.test.js +++ b/runner/test/cases/server/upload.test.js @@ -70,7 +70,7 @@ suite("uploads", () => { stub(UploadService.prototype, "uploadDocuments").callsFake(async () => { return { - error: 'The selected file for "%s" contained a virus', + error: 'The selected files contained a virus', }; }); @@ -87,7 +87,7 @@ suite("uploads", () => { const $ = cheerio.load(response.payload); expect($("[href='#file1']").text().trim()).to.equal( - 'The selected file for "Passport photo" contained a virus' + 'The selected files contained a virus' ); }); @@ -112,7 +112,7 @@ suite("uploads", () => { const $ = cheerio.load(response.payload); expect($("[href='#file1']").text().trim()).to.contain( - "The selected file must be smaller than" + "The selected files must be smaller than" ); }); @@ -150,7 +150,7 @@ suite("uploads", () => { const $ = cheerio.load(response.payload); expect($("[href='#file1']").text().trim()).to.contain( - 'The selected file for "Passport photo" must be a JPG, JPEG, PNG or PDF' + 'The selected files must be a JPG, JPEG, PNG or PDF' ); });