diff --git a/src/errorHandler/handlerForExpress.ts b/src/errorHandler/handlerForExpress.ts index 7c0fbbb..6b0ea56 100644 --- a/src/errorHandler/handlerForExpress.ts +++ b/src/errorHandler/handlerForExpress.ts @@ -8,18 +8,27 @@ export const errorLogger = ( response: Response, next: NextFunction, ) => { - console.log(`error ${error.message}`); - next(error); // calling next middleware + console.log(`Caught Error: ${error.message}`); + return next(error); }; // Error handling Middleware function reads the error message // and sends back a response in JSON format -export const errorResponder = (error: Error, request: Request, response: Response) => { - response.header('Content-Type', 'application/json'); - if (error instanceof BaseError) { - response.status(error.status).send(error.message); +export const errorResponder = ( + error: Error, + request: Request, + response: Response, + next: NextFunction, +) => { + if (error) { + response.header('Content-Type', 'application/json'); + if (error instanceof BaseError) { + response.status(error.status).send({ message: error.message }); + } else { + response.status(500).send({ message: 'Something went wrong' }); + } } else { - response.status(500).send('Something went wrong'); + next(); } }; @@ -27,5 +36,5 @@ export const errorResponder = (error: Error, request: Request, response: Respons // 404 error for undefined paths export const invalidPathHandler = (request: Request, response: Response) => { response.status(404); - response.send('invalid path'); + response.send('Invalid path'); }; diff --git a/src/firebase/users.ts b/src/firebase/users.ts index e64cda1..e97d4fa 100644 --- a/src/firebase/users.ts +++ b/src/firebase/users.ts @@ -24,7 +24,7 @@ export async function createUser(newUser: BeforeCreateUser): Promise { const emailQuery = query(collection(db, 'users'), where('email', '==', newUser.email)); const emailQuerySnapshot = await getDocs(emailQuery); if (!emailQuerySnapshot.empty) { - throw new BaseError('That email is already in the system', 400); + throw new BaseError('That email is already in the system', 400); } const hashedPassword: string = await bcrypt.hash(newUser.password!, 10); const docRef = doc(collection(db, `users`)); @@ -89,11 +89,7 @@ export async function getUserByToken(id: string): Promise { return user as User; } -export async function userLogin( - email: string, - password: string, - orgId: string, -): Promise<{ user: User }> { +export async function userLogin(email: string, password: string, orgId: string): Promise { const emailQuery = query(collection(db, 'users'), where('email', '==', email)); const emailQuerySnapshot = await getDocs(emailQuery); @@ -117,7 +113,7 @@ export async function userLogin( if (!user) { throw new BaseError('User not found', 404); } - return { user }; + return user; } } throw new BaseError('User did not complete the login because something was spelt wrong!', 401); diff --git a/src/index.ts b/src/index.ts index b83fdc0..54d6be3 100644 --- a/src/index.ts +++ b/src/index.ts @@ -19,6 +19,7 @@ app.use('/users', userRoutes); app.get('/', (req: Request, res: Response) => { res.send('Hello, this is the backend.'); }); + // Catch celebrate validation errors app.use(errors()); diff --git a/src/jest/users.test.ts b/src/jest/users.test.ts index c667b7c..a8ec98e 100644 --- a/src/jest/users.test.ts +++ b/src/jest/users.test.ts @@ -23,12 +23,14 @@ describe('FIREBASE User tests', () => { beforeAll(async () => { testUser = await createUser(createTestUser); }); + test('Successfully create a user in the FIREBASE User service', async () => { expect(testUser.firstName).toBe(createTestUser.firstName); expect(testUser.lastName).toBe(createTestUser.lastName); expect(testUser.email).toBe(createTestUser.email); expect(testUser.orgId).toStrictEqual(createTestUser.orgId); }); + test('Successfully retrieve a user by organization ID from the FIREBASE User service', async () => { const data = await getAllUsersByOrgId(testUser.orgId![0]); const corretId = data.find((e) => e.id === testUser.id); @@ -46,17 +48,18 @@ describe('FIREBASE User tests', () => { expect(data.email).toBe(testUser.email); expect(data.orgId).toStrictEqual(testUser.orgId); }); + test('Successfully log in a user via the FIREBASE User service', async () => { const data = await userLogin( testUser.email, createTestUser.password as string, testUser.orgId![0].toString(), ); - expect(data.user.firstName).toBe(testUser.firstName); - expect(data.user.lastName).toBe(testUser.lastName); - expect(data.user.email).toBe(testUser.email); - expect(data.user.orgId[0]).toStrictEqual(testUser.orgId); - expect(data.user.id).toBe(testUser.id); + expect(data.firstName).toBe(testUser.firstName); + expect(data.lastName).toBe(testUser.lastName); + expect(data.email).toBe(testUser.email); + expect(data.orgId[0]).toStrictEqual(testUser.orgId); + expect(data.id).toBe(testUser.id); }); test('Successfully delete a user from the FIREBASE User service', async () => { @@ -68,7 +71,6 @@ describe('FIREBASE User tests', () => { /******************/ /**** Express ****/ /******************/ - describe('EXPRESS user routes', () => { let expressId: string; let expressToken: string; @@ -92,6 +94,7 @@ describe('EXPRESS user routes', () => { expect(res.body.email).toBe(user1.email); expect(res.body).not.toHaveProperty('password'); }); + test('Successfully log in a user via the EXPRESS user route', async () => { const res = await request(app) .post('/users/' + orgid + '/login') @@ -101,11 +104,12 @@ describe('EXPRESS user routes', () => { }) .set('Authorization', 'Bearer ' + expressToken); expect(res.statusCode).toBe(200); - expect(res.body.user.firstName).toBe(user1.firstName); - expect(res.body.user.lastName).toBe(user1.lastName); - expect(res.body.user.email).toBe(user1.email); + expect(res.body.firstName).toBe(user1.firstName); + expect(res.body.lastName).toBe(user1.lastName); + expect(res.body.email).toBe(user1.email); expect(res.body).not.toHaveProperty('password'); }); + test('Get user by orgId', async () => { const res = await request(app) .get('/users/' + orgid) @@ -117,6 +121,7 @@ describe('EXPRESS user routes', () => { expect(user.email).toBe(user1.email); expect(res.body).not.toHaveProperty('password'); }); + test('Successfully retrieve a user by token from the EXPRESS user route', async () => { const res = await request(app) .get('/users/' + orgid + '/me') @@ -127,12 +132,14 @@ describe('EXPRESS user routes', () => { expect(res.body.email).toBe(user1.email); expect(res.body).not.toHaveProperty('password'); }); + const user2: { [key: string]: any } = { firstName: 'Thor', lastName: 'Hansen', email: 'updatedtest@mail.com', password: 'Testå123Å4!!!!!', }; + test('Successfully update a user via the EXPRESS user route', async () => { const res = await request(app) .put('/users/' + orgid + '/' + expressId) @@ -144,6 +151,7 @@ describe('EXPRESS user routes', () => { expect(res.body.email).toBe(user2.email); expect(res.body).not.toHaveProperty('password'); }); + test('Successfully log in a user after password change via the EXPRESS user route', async () => { const res = await request(app) .post('/users/' + orgid + '/login') @@ -153,11 +161,12 @@ describe('EXPRESS user routes', () => { }) .set('Authorization', 'Bearer ' + expressToken); expect(res.statusCode).toBe(200); - expect(res.body.user.firstName).toBe(user2.firstName); - expect(res.body.user.lastName).toBe(user2.lastName); - expect(res.body.user.email).toBe(user2.email); + expect(res.body.firstName).toBe(user2.firstName); + expect(res.body.lastName).toBe(user2.lastName); + expect(res.body.email).toBe(user2.email); expect(res.body).not.toHaveProperty('password'); }); + test('Delete user', async () => { const res = await request(app) .delete('/users/' + orgid + '/' + expressId) @@ -205,8 +214,10 @@ describe('Test meant to fail', () => { }); expect(res.statusCode).toBe(400); }); + const userWithTokenPassword = 'Asd!!!asdD23123'; let userWithToken: User; + test('Fail to create a user with an existing email via the EXPRESS user route', async () => { const res1 = await request(app) .post('/users/' + orgId) @@ -225,9 +236,11 @@ describe('Test meant to fail', () => { email: 'asdfasdfasdf@hotmail.com', password: 'Asd!!!asdD23123', }); + expect(res1.statusCode).toBe(201); expect(res2.statusCode).toBe(400); }); + test('Fail to authenticate a user with an incorrect password via the EXPRESS user route', async () => { const res = await request(app) .post('/users/' + orgId + '/login') @@ -258,12 +271,14 @@ describe('Test meant to fail', () => { expect(res.statusCode).toBe(401); await deleteUser(userWithToken); }); + test('Fail to fetch user details by organization ID with an invalid token via the EXPRESS user route', async () => { const res = await request(app) .post('/users/' + orgId + '/me') .set('Authorization', 'Bearer ' + 'wrongToken'); - expect(res.statusCode).toBe(500); + expect(res.statusCode).toBe(404); }); + test('Fail to create a user with inconsistent repeat password via the EXPRESS user route', async () => { const res = await request(app) .post('/users/' + orgId) diff --git a/src/routes/events.ts b/src/routes/events.ts index 4e77c66..e14c27f 100644 --- a/src/routes/events.ts +++ b/src/routes/events.ts @@ -15,7 +15,9 @@ import { BaseError } from '../errorHandler/baseErrors'; const router = Router(); -// create new +/**********************/ +/** CREATE NEW EVENT **/ +/**********************/ router.post( '/:orgId/', celebrate({ @@ -41,7 +43,9 @@ router.post( }), ); -// get all +/**********************/ +/*** GET ALL EVENTS ***/ +/**********************/ router.get( '/:orgId/', asyncHandler(async (req: Request, res: Response) => { @@ -50,7 +54,9 @@ router.get( }), ); -//get by id +/**********************/ +/***** GET BY ID ******/ +/**********************/ router.get( '/:orgId/:id', asyncHandler(async (req: Request, res: Response) => { @@ -63,7 +69,9 @@ router.get( }), ); -//update +/**********************/ +/**** UPDATE EVENT ****/ +/**********************/ router.put( '/:orgId/:id', celebrate({ @@ -93,7 +101,9 @@ router.put( }), ); -// delete by id +/**********************/ +/**** DELETE EVENT ****/ +/**********************/ router.delete( '/:orgId/:id', auth, diff --git a/src/routes/users.ts b/src/routes/users.ts index a83b54e..5f96026 100644 --- a/src/routes/users.ts +++ b/src/routes/users.ts @@ -18,10 +18,10 @@ import { celebrate, Joi, Segments } from 'celebrate'; import { BaseError } from '../errorHandler/baseErrors'; const router = Router(); + /*******************/ /*** CREATE USER ***/ /*******************/ - router.post( '/:orgId/', celebrate({ @@ -60,10 +60,10 @@ router.post( res.status(201).json(user); }), ); + /******************/ /*** USER LOGIN ***/ /******************/ - router.post( `/:orgId/login`, celebrate({ @@ -77,18 +77,14 @@ router.post( }), }), asyncHandler(async (req: Request, res: Response) => { - const user: { user: User } = await userLogin( - req.body.email, - req.body.password, - req.params.orgId, - ); + const user: User = await userLogin(req.body.email, req.body.password, req.params.orgId); res.status(200).json(user); }), ); + /****************************/ /*** GET ALL USERS BY ORG ***/ /****************************/ - router.get( '/:orgId/', auth, @@ -97,6 +93,7 @@ router.get( res.json(users); }), ); + /****************************/ /*** GET USER BY TOKEN/ID ***/ /****************************/ @@ -105,14 +102,13 @@ router.get( auth, asyncHandler(async (req: CustomRequest, res: Response) => { const user: User = await getUserByToken(req.token as string); - res.json(user); }), ); + /**********************/ /*** GET USER BY ID ***/ /**********************/ - router.get( '/:orgId/:id', auth, @@ -121,10 +117,10 @@ router.get( res.json(user); }), ); + /**********************/ /**** UPDATE USER *****/ /**********************/ - router.put( '/:orgId/:id', auth, @@ -164,10 +160,10 @@ router.put( res.json(newUserInfo); }), ); + /**********************/ /**** DELETE USER *****/ /**********************/ - router.delete( '/:orgId/:id', auth, @@ -177,10 +173,10 @@ router.delete( res.status(204).end(); }), ); + /************************/ /**** FORGOT PASSWORD ***/ /************************/ - router.post( '/:orgId/forgot-password', celebrate({ @@ -193,4 +189,5 @@ router.post( res.status(200).json({ message: 'Email sent' }); }), ); + export default router;