-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #67 from atlp-rwanda/ft-logout
ft: implement user logout feature
- Loading branch information
Showing
17 changed files
with
334 additions
and
219 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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: '[email protected]', | ||
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 = '[email protected]'; | ||
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' }); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,11 +8,8 @@ beforeAll(async () => { | |
const connectionOptions = await getConnectionOptions(); | ||
|
||
await createConnection({ ...connectionOptions, name: 'testConnection' }); | ||
|
||
}); | ||
|
||
|
||
|
||
afterAll(async () => { | ||
const connection = getConnection('testConnection'); | ||
const userRepository = connection.getRepository(User); | ||
|
@@ -106,9 +103,8 @@ describe('POST /user/verify/:id', () => { | |
}); | ||
|
||
describe('Send password reset link', () => { | ||
|
||
it('Attempt to send email with rate limiting', async () => { | ||
const email = "[email protected]"; | ||
const email = '[email protected]'; | ||
|
||
const requests = Array.from({ length: 5 }, async () => { | ||
return await request(app).post(`/user/password/reset/link?email=${email}`); | ||
|
@@ -118,34 +114,33 @@ describe('Send password reset link', () => { | |
const lastResponse = responses[responses.length - 1]; | ||
expect(lastResponse.status).toBe(404); | ||
expect(lastResponse.body.message).toEqual('User not found'); | ||
}); | ||
}, 20000); | ||
|
||
it('Attempt to send email with invalid email template', async () => { | ||
const email = "[email protected]"; | ||
const email = '[email protected]'; | ||
|
||
const res = await request(app).post(`/user/password/reset/link?email=${email}`); | ||
|
||
expect(res.status).toBe(404); | ||
expect(res.body.message).toEqual('User not found'); | ||
}); | ||
}, 10000); | ||
|
||
it('Send email to a user with special characters in email address', async () => { | ||
const email = "[email protected]"; | ||
const email = '[email protected]'; | ||
|
||
const res = await request(app).post(`/user/password/reset/link?email=${encodeURIComponent(email)}`); | ||
|
||
expect(res.status).toBe(404); | ||
expect(res.body.message).toEqual('User not found'); | ||
}); | ||
|
||
}, 10000); | ||
}); | ||
describe('Password Reset Service', () => { | ||
it('Should reset password successfully', async () => { | ||
const data = { | ||
"newPassword": "user", | ||
"confirmPassword": "user", | ||
newPassword: 'user', | ||
confirmPassword: 'user', | ||
}; | ||
const email = "[email protected]"; | ||
const email = '[email protected]'; | ||
const userRepository = getRepository(User); | ||
const user = await userRepository.findOne({ where: { email: email } }); | ||
if (user) { | ||
|
@@ -158,22 +153,21 @@ describe('Password Reset Service', () => { | |
|
||
it('Should return 404 if user not found', async () => { | ||
const data = { | ||
"newPassword": "user", | ||
"confirmPassword": "user", | ||
newPassword: 'user', | ||
confirmPassword: 'user', | ||
}; | ||
const email = "[email protected]"; | ||
const userId = "nonexistentuserid"; | ||
const email = '[email protected]'; | ||
const userId = 'nonexistentuserid'; | ||
const res: any = await request(app).post(`/user/password/reset?userid=${userId}&email=${email}`).send(data); | ||
// Asser | ||
expect(res).toBeTruthy; | ||
|
||
}); | ||
|
||
it('Should return 204 if required fields are missing', async () => { | ||
const data = { | ||
// | ||
}; | ||
const email = "[email protected]"; | ||
const email = '[email protected]'; | ||
|
||
const userRepository = getRepository(User); | ||
const user = await userRepository.findOne({ where: { email: email } }); | ||
|
@@ -186,10 +180,10 @@ describe('Password Reset Service', () => { | |
|
||
it('Should return 204 if newPassword and confirmPassword do not match', async () => { | ||
const data = { | ||
"newPassword": "user123", | ||
"confirmPassword": "user456", | ||
newPassword: 'user123', | ||
confirmPassword: 'user456', | ||
}; | ||
const email = "[email protected]"; | ||
const email = '[email protected]'; | ||
|
||
const userRepository = getRepository(User); | ||
const user = await userRepository.findOne({ where: { email: email } }); | ||
|
@@ -200,4 +194,3 @@ describe('Password Reset Service', () => { | |
} | ||
}); | ||
}); | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -152,7 +152,8 @@ describe('start2FAProcess', () => { | |
|
||
it('should return 403 if OTP is expired', async () => { | ||
const email = '[email protected]'; | ||
const user = await getRepository(User).findOneBy({ email }); | ||
const userRepository = getRepository(User); | ||
const user = await userRepository.findOneBy({ email }); | ||
if (user) { | ||
user.twoFactorEnabled = true; | ||
user.twoFactorCode = '123456'; | ||
|
@@ -168,6 +169,9 @@ describe('start2FAProcess', () => { | |
const res = await request(app).post('/user/verify-otp').send(data); | ||
expect(res.status).toBe(403); | ||
expect(res.body).toEqual({ status: 'error', message: 'Authentication code expired' }); | ||
if (user) { | ||
await userRepository.remove(user); | ||
} | ||
}); | ||
|
||
it('should return 400 if not sent email in body on resending OTP', async () => { | ||
|
@@ -190,14 +194,29 @@ describe('start2FAProcess', () => { | |
}); | ||
|
||
it('should resend OTP', async () => { | ||
const newUser = { | ||
firstName: 'John', | ||
lastName: 'Doe', | ||
email: '[email protected]', | ||
password: 'password', | ||
gender: 'Male', | ||
phoneNumber: '0785044398', | ||
userType: 'Buyer', | ||
}; | ||
|
||
// Act | ||
const resp = await request(app).post('/user/register').send(newUser); | ||
if (!resp) { | ||
console.log('Error creating user in resend otp test case'); | ||
} | ||
const data = { | ||
email: 'john.doe1@example.com', | ||
email: 'john.doe187@example.com', | ||
}; | ||
|
||
const res = await request(app).post('/user/resend-otp').send(data); | ||
expect(res.status).toBe(200); | ||
expect(res.body).toEqual({ status: 'success', data: { message: 'OTP sent successfully' } }); | ||
}); | ||
}, 20000); | ||
|
||
it('should return 400 if not sent email in body on login', async () => { | ||
const data = {}; | ||
|
Oops, something went wrong.