Skip to content

Commit c75cdad

Browse files
committed
deleteProject controller tests
1 parent db717b7 commit c75cdad

File tree

5 files changed

+183
-32
lines changed

5 files changed

+183
-32
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export const getObjectKey = jest.mock();
2+
export const deleteObjectsFromS3 = jest.fn();
3+
export const signS3 = jest.fn();
4+
export const copyObjectInS3 = jest.fn();
5+
export const listObjectsInS3ForUser = jest.fn();

server/controllers/project.controller.js

Lines changed: 1 addition & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,18 @@ import archiver from 'archiver';
22
import format from 'date-fns/format';
33
import isUrl from 'is-url';
44
import jsdom, { serializeDocument } from 'jsdom';
5-
import isBefore from 'date-fns/is_before';
65
import isAfter from 'date-fns/is_after';
76
import request from 'request';
87
import slugify from 'slugify';
98
import Project from '../models/project';
109
import User from '../models/user';
1110
import { resolvePathToFile } from '../utils/filePath';
1211
import generateFileSystemSafeName from '../utils/generateFileSystemSafeName';
13-
import { deleteObjectsFromS3, getObjectKey } from './aws.controller';
1412
import { toApi as toApiProjectObject } from '../domain-objects/Project';
1513
import createApplicationErrorClass from '../utils/createApplicationErrorClass';
1614

1715
export { default as createProject, apiCreateProject } from './project.controller/createProject';
16+
export { default as deleteProject } from './project.controller/deleteProject';
1817

1918
const UserNotFoundError = createApplicationErrorClass('UserNotFoundError');
2019

@@ -88,36 +87,7 @@ export function getProject(req, res) {
8887
});
8988
}
9089

91-
function deleteFilesFromS3(files) {
92-
deleteObjectsFromS3(files.filter((file) => {
93-
if (file.url) {
94-
if (!process.env.S3_DATE || (
95-
process.env.S3_DATE &&
96-
isBefore(new Date(process.env.S3_DATE), new Date(file.createdAt)))) {
97-
return true;
98-
}
99-
}
100-
return false;
101-
})
102-
.map(file => getObjectKey(file.url)));
103-
}
10490

105-
export function deleteProject(req, res) {
106-
Project.findById(req.params.project_id, (findProjectErr, project) => {
107-
if (!project.user.equals(req.user._id)) {
108-
res.status(403).json({ success: false, message: 'Authenticated user does not match owner of project.' });
109-
return;
110-
}
111-
deleteFilesFromS3(project.files);
112-
project.remove((removeProjectError) => {
113-
if (removeProjectError) {
114-
res.status(404).send({ message: 'Project with that id does not exist' });
115-
return;
116-
}
117-
res.json({ success: true });
118-
});
119-
});
120-
}
12191

