Skip to content

Commit 91c7fa3

Browse files
authored
Merge pull request #58 from UTSC-CSCC01-Software-Engineering-I/backend_tests
controllers unit tests
2 parents 2cfc774 + a4051d4 commit 91c7fa3

3 files changed

Lines changed: 667 additions & 0 deletions

File tree

Lines changed: 294 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,294 @@
1+
// __tests__/pointController.test.js
2+
const {
3+
addPoint,
4+
getPoints,
5+
getUserPoints,
6+
editPoint,
7+
deletePoint
8+
} = require('../controllers/pointController');
9+
const User = require('../models/User');
10+
const Point = require('../models/pointsModel');
11+
12+
jest.mock('../models/User');
13+
jest.mock('../models/pointsModel');
14+
15+
describe('pointController', () => {
16+
let req, res, selectMock;
17+
18+
beforeEach(() => {
19+
req = { body: {}, params: {}, userId: 'u123' };
20+
res = {
21+
status: jest.fn().mockReturnThis(),
22+
json: jest.fn().mockReturnThis()
23+
};
24+
25+
// reset all mocks
26+
User.findById.mockReset();
27+
Point.find.mockReset();
28+
Point.findOne.mockReset();
29+
Point.findOneAndDelete.mockReset();
30+
Point.mockClear();
31+
32+
// default: findById().select('email') resolves to a fake user
33+
selectMock = jest.fn().mockResolvedValue({ _id: 'u123', email: 'foo@bar.com' });
34+
User.findById.mockReturnValue({ select: selectMock });
35+
});
36+
37+
describe('addPoint', () => {
38+
it('400 if any field is missing', async () => {
39+
req.body = { lat: 1.0, lon: 2.0 }; // missing temp
40+
await addPoint(req, res);
41+
expect(res.status).toHaveBeenCalledWith(400);
42+
expect(res.json).toHaveBeenCalledWith({ message: 'Missing required fields' });
43+
});
44+
45+
it('404 if user not found', async () => {
46+
req.body = { lat:1, lon:2, temp:3 };
47+
// each test gets its own select-mock
48+
const userSelect = jest.fn().mockResolvedValue(null);
49+
User.findById.mockReturnValue({ select: userSelect });
50+
51+
await addPoint(req, res);
52+
expect(User.findById).toHaveBeenCalledWith('u123');
53+
expect(userSelect).toHaveBeenCalledWith('email');
54+
expect(res.status).toHaveBeenCalledWith(404);
55+
expect(res.json).toHaveBeenCalledWith({ message: 'User not found' });
56+
});
57+
58+
59+
it('201 and point on success', async () => {
60+
req.body = { lat:1, lon:2, temp:3 };
61+
// mock Point constructor
62+
const fakePoint = { lat:1, lon:2, temp:3, user:{ id:'u123', email:'foo@bar.com' }, save: jest.fn() };
63+
Point.mockImplementation(() => fakePoint);
64+
65+
await addPoint(req, res);
66+
67+
expect(fakePoint.save).toHaveBeenCalled();
68+
expect(res.status).toHaveBeenCalledWith(201);
69+
expect(res.json).toHaveBeenCalledWith({
70+
message: 'Point added successfully',
71+
point: fakePoint
72+
});
73+
});
74+
75+
it('500 on save() error', async () => {
76+
req.body = { lat:1, lon:2, temp:3 };
77+
const badPoint = { save: jest.fn().mockRejectedValue(new Error('fail')) };
78+
Point.mockImplementation(() => badPoint);
79+
console.error = jest.fn();
80+
81+
await addPoint(req, res);
82+
83+
expect(res.status).toHaveBeenCalledWith(500);
84+
expect(res.json).toHaveBeenCalledWith({ message: 'Server error' });
85+
});
86+
});
87+
88+
describe('getPoints', () => {
89+
it('returns all points with source:user', async () => {
90+
const docs = [
91+
{ toObject: () => ({ foo: 'bar' }) },
92+
{ toObject: () => ({ baz: 'qux' }) }
93+
];
94+
Point.find.mockResolvedValue(docs);
95+
96+
await getPoints(req, res);
97+
98+
expect(Point.find).toHaveBeenCalledWith({});
99+
expect(res.json).toHaveBeenCalledWith({
100+
items: [
101+
{ foo: 'bar', source: 'user' },
102+
{ baz: 'qux', source: 'user' }
103+
]
104+
});
105+
});
106+
107+
it('500 on db error', async () => {
108+
Point.find.mockRejectedValue(new Error('oops'));
109+
console.error = jest.fn();
110+
111+
await getPoints(req, res);
112+
113+
expect(res.status).toHaveBeenCalledWith(500);
114+
expect(res.json).toHaveBeenCalledWith({ message: 'Server error' });
115+
});
116+
});
117+
118+
describe('getUserPoints', () => {
119+
it('404 when user missing', async () => {
120+
// simulate findById().select rejecting to no user
121+
User.findById.mockReturnValue({ select: jest.fn().mockResolvedValue(null) });
122+
123+
await getUserPoints(req, res);
124+
125+
expect(res.status).toHaveBeenCalledWith(404);
126+
expect(res.json).toHaveBeenCalledWith({
127+
success: false,
128+
message: 'User not found'
129+
});
130+
});
131+
132+
it('returns only this user’s points', async () => {
133+
const dbPoints = [
134+
{ _id:'1', lat:1, lon:2, temp:3, createdAt:'ts1' },
135+
{ _id:'2', lat:4, lon:5, temp:6, createdAt:'ts2' }
136+
];
137+
Point.find.mockResolvedValue(dbPoints);
138+
139+
await getUserPoints(req, res);
140+
141+
expect(Point.find).toHaveBeenCalledWith({ 'user.email':'foo@bar.com' });
142+
expect(res.json).toHaveBeenCalledWith({
143+
success: true,
144+
data: [
145+
{ _id:'1', lat:1, lon:2, temp:3, timestamp:'ts1', source:'user' },
146+
{ _id:'2', lat:4, lon:5, temp:6, timestamp:'ts2', source:'user' }
147+
]
148+
});
149+
});
150+
151+
it('500 on db error', async () => {
152+
// simulate error in findById.select
153+
User.findById.mockReturnValue({ select: jest.fn().mockRejectedValue(new Error('DB error')) });
154+
console.error = jest.fn();
155+
156+
await getUserPoints(req, res);
157+
158+
expect(res.status).toHaveBeenCalledWith(500);
159+
expect(res.json).toHaveBeenCalledWith({
160+
success: false,
161+
message: 'Server error'
162+
});
163+
});
164+
});
165+
166+
describe('editPoint', () => {
167+
beforeEach(() => {
168+
req.params.pointId = 'p1';
169+
});
170+
171+
it('400 if fields missing', async () => {
172+
req.body = { lat:1, lon:2 }; // missing temp
173+
await editPoint(req, res);
174+
expect(res.status).toHaveBeenCalledWith(400);
175+
expect(res.json).toHaveBeenCalledWith({
176+
success: false,
177+
message: 'Missing required fields: lat, lon, temp'
178+
});
179+
});
180+
181+
it('404 if user not found', async () => {
182+
req.body = { lat:1, lon:2, temp:3 };
183+
User.findById.mockReturnValue({ select: jest.fn().mockResolvedValue(null) });
184+
185+
await editPoint(req, res);
186+
expect(res.status).toHaveBeenCalledWith(404);
187+
expect(res.json).toHaveBeenCalledWith({
188+
success: false,
189+
message: 'User not found'
190+
});
191+
});
192+
193+
it('404 if point not found or wrong owner', async () => {
194+
req.body = { lat:1, lon:2, temp:3 };
195+
Point.findOne.mockResolvedValue(null);
196+
197+
await editPoint(req, res);
198+
expect(res.status).toHaveBeenCalledWith(404);
199+
expect(res.json).toHaveBeenCalledWith({
200+
success: false,
201+
message: 'Point not found or you do not have permission to edit it'
202+
});
203+
});
204+
205+
it('updates and returns success', async () => {
206+
req.body = { lat:1, lon:2, temp:3 };
207+
const found = {
208+
_id: 'p1',
209+
lat: 9, lon: 9, temp: 9,
210+
createdAt: 'ts',
211+
save: jest.fn()
212+
};
213+
Point.findOne.mockResolvedValue(found);
214+
215+
await editPoint(req, res);
216+
217+
expect(found.lat).toBe(1);
218+
expect(found.lon).toBe(2);
219+
expect(found.temp).toBe(3);
220+
expect(found.save).toHaveBeenCalled();
221+
expect(res.json).toHaveBeenCalledWith({
222+
success: true,
223+
message: 'Point updated successfully',
224+
point: {
225+
_id:'p1', lat:1, lon:2, temp:3,
226+
timestamp:'ts', source:'user'
227+
}
228+
});
229+
});
230+
231+
it('handles errors with 500', async () => {
232+
// must supply body so we don't hit the 400-missing-fields branch
233+
req.body = { lat:1, lon:2, temp:3 };
234+
const userSelect = jest.fn().mockRejectedValue(new Error('err'));
235+
User.findById.mockReturnValue({ select: userSelect });
236+
console.error = jest.fn();
237+
238+
await editPoint(req, res);
239+
expect(userSelect).toHaveBeenCalledWith('email');
240+
expect(res.status).toHaveBeenCalledWith(500);
241+
expect(res.json).toHaveBeenCalledWith({
242+
success: false,
243+
message: 'Server error'
244+
});
245+
});
246+
});
247+
248+
describe('deletePoint', () => {
249+
beforeEach(() => {
250+
req.params.pointId = 'p1';
251+
});
252+
253+
it('404 if user not found', async () => {
254+
User.findById.mockReturnValue({ select: jest.fn().mockResolvedValue(null) });
255+
await deletePoint(req, res);
256+
expect(res.status).toHaveBeenCalledWith(404);
257+
expect(res.json).toHaveBeenCalledWith({
258+
success: false,
259+
message: 'User not found'
260+
});
261+
});
262+
263+
it('404 if point not found or wrong owner', async () => {
264+
Point.findOneAndDelete.mockResolvedValue(null);
265+
await deletePoint(req, res);
266+
expect(res.status).toHaveBeenCalledWith(404);
267+
expect(res.json).toHaveBeenCalledWith({
268+
success: false,
269+
message: 'Point not found or you do not have permission to delete it'
270+
});
271+
});
272+
273+
it('deletes and returns success', async () => {
274+
Point.findOneAndDelete.mockResolvedValue({});
275+
await deletePoint(req, res);
276+
expect(res.json).toHaveBeenCalledWith({
277+
success: true,
278+
message: 'Point deleted successfully'
279+
});
280+
});
281+
282+
it('500 on error', async () => {
283+
User.findById.mockReturnValue({ select: jest.fn().mockRejectedValue(new Error('err')) });
284+
console.error = jest.fn();
285+
286+
await deletePoint(req, res);
287+
expect(res.status).toHaveBeenCalledWith(500);
288+
expect(res.json).toHaveBeenCalledWith({
289+
success: false,
290+
message: 'Server error'
291+
});
292+
});
293+
});
294+
});

0 commit comments

Comments
 (0)