From 15d543af7ae93a37f380fe5f4ebfe149cff5803a Mon Sep 17 00:00:00 2001 From: Ndevu12 Date: Mon, 6 May 2024 13:47:32 +0200 Subject: [PATCH] ft logout feature --- src/__test__/logout.test.ts | 74 +++++++++++++++++++++ src/controllers/authController.ts | 5 ++ src/routes/UserRoutes.ts | 2 + src/services/index.ts | 1 + src/services/userServices/logoutServices.ts | 18 +++++ 5 files changed, 100 insertions(+) create mode 100644 src/__test__/logout.test.ts create mode 100644 src/services/userServices/logoutServices.ts diff --git a/src/__test__/logout.test.ts b/src/__test__/logout.test.ts new file mode 100644 index 0000000..19cdf70 --- /dev/null +++ b/src/__test__/logout.test.ts @@ -0,0 +1,74 @@ +import request from 'supertest'; +import { app, server } from '../index'; +import { createConnection, getConnection, getConnectionOptions, getRepository } from 'typeorm'; +import { User } from '../entities/User'; + +beforeAll(async () => { + // Connect to the test database + const connectionOptions = await getConnectionOptions(); + await createConnection({ ...connectionOptions, name: 'testConnection' }); +}); + +afterAll(async () => { + await getConnection('testConnection').close(); + server.close(); +}); + +describe('POST /user/logout', () => { + it('should logout a user', async () => { + // sign up a user + const registerUser = { + firstName: 'Ndevu', + lastName: 'Elisa', + email: 'ndevukumurindi@gmail.com', + gender: 'male', + phoneNumber: '078907987443', + photoUrl: 'https://example.com/images/photo.jpg', + userType: 'vender', + verified: true, + status: 'active', + password: process.env.TEST_USER_LOGIN_PASS, + }; + + await request(app).post('/user/register').send(registerUser); + + const loginUser = { + email: registerUser.email, + password: process.env.TEST_USER_LOGIN_PASS, + }; + + const userRepository = getRepository(User); + const user = await userRepository.findOne({ where: { email: registerUser.email } }); + if (user) { + const verifyRes = await request(app).get(`/user/verify/${user.id}`); + + if (!verifyRes) throw new Error(`Test User verification failed for ${user.email}`); + + const loginResponse = await request(app).post('/user/login').send(loginUser); + const setCookie = loginResponse.headers['set-cookie']; + + if (!setCookie) { + throw new Error('No cookies set in login response'); + } + + const resp = await request(app).post('/user/logout').set('Cookie', setCookie); + expect(resp.status).toBe(200); + expect(resp.body).toEqual({ Message: 'Logged out successfully' }); + + // Clean up: delete the test user + await userRepository.remove(user); + } + }); + + it('should not logout a user who is not logged in or with no token', async () => { + const fakeEmail = 'ndevukkkk@gmail.com'; + const loginUser = { + email: fakeEmail, + password: process.env.TEST_USER_LOGIN_PASS, + }; + const token = ''; + const res = await request(app).post('/user/logout').send(loginUser).set('Cookie', token); + expect(res.status).toBe(400); + expect(res.body).toEqual({ Message: 'Access denied. You must be logged in' }); + }); +}); diff --git a/src/controllers/authController.ts b/src/controllers/authController.ts index 6495e28..037a50f 100644 --- a/src/controllers/authController.ts +++ b/src/controllers/authController.ts @@ -7,6 +7,7 @@ import { userDisableTwoFactorAuth, userValidateOTP, userResendOtpService, + logoutService, } from '../services'; export const userRegistration = async (req: Request, res: Response) => { @@ -36,3 +37,7 @@ export const verifyOTP = async (req: Request, res: Response) => { export const resendOTP = async (req: Request, res: Response) => { await userResendOtpService(req, res); }; + +export const logout = async (req: Request, res: Response) => { + await logoutService(req, res); +}; diff --git a/src/routes/UserRoutes.ts b/src/routes/UserRoutes.ts index c7154af..a1cab7b 100644 --- a/src/routes/UserRoutes.ts +++ b/src/routes/UserRoutes.ts @@ -7,6 +7,7 @@ import { disable2FA, verifyOTP, resendOTP, + logout, } from '../controllers/authController'; const router = Router(); @@ -14,6 +15,7 @@ const router = Router(); router.post('/register', userRegistration); router.get('/verify/:id', userVerification); router.post('/login', login); +router.post('/logout', logout); router.post('/enable-2fa', enable2FA); router.post('/disable-2fa', disable2FA); router.post('/verify-otp', verifyOTP); diff --git a/src/services/index.ts b/src/services/index.ts index ae1157c..7374ea7 100644 --- a/src/services/index.ts +++ b/src/services/index.ts @@ -6,3 +6,4 @@ export * from './userServices/userDisableTwoFactorAuth'; export * from './userServices/userValidateOTP'; export * from './userServices/userLoginService'; export * from './userServices/userResendOTP'; +export * from './userServices/logoutServices'; diff --git a/src/services/userServices/logoutServices.ts b/src/services/userServices/logoutServices.ts new file mode 100644 index 0000000..541c364 --- /dev/null +++ b/src/services/userServices/logoutServices.ts @@ -0,0 +1,18 @@ +import { Request, Response } from 'express'; + +// logout method +export const logoutService = async (req: Request, res: Response): Promise => { + try { + const token = req.cookies['token'] || null; + if (!token) { + res.status(400).json({ Message: 'Access denied. You must be logged in' }); + return; + } + + res.clearCookie('token'); + res.status(200).json({ Message: 'Logged out successfully' }); + } catch (error) { + console.error('Error logging out:', error); + res.status(500).json({ error: 'Sorry, Token required.' }); + } +};