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