From de6b74d3572857a7b0efacf2ba5f96f81c060a0e Mon Sep 17 00:00:00 2001 From: Clooooode Date: Wed, 13 Mar 2024 19:46:03 +0800 Subject: [PATCH 1/2] test: case with optional file @ upload --- tests/fixtures/controllers/postController.ts | 7 ++--- tests/integration/express-server.spec.ts | 27 ++++++++++++++++++-- tests/integration/hapi-server.spec.ts | 27 ++++++++++++++++++-- tests/integration/koa-server.spec.ts | 27 ++++++++++++++++++-- 4 files changed, 79 insertions(+), 9 deletions(-) diff --git a/tests/fixtures/controllers/postController.ts b/tests/fixtures/controllers/postController.ts index ff581e249..b385543af 100644 --- a/tests/fixtures/controllers/postController.ts +++ b/tests/fixtures/controllers/postController.ts @@ -75,12 +75,13 @@ export class PostTestController { return [fileA, fileB]; } - @Post('MixedFormDataWithFile') + @Post('MixedFormDataWithFilesContainsOptionalFile') public async mixedFormDataWithFile( @FormField('username') username: string, @UploadedFile('avatar') avatar: File, - ): Promise<{ username: string; avatar: File; }> { - return { username, avatar }; + @UploadedFile('optionalAvatar') optionalAvatar?: File, + ): Promise<{ username: string; avatar: File; optionalAvatar?: File; }> { + return { username, avatar, optionalAvatar }; } /** diff --git a/tests/integration/express-server.spec.ts b/tests/integration/express-server.spec.ts index cf5e6af9d..d3bb88272 100644 --- a/tests/integration/express-server.spec.ts +++ b/tests/integration/express-server.spec.ts @@ -1560,16 +1560,17 @@ describe('Express Server', () => { }); }); - it('can post mixed form data content with file', () => { + it('can post mixed form data content with file and not providing optional file', () => { const formData = { username: 'test', avatar: '@../tsconfig.json', }; - return verifyFileUploadRequest(`${basePath}/PostTest/MixedFormDataWithFile`, formData, (_err, res) => { + return verifyFileUploadRequest(`${basePath}/PostTest/MixedFormDataWithFilesContainsOptionalFile`, formData, (_err, res) => { const file = res.body.avatar; const packageJsonBuffer = readFileSync(resolve(__dirname, `../${file.originalname}`)); const returnedBuffer = Buffer.from(file.buffer); expect(res.body.username).to.equal(formData.username); + expect(res.body.optionalAvatar).to.undefined; expect(file).to.not.be.undefined; expect(file.fieldname).to.be.not.undefined; expect(file.originalname).to.be.not.undefined; @@ -1579,6 +1580,28 @@ describe('Express Server', () => { }); }); + it('can post mixed form data content with file and provides optional file', () => { + const formData = { + username: 'test', + avatar: '@../tsconfig.json', + optionalAvatar: '@../package.json', + }; + return verifyFileUploadRequest(`${basePath}/PostTest/MixedFormDataWithFilesContainsOptionalFile`, formData, (_err, res) => { + expect(res.body.username).to.equal(formData.username); + for (const fieldName of ['avatar', 'optionalAvatar']) { + const file = res.body[fieldName]; + const packageJsonBuffer = readFileSync(resolve(__dirname, `../${file.originalname}`)); + const returnedBuffer = Buffer.from(file.buffer); + expect(file).to.not.be.undefined; + expect(file.fieldname).to.be.not.undefined; + expect(file.originalname).to.be.not.undefined; + expect(file.encoding).to.be.not.undefined; + expect(file.mimetype).to.equal('application/json'); + expect(Buffer.compare(returnedBuffer, packageJsonBuffer)).to.equal(0); + } + }); + }); + function verifyFileUploadRequest( path: string, formData: any, diff --git a/tests/integration/hapi-server.spec.ts b/tests/integration/hapi-server.spec.ts index 24729fc9a..0610bb73e 100644 --- a/tests/integration/hapi-server.spec.ts +++ b/tests/integration/hapi-server.spec.ts @@ -1443,16 +1443,17 @@ describe('Hapi Server', () => { }); }); - it('can post mixed form data content with file', () => { + it('can post mixed form data content with file and not providing optional file', () => { const formData = { username: 'test', avatar: '@../tsconfig.json', }; - return verifyFileUploadRequest(`${basePath}/PostTest/MixedFormDataWithFile`, formData, (_err, res) => { + return verifyFileUploadRequest(`${basePath}/PostTest/MixedFormDataWithFilesContainsOptionalFile`, formData, (_err, res) => { const file = res.body.avatar; const packageJsonBuffer = readFileSync(resolve(__dirname, `../${file.originalname}`)); const returnedBuffer = Buffer.from(file.buffer); expect(res.body.username).to.equal(formData.username); + expect(res.body.optionalAvatar).to.undefined; expect(file).to.not.be.undefined; expect(file.fieldname).to.be.not.undefined; expect(file.originalname).to.be.not.undefined; @@ -1462,6 +1463,28 @@ describe('Hapi Server', () => { }); }); + it('can post mixed form data content with file and provides optional file', () => { + const formData = { + username: 'test', + avatar: '@../tsconfig.json', + optionalAvatar: '@../package.json', + }; + return verifyFileUploadRequest(`${basePath}/PostTest/MixedFormDataWithFilesContainsOptionalFile`, formData, (_err, res) => { + expect(res.body.username).to.equal(formData.username); + for (const fieldName of ['avatar', 'optionalAvatar']) { + const file = res.body[fieldName]; + const packageJsonBuffer = readFileSync(resolve(__dirname, `../${file.originalname}`)); + const returnedBuffer = Buffer.from(file.buffer); + expect(file).to.not.be.undefined; + expect(file.fieldname).to.be.not.undefined; + expect(file.originalname).to.be.not.undefined; + expect(file.encoding).to.be.not.undefined; + expect(file.mimetype).to.equal('application/json'); + expect(Buffer.compare(returnedBuffer, packageJsonBuffer)).to.equal(0); + } + }); + }); + function verifyFileUploadRequest( path: string, formData: any, diff --git a/tests/integration/koa-server.spec.ts b/tests/integration/koa-server.spec.ts index 2ad02fb7d..568f28e1b 100644 --- a/tests/integration/koa-server.spec.ts +++ b/tests/integration/koa-server.spec.ts @@ -1423,16 +1423,17 @@ describe('Koa Server', () => { }); }); - it('can post mixed form data content with file', () => { + it('can post mixed form data content with file and not providing optional file', () => { const formData = { username: 'test', avatar: '@../tsconfig.json', }; - return verifyFileUploadRequest(`${basePath}/PostTest/MixedFormDataWithFile`, formData, (_err, res) => { + return verifyFileUploadRequest(`${basePath}/PostTest/MixedFormDataWithFilesContainsOptionalFile`, formData, (_err, res) => { const file = res.body.avatar; const packageJsonBuffer = readFileSync(resolve(__dirname, `../${file.originalname}`)); const returnedBuffer = Buffer.from(file.buffer); expect(res.body.username).to.equal(formData.username); + expect(res.body.optionalAvatar).to.undefined; expect(file).to.not.be.undefined; expect(file.fieldname).to.be.not.undefined; expect(file.originalname).to.be.not.undefined; @@ -1442,6 +1443,28 @@ describe('Koa Server', () => { }); }); + it('can post mixed form data content with file and provides optional file', () => { + const formData = { + username: 'test', + avatar: '@../tsconfig.json', + optionalAvatar: '@../package.json', + }; + return verifyFileUploadRequest(`${basePath}/PostTest/MixedFormDataWithFilesContainsOptionalFile`, formData, (_err, res) => { + expect(res.body.username).to.equal(formData.username); + for (const fieldName of ['avatar', 'optionalAvatar']) { + const file = res.body[fieldName]; + const packageJsonBuffer = readFileSync(resolve(__dirname, `../${file.originalname}`)); + const returnedBuffer = Buffer.from(file.buffer); + expect(file).to.not.be.undefined; + expect(file.fieldname).to.be.not.undefined; + expect(file.originalname).to.be.not.undefined; + expect(file.encoding).to.be.not.undefined; + expect(file.mimetype).to.equal('application/json'); + expect(Buffer.compare(returnedBuffer, packageJsonBuffer)).to.equal(0); + } + }); + }); + function verifyFileUploadRequest( path: string, formData: any, From 41b1e4804eb3eb89e00980715832d24a30f63c41 Mon Sep 17 00:00:00 2001 From: Clooooode Date: Wed, 13 Mar 2024 19:59:26 +0800 Subject: [PATCH 2/2] fix: missing optional file case in upload validate --- .../templates/express/expressTemplateService.ts | 4 ++++ .../src/routeGeneration/templates/koa/koaTemplateService.ts | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/packages/runtime/src/routeGeneration/templates/express/expressTemplateService.ts b/packages/runtime/src/routeGeneration/templates/express/expressTemplateService.ts index eb7578c72..d65364384 100644 --- a/packages/runtime/src/routeGeneration/templates/express/expressTemplateService.ts +++ b/packages/runtime/src/routeGeneration/templates/express/expressTemplateService.ts @@ -85,6 +85,10 @@ export class ExpressTemplateService extends TemplateService param.dataType === 'file'); if (param.dataType === 'file' && files.length > 0) { const requestFiles = request.files as { [fileName: string]: Express.Multer.File[] }; + if (requestFiles[name] === undefined) { + return undefined; + } + const fileArgs = this.validationService.ValidateParam(param, requestFiles[name], name, fieldErrors, undefined, this.minimalSwaggerConfig); return fileArgs.length === 1 ? fileArgs[0] : fileArgs; } else if (param.dataType === 'array' && param.array && param.array.dataType === 'file') { diff --git a/packages/runtime/src/routeGeneration/templates/koa/koaTemplateService.ts b/packages/runtime/src/routeGeneration/templates/koa/koaTemplateService.ts index 4660179d5..f5cea4f0b 100644 --- a/packages/runtime/src/routeGeneration/templates/koa/koaTemplateService.ts +++ b/packages/runtime/src/routeGeneration/templates/koa/koaTemplateService.ts @@ -94,6 +94,10 @@ export class KoaTemplateService extends TemplateService param.dataType === 'file'); const contextRequest = context.request as any; if (param.dataType === 'file' && files.length > 0) { + if (contextRequest.files[name] === undefined) { + return undefined; + } + const fileArgs = this.validationService.ValidateParam(param, contextRequest.files[name], name, errorFields, undefined, this.minimalSwaggerConfig); return fileArgs.length === 1 ? fileArgs[0] : fileArgs; } else if (param.dataType === 'array' && param.array && param.array.dataType === 'file') {