From 3f6e89d7160e9e7b898e5c8f2ebd03a1547fb690 Mon Sep 17 00:00:00 2001 From: Mihajlo Medjedovic Date: Fri, 30 Oct 2020 16:11:50 +0100 Subject: [PATCH] fix: file uploader error handling and tests --- src/FileUploader.ts | 53 +++++------ src/test/FileUploader.spec.ts | 93 +++++++++++++++++++ .../utils/parseGeneratedCode.spec.ts | 2 +- src/{ => test}/utils/parseSourceCode.spec.ts | 2 +- 4 files changed, 122 insertions(+), 28 deletions(-) create mode 100644 src/test/FileUploader.spec.ts rename src/{ => test}/utils/parseGeneratedCode.spec.ts (96%) rename src/{ => test}/utils/parseSourceCode.spec.ts (95%) diff --git a/src/FileUploader.ts b/src/FileUploader.ts index da87862..fe63ee4 100644 --- a/src/FileUploader.ts +++ b/src/FileUploader.ts @@ -1,6 +1,7 @@ import { isLogInRequired, needsRetry, isUrl } from './utils' import { CsrfToken } from './types/CsrfToken' import { UploadFile } from './types/UploadFile' +import { ErrorResponse } from './types' const requestRetryLimit = 5 @@ -18,29 +19,29 @@ export class FileUploader { private retryCount = 0 public uploadFile(sasJob: string, files: UploadFile[], params: any) { - if (files?.length < 1) - throw new Error('At least one file must be provided.') - - let paramsString = '' - - for (let param in params) { - if (params.hasOwnProperty(param)) { - paramsString += `&${param}=${params[param]}` - } - } - - const program = this.appLoc - ? this.appLoc.replace(/\/?$/, '/') + sasJob.replace(/^\//, '') - : sasJob - const uploadUrl = `${this.serverUrl}${this.jobsPath}/?${ - '_program=' + program - }${paramsString}` - - const headers = { - 'cache-control': 'no-cache' - } - return new Promise((resolve, reject) => { + if (files?.length < 1) reject(new ErrorResponse('At least one file must be provided.')) + if (!sasJob || sasJob === '') reject(new ErrorResponse('sasJob must be provided.')) + + let paramsString = '' + + for (let param in params) { + if (params.hasOwnProperty(param)) { + paramsString += `&${param}=${params[param]}` + } + } + + const program = this.appLoc + ? this.appLoc.replace(/\/?$/, '/') + sasJob.replace(/^\//, '') + : sasJob + const uploadUrl = `${this.serverUrl}${this.jobsPath}/?${ + '_program=' + program + }${paramsString}` + + const headers = { + 'cache-control': 'no-cache' + } + const formData = new FormData() for (let file of files) { @@ -48,7 +49,7 @@ export class FileUploader { } if (this.csrfToken) formData.append('_csrf', this.csrfToken.value) - + fetch(uploadUrl, { method: 'POST', body: formData, @@ -76,7 +77,7 @@ export class FileUploader { }) .then((responseText) => { if (isLogInRequired(responseText)) - reject('You must be logged in to upload a file') + reject(new ErrorResponse('You must be logged in to upload a file.')) if (needsRetry(responseText)) { if (this.retryCount < requestRetryLimit) { @@ -95,12 +96,12 @@ export class FileUploader { try { resolve(JSON.parse(responseText)) } catch (e) { - reject(e) + reject(new ErrorResponse('Error while parsing json from upload response.', e)) } } }) .catch((err: any) => { - reject(err) + reject(new ErrorResponse('Upload request failed.', err)) }) }) } diff --git a/src/test/FileUploader.spec.ts b/src/test/FileUploader.spec.ts new file mode 100644 index 0000000..538e178 --- /dev/null +++ b/src/test/FileUploader.spec.ts @@ -0,0 +1,93 @@ +import { FileUploader } from '../FileUploader' +import { UploadFile } from '../types'; + +(global as any).fetch = jest.fn().mockImplementation(() => + Promise.resolve({ + text: () => Promise.resolve(sampleResponse), + }) +); + +it('should upload successfully', async (done) => { + const fileUploader = + new FileUploader( + '/sample/apploc', + 'https://sample.server.com', + '/jobs/path', + null, + null + ) + + const sasJob = 'test/upload' + const files: UploadFile[] = [ + { + file: new File([''], 'testfile'), + fileName: 'testfile' + } + ]; + const params = {table: 'libtable'} + + fileUploader.uploadFile(sasJob, files, params).then( + (res: any) => { + if (JSON.stringify(res) === JSON.stringify(JSON.parse(sampleResponse))) done() + } + ) +}) + +it('should throw no files error', async (done) => { + const fileUploader = + new FileUploader( + '/sample/apploc', + 'https://sample.server.com', + '/jobs/path', + null, + null + ) + + const sasJob = 'test/upload' + const files: UploadFile[] = []; + const params = {table: 'libtable'} + + fileUploader.uploadFile(sasJob, files, params).then( + (res: any) => {}, + (err: any) => { + if (err.error.message === 'At least one file must be provided.') done() + } + ) +}) + +it('should throw no sasJob error', async (done) => { + const fileUploader = + new FileUploader( + '/sample/apploc', + 'https://sample.server.com', + '/jobs/path', + null, + null + ) + + const sasJob = '' + const files: UploadFile[] = [ + { + file: new File([''], 'testfile'), + fileName: 'testfile' + } + ]; + const params = {table: 'libtable'} + + fileUploader.uploadFile(sasJob, files, params).then( + (res: any) => {}, + (err: any) => { + if (err.error.message === 'sasJob must be provided.') done() + } + ) +}) + +const sampleResponse = `{ + "SYSUSERID": "cas", + "_DEBUG":" ", + "SYS_JES_JOB_URI": "/jobExecution/jobs/000-000-000-000", + "_PROGRAM" : "/Public/app/editors/loadfile", + "SYSCC" : "0", + "SYSJOBID" : "117382", + "SYSWARNINGTEXT" : "" +}` \ No newline at end of file diff --git a/src/utils/parseGeneratedCode.spec.ts b/src/test/utils/parseGeneratedCode.spec.ts similarity index 96% rename from src/utils/parseGeneratedCode.spec.ts rename to src/test/utils/parseGeneratedCode.spec.ts index 116a88f..d08108d 100644 --- a/src/utils/parseGeneratedCode.spec.ts +++ b/src/test/utils/parseGeneratedCode.spec.ts @@ -1,4 +1,4 @@ -import { parseGeneratedCode } from './index' +import { parseGeneratedCode } from '../../utils/index' it('should parse generated code', async (done) => { expect(sampleResponse).toBeTruthy() diff --git a/src/utils/parseSourceCode.spec.ts b/src/test/utils/parseSourceCode.spec.ts similarity index 95% rename from src/utils/parseSourceCode.spec.ts rename to src/test/utils/parseSourceCode.spec.ts index d407d49..4e779cb 100644 --- a/src/utils/parseSourceCode.spec.ts +++ b/src/test/utils/parseSourceCode.spec.ts @@ -1,4 +1,4 @@ -import { parseSourceCode } from './index' +import { parseSourceCode } from '../../utils/index' it('should parse SAS9 source code', async (done) => { expect(sampleResponse).toBeTruthy()