diff --git a/.gitignore b/.gitignore index c16ef02..4133897 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ # compiled output +.npmrc /dist /node_modules @@ -31,4 +32,4 @@ lerna-debug.log* !.vscode/settings.json !.vscode/tasks.json !.vscode/launch.json -!.vscode/extensions.json \ No newline at end of file +!.vscode/extensions.json diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..d2a0cb3 --- /dev/null +++ b/.npmignore @@ -0,0 +1 @@ +.npmrc diff --git a/CHANGELOG.md b/CHANGELOG.md index a5bd62e..2ecee5f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +### v1.9.9 +- Resolved [Issue 60](https://github.com/dmitriy-nz/nestjs-form-data/issues/60) +- Added test cases for `enableImplicitConversion` field in the `class-validator` transform options +- Modified `IsFile` validator to handle `enableImplicitConversion` param +- Some other test cases were improved + + ### v1.9.8 - Updated `README.md`, clarified `class-validator` pipe configuration diff --git a/package.json b/package.json index 2d987ea..b8a1cfd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "nestjs-form-data", - "version": "1.9.7", + "version": "1.9.9", "description": "NestJS middleware for handling multipart/form-data, which is primarily used for uploading files", "main": "dist/index", "types": "dist/index", diff --git a/src/decorators/validation/is-file.validator.ts b/src/decorators/validation/is-file.validator.ts index d34f19f..8f13a9f 100644 --- a/src/decorators/validation/is-file.validator.ts +++ b/src/decorators/validation/is-file.validator.ts @@ -25,6 +25,12 @@ export function IsFile(validationOptions?: ValidationOptions): PropertyDecorator }, }, validationOptions); + const transformEnableImplicitConversion = Transform(params => { + return params.obj[params.key] + }) + + + if(validationOptions?.each){ return applyDecorators( Transform((params: TransformFnParams) => { @@ -33,12 +39,15 @@ export function IsFile(validationOptions?: ValidationOptions): PropertyDecorator } return params.value; }), + transformEnableImplicitConversion, isFileValidator, - IsArray(Object.assign({},validationOptions || {}, {each: false})) - ) + IsArray(Object.assign({},validationOptions || {}, { each: false })) + ); } - return isFileValidator + return applyDecorators( + transformEnableImplicitConversion, + isFileValidator + ); - -} \ No newline at end of file +} diff --git a/test/array-files-upload.e2e-spec.ts b/test/array-files-upload.e2e-spec.ts index 52b6733..404434a 100644 --- a/test/array-files-upload.e2e-spec.ts +++ b/test/array-files-upload.e2e-spec.ts @@ -11,7 +11,7 @@ describe('Express - Array files uploads', () => { app = await createTestModule(); }); - it('Valid files upload', () => { + it('Valid files upload - array dto - array files', () => { return request .default(app.getHttpServer()) .post('/array-files') @@ -24,7 +24,7 @@ describe('Express - Array files uploads', () => { ]); }); - it('Valid single file as array', () => { + it('Valid files upload - array dto - single file', () => { return request .default(app.getHttpServer()) .post('/array-files') diff --git a/test/enable-implicit-conversion.e2e-spec.ts b/test/enable-implicit-conversion.e2e-spec.ts new file mode 100644 index 0000000..0fb737a --- /dev/null +++ b/test/enable-implicit-conversion.e2e-spec.ts @@ -0,0 +1,111 @@ +import { INestApplication } from '@nestjs/common'; +import { NestFastifyApplication } from '@nestjs/platform-fastify'; +import * as request from 'supertest'; +import path from 'path'; +import { createTestModule } from './helpers/create-test-module'; + +describe('Express - transform enableImplicitConversion', () => { + let app: INestApplication; + + beforeEach(async () => { + app = await createTestModule({}, { + transform: true, transformOptions: { + enableImplicitConversion: true, + }, + }); + }); + + it('Valid files upload - array dto - array files', () => { + return request + .default(app.getHttpServer()) + .post('/array-files') + .attach('files', path.resolve(__dirname, 'test-files', 'file.txt')) + .attach('files', path.resolve(__dirname, 'test-files', 'file.txt')) + .expect(200) + .expect([ + { filename: 'file.txt', mimetype: 'text/plain' }, + { filename: 'file.txt', mimetype: 'text/plain' }, + ]); + }); + + it('Valid files upload - array dto - single file', () => { + return request + .default(app.getHttpServer()) + .post('/array-files') + .attach('files', path.resolve(__dirname, 'test-files', 'file.txt')) + .expect(200) + .expect([{ filename: 'file.txt', mimetype: 'text/plain' }]); + }); + + it('Valid file upload - single dto - single file', () => { + return request + .default(app.getHttpServer()) + .post('/single-file') + .attach('file', path.resolve(__dirname, 'test-files', 'file.txt')) + .expect(200) + .expect({ filename: 'file.txt', mimetype: 'text/plain' }); + }); + + it('Invalid file upload - single dto - array file', () => { + return request + .default(app.getHttpServer()) + .post('/single-file') + .attach('file', path.resolve(__dirname, 'test-files', 'file.txt')) + .attach('file', path.resolve(__dirname, 'test-files', 'file.txt')) + .expect(400); + }); +}); + +describe('Fastify - transform enableImplicitConversion', () => { + let app: NestFastifyApplication; + + beforeEach(async () => { + app = (await createTestModule({ + fastify: true, + }, { + transform: true, transformOptions: { + enableImplicitConversion: true, + }, + })) as NestFastifyApplication; + }); + + it('Valid files upload - array dto - array files', () => { + return request + .default(app.getHttpServer()) + .post('/array-files') + .attach('files', path.resolve(__dirname, 'test-files', 'file.txt')) + .attach('files', path.resolve(__dirname, 'test-files', 'file.txt')) + .expect(200) + .expect([ + { filename: 'file.txt', mimetype: 'text/plain' }, + { filename: 'file.txt', mimetype: 'text/plain' }, + ]); + }); + + it('Valid files upload - array dto - single file', () => { + return request + .default(app.getHttpServer()) + .post('/array-files') + .attach('files', path.resolve(__dirname, 'test-files', 'file.txt')) + .expect(200) + .expect([{ filename: 'file.txt', mimetype: 'text/plain' }]); + }); + + it('Valid file upload - single dto - single file', () => { + return request + .default(app.getHttpServer()) + .post('/single-file') + .attach('file', path.resolve(__dirname, 'test-files', 'file.txt')) + .expect(200) + .expect({ filename: 'file.txt', mimetype: 'text/plain' }); + }); + + it('Invalid file upload - single dto - array file', () => { + return request + .default(app.getHttpServer()) + .post('/single-file') + .attach('file', path.resolve(__dirname, 'test-files', 'file.txt')) + .attach('file', path.resolve(__dirname, 'test-files', 'file.txt')) + .expect(400); + }); +}); diff --git a/test/helpers/create-test-module.ts b/test/helpers/create-test-module.ts index c2bf53e..dcc906e 100644 --- a/test/helpers/create-test-module.ts +++ b/test/helpers/create-test-module.ts @@ -1,13 +1,16 @@ import { Test, TestingModule } from '@nestjs/testing'; -import { INestApplication } from '@nestjs/common'; +import { INestApplication, ValidationPipe } from '@nestjs/common'; import { FastifyAdapter, NestFastifyApplication, } from '@nestjs/platform-fastify'; import { TestModule } from '../test-module/test.module'; +import { ValidationPipeOptions } from '@nestjs/common/pipes/validation.pipe'; export async function createTestModule( - config: any = {}, + config: any = {}, validationPipeOptions: ValidationPipeOptions = { + transform: true, + } ): Promise { const moduleFixture: TestingModule = await Test.createTestingModule({ imports: [TestModule.config(config)], @@ -27,6 +30,10 @@ export async function createTestModule( app = moduleFixture.createNestApplication(); } + app.useGlobalPipes( + new ValidationPipe(validationPipeOptions), + ); + await app.init(); if (useFastify) { diff --git a/test/single-upload.e2e-spec.ts b/test/single-upload.e2e-spec.ts index e70d4e0..ae434bd 100644 --- a/test/single-upload.e2e-spec.ts +++ b/test/single-upload.e2e-spec.ts @@ -11,7 +11,7 @@ describe('Express - Single file uploads', () => { app = await createTestModule(); }); - it('Valid file upload', () => { + it('Valid file upload - single dto - single file', () => { return request .default(app.getHttpServer()) .post('/single-file') @@ -20,6 +20,15 @@ describe('Express - Single file uploads', () => { .expect({ filename: 'file.txt', mimetype: 'text/plain' }); }); + it('Invalid file upload - single dto - array file', () => { + return request + .default(app.getHttpServer()) + .post('/single-file') + .attach('file', path.resolve(__dirname, 'test-files', 'file.txt')) + .attach('file', path.resolve(__dirname, 'test-files', 'file.txt')) + .expect(400); + }); + it('Mime type validator', () => { return request .default(app.getHttpServer())