12292
export function getProjectsForUserId(userId) {
12393
return new Promise((resolve, reject) => {
@@ -239,7 +209,6 @@ export function apiGetProjectsForUser(req, res) {
239209
}
240210
}
241211

242-
243212
export function projectExists(projectId, callback) {
244213
Project.findById(projectId, (err, project) => (
245214
project ? callback(true) : callback(false)
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
/**
2+
* @jest-environment node
3+
*/
4+
import { Request, Response } from 'jest-express';
5+
6+
import Project, { createMock, createInstanceMock } from '../../../models/project';
7+
import User from '../../../models/user';
8+
import deleteProject from '../../project.controller/deleteProject';
9+
import { deleteObjectsFromS3 } from '../../aws.controller';
10+
11+
12+
jest.mock('../../../models/project');
13+
jest.mock('../../aws.controller');
14+
15+
describe('project.controller', () => {
16+
describe('deleteProject()', () => {
17+
let ProjectMock;
18+
let ProjectInstanceMock;
19+
20+
beforeEach(() => {
21+
ProjectMock = createMock();
22+
ProjectInstanceMock = createInstanceMock();
23+
});
24+
25+
afterEach(() => {
26+
ProjectMock.restore();
27+
ProjectInstanceMock.restore();
28+
});
29+
30+
it('returns 403 if project is not owned by authenticated user', (done) => {
31+
const user = new User();
32+
const project = new Project();
33+
project.user = user;
34+
35+
const request = new Request();
36+
request.setParams({ project_id: project._id });
37+
request.user = { _id: 'abc123' };
38+
39+
const response = new Response();
40+
41+
ProjectMock
42+
.expects('findById')
43+
.resolves(project);
44+
45+
const promise = deleteProject(request, response);
46+
47+
function expectations() {
48+
expect(response.status).toHaveBeenCalledWith(403);
49+
expect(response.json).toHaveBeenCalledWith({ success: false, message: 'Authenticated user does not match owner of project' });
50+
51+
done();
52+
}
53+
54+
promise.then(expectations, expectations).catch(expectations);
55+
});
56+
57+
it('returns 404 if project does not exist', (done) => {
58+
const user = new User();
59+
const project = new Project();
60+
project.user = user;
61+
62+
const request = new Request();
63+
request.setParams({ project_id: project._id });
64+
request.user = { _id: 'abc123' };
65+
66+
const response = new Response();
67+
68+
ProjectMock
69+
.expects('findById')
70+
.resolves(null);
71+
72+
const promise = deleteProject(request, response);
73+
74+
function expectations() {
75+
expect(response.status).toHaveBeenCalledWith(404);
76+
expect(response.json).toHaveBeenCalledWith({ success: false, message: 'Project with that id does not exist' });
77+
78+
done();
79+
}
80+
81+
promise.then(expectations, expectations).catch(expectations);
82+
});
83+
84+
it('deletes project and dependent files from S3 ', (done) => {
85+
const user = new User();
86+
const project = new Project();
87+
project.user = user;
88+
89+
const request = new Request();
90+
request.setParams({ project_id: project._id });
91+
request.user = { _id: user._id };
92+
93+
const response = new Response();
94+
95+
ProjectMock
96+
.expects('findById')
97+
.resolves(project);
98+
99+
ProjectInstanceMock.expects('remove')
100+
.yields();
101+
102+
const promise = deleteProject(request, response);
103+
104+
function expectations() {
105+
expect(response.status).toHaveBeenCalledWith(200);
106+
expect(response.json).toHaveBeenCalledWith({ success: true });
107+
expect(deleteObjectsFromS3).toHaveBeenCalled();
108+
109+
done();
110+
}
111+
112+
promise.then(expectations, expectations).catch(expectations);
113+
});
114+
});
115+
});
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import isBefore from 'date-fns/is_before';
2+
import Project from '../../models/project';
3+
import { deleteObjectsFromS3, getObjectKey } from '../aws.controller';
4+
import createApplicationErrorClass from '../../utils/createApplicationErrorClass';
5+
6+
const ProjectDeletionError = createApplicationErrorClass('ProjectDeletionError');
7+
8+
function deleteFilesFromS3(files) {
9+
deleteObjectsFromS3(files.filter((file) => {
10+
if (file.url) {
11+
if (!process.env.S3_DATE || (
12+
process.env.S3_DATE &&
13+
isBefore(new Date(process.env.S3_DATE), new Date(file.createdAt)))) {
14+
return true;
15+
}
16+
}
17+
return false;
18+
})
19+
.map(file => getObjectKey(file.url)));
20+
}
21+
22+
export default function deleteProject(req, res) {
23+
function sendFailure(error) {
24+
res.status(error.code).json({ success: false, message: error.message });
25+
}
26+
27+
function sendProjectNotFound() {
28+
sendFailure(new ProjectDeletionError('Project with that id does not exist', { code: 404 }));
29+
}
30+
31+
function handleProjectDeletion(project) {
32+
if (project == null) {
33+
sendProjectNotFound();
34+
return;
35+
}
36+
37+
if (!project.user.equals(req.user._id)) {
38+
sendFailure(new ProjectDeletionError('Authenticated user does not match owner of project', { code: 403 }));
39+
return;
40+
}
41+
42+
deleteFilesFromS3(project.files);
43+
44+
project.remove((removeProjectError) => {
45+
if (removeProjectError) {
46+
sendProjectNotFound();
47+
return;
48+
}
49+
50+
res.status(200).json({ success: true });
51+
});
52+
}
53+
54+
return Project.findById(req.params.project_id)
55+
.then(handleProjectDeletion)
56+
.catch(sendFailure);
57+
}

server/models/__mocks__/project.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@ export function createInstanceMock() {
2121
configurable: true,
2222
});
2323

24+
Object.defineProperty(Project.prototype, 'remove', {
25+
value: Project.prototype.remove,
26+
configurable: true,
27+
});
28+
2429
return sinon.mock(Project.prototype);
2530
}
2631

0 commit comments

Comments
 (0)