Skip to content

Commit

Permalink
add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Neo-Ryo committed Apr 30, 2024
1 parent 34f3d87 commit 6429ade
Show file tree
Hide file tree
Showing 6 changed files with 163 additions and 13 deletions.
138 changes: 138 additions & 0 deletions server/__tests__/fileUpload.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
import type { Response, Request } from 'express';
import fs from 'fs';
import path from 'path';

import { uploadFiles } from '../controllers/filesController';
import type { User } from '../entities/user';
import { AwsS3 } from '../fileUpload/s3';
import { AppError } from '../middlewares/handleErrors';
import { appDataSource, fakeUser } from './mock';

beforeAll(() => {
return appDataSource.initialize();
});
beforeEach(() => {});
afterAll(() => {
return appDataSource.destroy();
});

const dummyPdf = fs.readFileSync(path.join(__dirname, 'files/dummy.pdf'));
describe('Upload files', () => {
test('Should return an url array', async () => {
jest.spyOn(AwsS3.prototype, 'uploadFile').mockImplementationOnce(() => {
return Promise.resolve('url/test');
});
jest.spyOn(AwsS3.prototype, 'uploadS3File').mockImplementationOnce(() => {
return Promise.resolve('url/test');
});

const mockRequest: Partial<Request> = {
user: fakeUser as User,
files: [
{
buffer: dummyPdf,
fieldname: 'files',
filename: 'dummy.pdf',
mimetype: 'application/pdf',
originalname: 'dummy.pdf',
path: 'server/__tests__/files',
size: 1000,
destination: 'server/__tests__/files',
} as Express.Multer.File,
],
};

const res = {} as unknown as Response;
res.json = jest.fn();
res.status = jest.fn(() => res); // chained

await uploadFiles(mockRequest as Request, res as Response);
expect(res.status).toHaveBeenCalledWith(200);
expect(res.json).toHaveBeenCalledWith(['url/test']);
});
test('Should throw - files are missing -', async () => {
const mockRequest: Partial<Request> = {
user: fakeUser as User,
files: [],
};

const res = {} as unknown as Response;
res.json = jest.fn();
res.status = jest.fn(() => res); // chained

await uploadFiles(mockRequest as Request, res as Response);
expect(res.status).toHaveBeenCalledWith(400);
expect(res.json).toHaveBeenCalledWith('Files are missing');
});
test('User forbiden', async () => {
const mockRequest: Partial<Request> = {
files: [],
};

const res = {} as unknown as Response;
res.json = jest.fn();
res.status = jest.fn(() => res); // chained

await uploadFiles(mockRequest as Request, res as Response);
expect(res.status).toHaveBeenCalledWith(400);
expect(res.json).toHaveBeenCalledWith('Forbidden');
});
test('Should throw an app error', async () => {
jest.spyOn(AwsS3.prototype, 'uploadFile').mockImplementationOnce(() => {
throw new AppError('Yolo', 0);
});

const mockRequest: Partial<Request> = {
user: fakeUser as User,
files: [
{
buffer: dummyPdf,
fieldname: 'files',
filename: 'dummy.pdf',
mimetype: 'application/pdf',
originalname: 'dummy.pdf',
path: 'server/__tests__/files',
size: 1000,
destination: 'server/__tests__/files',
} as Express.Multer.File,
],
};

const res = {} as unknown as Response;
res.json = jest.fn();
res.status = jest.fn(() => res); // chained

await uploadFiles(mockRequest as Request, res as Response);
expect(res.status).toHaveBeenCalledWith(400);
expect(res.json).toHaveBeenCalledWith('Yolo');
});
test('Should throw an unknown error', async () => {
jest.spyOn(AwsS3.prototype, 'uploadFile').mockImplementationOnce(() => {
throw new Error('Yolo');
});

const mockRequest: Partial<Request> = {
user: fakeUser as User,
files: [
{
buffer: dummyPdf,
fieldname: 'files',
filename: 'dummy.pdf',
mimetype: 'application/pdf',
originalname: 'dummy.pdf',
path: 'server/__tests__/files',
size: 1000,
destination: 'server/__tests__/files',
} as Express.Multer.File,
],
};

const res = {} as unknown as Response;
res.json = jest.fn();
res.status = jest.fn(() => res); // chained

await uploadFiles(mockRequest as Request, res as Response);
expect(res.status).toHaveBeenCalledWith(500);
expect(res.json).toHaveBeenCalledWith('Internal server error');
});
});
Binary file added server/__tests__/files/dummy-image.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added server/__tests__/files/dummy.pdf
Binary file not shown.
15 changes: 6 additions & 9 deletions server/controllers/filesController.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,31 @@
import type { Request, Response } from 'express';
import fs from 'fs';
import path from 'path';

import { uploadFile } from '../fileUpload';
import { AppError, ErrorCode } from '../middlewares/handleErrors';

export async function uploadFiles(req: Request, res: Response) {
try {
// const user = req.user;
// if (!user) {
// throw new AppError('Forbidden', ErrorCode.UNKNOWN);
// }
const user = req.user;
if (!user) {
throw new AppError('Forbidden', ErrorCode.UNKNOWN);
}
const { files } = req;
if (!files || !files.length) {
throw new AppError('Files are missing', ErrorCode.UNKNOWN);
}
const userId = 1;
const promises: Promise<string | null>[] = [];
for (const file of files as Express.Multer.File[]) {
// making the filename being the path here is a trick to use
// upload function...
const filename = `images/${userId}/${file.filename}`;
const filename = `images/${user.id}/${file.filename}`;
const promise = uploadFile(filename, file.mimetype);
promises.push(promise);
}
const results = await Promise.all(promises);
res.status(200).json(results);
} catch (error) {
if (error instanceof AppError) {
res.status(error.errorCode).json(error.message);
res.status(400).json(error.message);
} else {
res.status(500).json('Internal server error');
}
Expand Down
18 changes: 17 additions & 1 deletion server/controllers/multer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ export const diskStorage = multer.diskStorage({
cb(null, `${uuid}${path.extname(file.originalname)}`);
},
});

export const upload = multer({ storage: diskStorage });

export const diskStorageToImages = multer.diskStorage({
Expand All @@ -28,3 +27,20 @@ export const diskStorageToImages = multer.diskStorage({
cb(null, `${uuid}${path.extname(file.originalname)}`);
},
});

const whitelist = [
'application/pdf',
'application/vnd.ms-powerpoint',
'application/vnd.openxmlformats-officedocument.presentationml.presentation',
'application/msword',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
];
export const fileUplad = multer({
storage: diskStorageToImages,
fileFilter: (_req, file, cb) => {
if (!whitelist.includes(file.mimetype)) {
return cb(new Error('file is not allowed'));
}
cb(null, true);
},
});
5 changes: 2 additions & 3 deletions server/routes/filesRouter.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import { Router } from 'express';
import multer from 'multer';

import { UserType } from '../../types/user.type';
import { uploadFiles } from '../controllers/filesController';
import { diskStorageToImages } from '../controllers/multer';
import { fileUplad } from '../controllers/multer';
import { authenticate } from '../middlewares/authenticate';
import { handleErrors } from '../middlewares/handleErrors';

export const filesRouter = Router();

filesRouter.post('/', multer({ storage: diskStorageToImages }).array('files'), handleErrors(authenticate(UserType.ADMIN)), uploadFiles);
filesRouter.post('/', fileUplad.array('files'), handleErrors(authenticate(UserType.ADMIN)), uploadFiles);

0 comments on commit 6429ade

Please sign in to comment.