Reputation: 211
I have below file in my nestjs.
import { extname } from 'path';
import { diskStorage } from 'multer';
import { v4 as uuid } from 'uuid';
import { HttpException, HttpStatus } from '@nestjs/common';
export const multerConfig = {
dest: process.env.UPLOAD_LOCATION,
};
export const multerOptions = {
limits: {
fileSize: +process.env.MAX_FILE_SIZE,
},
fileFilter: (_req: any, file: any, cb: any) => {
if (file.mimetype.match(/\/(jpg|jpeg|png|gif|pdf|msg|eml)$/)) {
cb(null, true);
} else {
cb(
new HttpException(
`Unsupported file type ${extname(file.originalname)}`,
HttpStatus.BAD_REQUEST
),
false
);
}
},
storage: diskStorage({
destination: multerConfig.dest,
filename: (_req: any, file: any, cb: any) => {
cb(null, `${uuid()}${extname(file.originalname)}`);
},
}),
};
I wrote below test cases for it.
import { Readable } from 'stream';
import { multerConfig, multerOptions } from './multer.config';
describe('Multer Configuration ', () => {
const mockFile: Express.Multer.File = {
filename: '',
fieldname: '',
originalname: '',
encoding: '',
mimetype: '',
size: 1,
stream: new Readable(),
destination: '',
path: '',
buffer: Buffer.from('', 'utf8'),
};
it('should define destination', () => {
expect(multerConfig).toBeDefined();
expect(multerConfig.dest).toBe(process.env.UPLOAD_LOCATION);
});
it('should define multer upload options', async () => {
expect(multerOptions).toBeDefined();
expect(multerOptions.fileFilter).toBeDefined();
expect(multerOptions.storage).toBeTruthy();
expect(multerOptions.limits).toBeTruthy();
const cb = jest.fn();
multerOptions.fileFilter({}, mockFile, cb);
expect(cb).toHaveBeenCalled();
expect(cb).toHaveBeenCalledTimes(1);
expect(cb()).toBeFalsy();
});
afterAll(() => {
jest.resetAllMocks();
});
});
Both the test cases are successful but when I check code coverage then it is showing only 50% .It is showing line 16
and 31
not covered.
Line 16 is
cb(null, true); it comes inside the `if` block
and line 31 is
cb(null, `${uuid()}${extname(file.originalname)}`);
Could you please help me how can I cover this part? I am really struggling. Do I need to additional test case or I need to modify the existing test case?
Edit 1:-
const fileType = 'jpg';
it('should define filetype', async () => {
const cb = jest.fn();
process.env.FILE_TYPE = 'jpg';
multerOptions.fileFilter({}, mockFile, cb);
expect(cb).toHaveBeenCalled();
expect(cb).toHaveBeenCalledTimes(1);
expect(cb()).toBeFalsy();
});
Test case getting success. but coverage and lines are still same
Upvotes: 1
Views: 1400
Reputation: 20420
Your first not covered part of the code comes from the fact that you use pattern matching on the mime type.
if (file.mimetype.match(/\/(jpg|jpeg|png|gif|pdf|msg|eml)$/)) {
cb(null, true);
}
So you need to create a test that creates a mock file with one of those mime types.
For example, something like below. Although, in a good test setup, you probably would want to test all those extensions as a test case. Maybe with some sort of table driven test approach.
const mockFile: Express.Multer.File = {
mimetype: 'jpg',
// other stuff
};
It seems that in your test, the function always goes into the else block, which raises an HTTP Exception.
Your second issue is that you don't use options.storage, in your tests. And you also provide the options to something that would make the function get called.
Potentially, you can call it like below in your test.
const upload = multer(multerOptions).single('somefile');
If you don't want to do that, you could move the callback into a named function and assign it.
export function filename(_req: any, file: any, cb: any) {
cb(null, `${uuid()}${extname(file.originalname)}`);
}
export const multerOptions = {
storage: diskStorage({
destination: multerConfig.dest,
filename,
}),
}
Then you can test the filename function on its own in your test setup.
Or you find a way to call the filename function on the storage object on its own. I don't know multer
, so I cannot tell if it is possible. You would need to consult the documentation.
In total this might look like this.
import { extname } from 'path';
import { diskStorage } from 'multer';
import { v4 as uuid } from 'uuid';
import { HttpException, HttpStatus } from '@nestjs/common';
export const multerConfig = {
dest: process.env.UPLOAD_LOCATION,
};
export function filename(_req: any, file: any, cb: any) {
cb(null, `${uuid()}${extname(file.originalname)}`);
};
export const multerOptions = {
limits: {
fileSize: +process.env.MAX_FILE_SIZE,
},
fileFilter: (_req: any, file: any, cb: any) => {
if (file.mimetype.match(/\/(jpg|jpeg|png|gif|pdf|msg|eml)$/)) {
cb(null, true);
} else {
cb(
new HttpException(
`Unsupported file type ${extname(file.originalname)}`,
HttpStatus.BAD_REQUEST
),
false
);
}
},
storage: diskStorage({
destination: multerConfig.dest,
filename,
}),
};
And then in your test like this.
import { Readable } from 'stream';
import { multerConfig, multerOptions, filename } from './multer.config';
describe('Multer Configuration ', () => {
const mockFile: Express.Multer.File = {
filename: 'foo.jpg', // give it a name
fieldname: '',
originalname: '',
encoding: 'utf8',
mimetype: 'jpg', // give it a mime type
size: 1,
stream: new Readable(),
destination: '',
path: '',
buffer: Buffer.from('', 'utf8'),
};
it('should define destination', () => {
expect(multerConfig).toBeDefined();
expect(multerConfig.dest).toBe(process.env.UPLOAD_LOCATION);
});
it('should define multer upload options', async () => {
expect(multerOptions).toBeDefined();
expect(multerOptions.fileFilter).toBeDefined();
expect(multerOptions.storage).toBeTruthy();
expect(multerOptions.limits).toBeTruthy();
});
// test the filter
it('should filter the file based on mimetype', () => {
const cb = jest.fn();
multerOptions.fileFilter({}, mockFile, cb);
// do something with the callback
});
// test the filename
it('should create the proper filename', () => {
const cb = jest.fn();
filename({}, mockfile, cb)
// do something with the callback
});
afterAll(() => {
jest.resetAllMocks();
});
});
I am not sure how to use jest or what you actually want to test. But like this, the line should get covered. But coverage doesn't mean much in that sense. The tests like this are not good. You should work out what precisely you want to test. This is just to show you wants roughly required.
Upvotes: 2