Untitled
unknown
plain_text
a year ago
27 kB
13
Indexable
/* eslint-disable @typescript-eslint/no-unused-vars */ import { expect } from 'chai'; import { describe, it, beforeEach, afterEach, before } from 'mocha'; // eslint-disable-next-line @typescript-eslint/no-unused-vars import * as nodemailer from 'nodemailer'; import sinon from 'sinon'; import request from 'supertest'; import app from '../src/app'; // eslint-disable-next-line import/order import { UserController } from '../src/controllers/user.controller'; // eslint-disable-next-line import/order import UserModel from '../src/models/user.model'; const mockAccessToken = 'mockedAccessToken'; const mockRefreshToken = 'mockedRefreshToken'; const mockVerificationToken = 'mockedVerificationToken'; const mockAccessTokenC = 'mockedAccessToken'; const mockRefreshTokenC = 'mockedRefreshToken'; const mockVerificationTokenC = 'mockedVerificationToken'; import { UserService } from '../src/services/user.service'; // import { extractEmailFromPayload } from '../src/utils/authUtils'; import { ResponseHandler } from '../src/utils/handleResponse'; // Define mock users const mockUser1 = { _id: '60f6a1b5f3c1ac3dc0a0a8a0', email: 'test1@example.com', userType: 'customer', status: 'online', phoneNumber: '23-788-421', accessToken: mockAccessTokenC, refreshToken: mockRefreshTokenC, verificationToken: mockVerificationTokenC, }; const mockUser2 = { _id: '60f6a1b5f3c1ac3dc0a0a8a2', // Unique _id for the first admin user email: 'admin1@example.com', userType: 'admin', status: 'online', phoneNumber: '23-788-421', accessToken: mockAccessToken, refreshToken: mockRefreshToken, verificationToken: mockVerificationToken, }; const mockUser4 = { _id: '60f6a1b5f3c1ac3dc0a0a8a4', // Unique _id for the second admin user email: 'admin2@example.com', userType: 'admin', status: 'online', phoneNumber: '23-788-422', accessToken: mockAccessToken, refreshToken: mockRefreshToken, verificationToken: mockVerificationToken, }; const mockUser3 = { phoneNumber: '321-654-0987', userType: 'customer', }; const mockUser = { _id: '60f6a1b5f3c1ac3dc0a0a8a5', // Unique _id for the second admin user email: 'verify_email@test.com', userType: 'customer', }; // Will Be used for login //Service //Controller & Service describe('User Tests', () => { beforeEach(async () => { // Clear the database before each test await UserModel.deleteMany({}); }); afterEach(() => { sinon.restore(); }); describe('POST /users/addUser', () => { it('should create a new user admin', async () => { const res = await request(app).post('/users/addUser').send({ _id: mockUser2._id, email: mockUser2.email, userType: mockUser2.userType, }); expect(res.status).to.equal(201); expect(res.body).to.have.property('data'); }); it('should create a new user customer', async () => { const res = await request(app).post('/users/addUser').send({ email: mockUser1.email, userType: mockUser1.userType, }); expect(res.status).to.equal(201); expect(res.body).to.have.property('data'); }); it('should return an error for duplicate email', async () => { // Create the first user await UserModel.create(mockUser1); // Try to create a user with the same email const res = await request(app).post('/users/addUser').send({ email: mockUser1.email, userType: 'customer' }); expect(res.status).to.equal(400); }); it('should create a new user with only phoneNumber', async () => { const res = await request(app).post('/users/addUser').send({ phoneNumber: mockUser3.phoneNumber, }); expect(res.status).to.equal(201); expect(res.body).to.have.property('data'); }); it('should return an error for duplicate phoneNumber', async () => { // Create the first user with mockUser3's phoneNumber await UserModel.create(mockUser3); // Try to create another user with the same phoneNumber as mockUser3 const res = await request(app).post('/users/addUser').send({ phoneNumber: mockUser3.phoneNumber }); expect(res.status).to.equal(400); // Assuming 409 for conflict/error // Add additional assertions here based on your API's error response structure }); it('should return an error if neither email nor phoneNumber is provided', async () => { const res = await request(app).post('/users/addUser').send({}); expect(res.status).to.equal(500); // Expecting 500 Internal Server Error expect(res.text).to.equal('{"error":"Either email or phoneNumber must be provided."}'); }); }); describe('GET /users/:id', () => { it('should retrieve a user by ID', async () => { // Create a user in the database const createdUser = await UserModel.create(mockUser2); const response = await request(app).get(`/users/${createdUser._id}`); expect(response.status).to.equal(200); // The expected data should match mockUser2 expect(response.body.data).to.deep.equal({ _id: mockUser2._id, email: mockUser2.email, }); }); it('should handle user not found', async () => { const response = await request(app).get('/users/60f6a1b5f3c1ac3dc0a0a8a1'); expect(response.status).to.equal(404); }); }); describe('POST /users/loginUltimate', () => { it('should log in an existing user with email', async () => { // Create a user in the database await UserModel.create(mockUser2); const res = await request(app).post('/users/loginUltimate').send({ email: mockUser2.email, }); expect(res.status).to.equal(200); // Add assertions for cookies if needed }); it('should register and send verification email to a new user', async () => { const sendVerificationEmailStub = sinon.stub(UserController.sendVerificationEmail).resolves({ status: 201 }); const res = await request(app).post('/users/loginUltimate').send({ email: mockUser1.email, }); expect(res.status).to.equal(201); expect(sendVerificationEmailStub.calledOnce).to.be.false; // Add assertions for cookies if needed }); it('should handle errors during login', async () => { sinon.stub(UserModel, 'findOne').throws(new Error('Some error occurred')); const res = await request(app).post('/users/loginUltimate').send({ email: 'nonexistent@example.com', }); expect(res.status).to.equal(400); }); }); describe('POST /users/logout', () => { it('should log out an existing user and clear cookies', async () => { await UserModel.create({ ...mockUser1, status: 'online' }); const res = await request(app).post('/users/logout').send({ email: mockUser1.email }); expect(res.status).to.equal(200); expect(res.body.message).to.equal('Logout successful.'); // Assertions for cleared cookies const cookies = res.headers['set-cookie']; expect(cookies).to.be.an('array'); cookies.forEach((cookie) => { expect(cookie).to.match(/^(accessToken=;|refreshToken=;|verificationToken=;)/); }); }); it('should return an error if the user is not found', async () => { // Ensure no user with this email exists await UserModel.deleteMany({ email: 'nonexistent@example.com' }); // Attempt to log out a user who does not exist const res = await request(app).post('/users/logout').send({ email: 'nonexistent@example.com' }); // Check for a 401 Unauthorized response expect(res.status).to.equal(401); // Confirm the text contains the expected error message as a string expect(res.text).to.equal('{"error":"User not found. Maybe already logged out or invalid email."}'); }); it('should return an error if the user is already logged out', async () => { // Ensure a user with this email exists and is 'offline' await UserModel.create({ ...mockUser1, status: 'offline' }); // Attempt to log out a user who is already 'offline' const res = await request(app).post('/users/logout').send({ email: mockUser1.email }); // Check for a 401 Unauthorized response expect(res.status).to.equal(401); // Confirm the text contains the expected error message as a string expect(res.text.trim()).to.equal(`{"error":"${mockUser1.email} - You are already logged out."}`); }); //an error during logout let saveStub; beforeEach(() => { // Stub the save method before each test saveStub = sinon.stub(UserModel.prototype, 'save'); }); afterEach(() => { // Restore the stubbed method after each test sinon.restore(); }); describe('ResponseHandler.success method', () => { it('should return a successful response with the correct structure', () => { // Create a mock response object const res = { status: sinon.stub().returnsThis(), // Stub the status method to return 'this' json: sinon.stub(), // Stub the json method }; // Call the success method of ResponseHandler ResponseHandler.success({ res, responseBody: { data: { email: 'test@example.com' }, message: 'Email extracted successfully' }, }); // Assert that the status method was called with 200 expect(res.status.calledWith(200)).to.be.true; // Assert that the json method was called with the correct response body expect( res.json.calledWith({ data: { email: 'test@example.com' }, message: 'Email extracted successfully', }), ).to.be.true; }); }); it('should handle an internal server error during logout', async () => { // Create a mock user with 'online' status await UserModel.create({ ...mockUser1, status: 'online' }); // Simulate a save error saveStub.throws(new Error('An error occurred during logout.')); // Attempt to log out the user const res = await request(app).post('/users/logout').send({ email: mockUser1.email }); // Check for a 500 Internal Server Error response expect(res.status).to.equal(500); // Confirm the response contains the expected error message // If the response is JSON with an 'error' property: expect(res.body.error).to.equal('An error occurred during logout.'); // If the response is a plain text: // expect(res.text).to.equal('"An error occurred during logout."'); }); }); describe('convertPermissions', () => { const userController = new UserController(); it('should handle an empty permissions object', () => { const userTypePermissions = {}; const expectedOutput = {}; expect(userController.convertPermissions(userTypePermissions)).to.deep.equal(expectedOutput); }); it('should handle a single category of permissions', () => { const userTypePermissions = { category1: { read: true, write: false }, }; const expectedOutput = { category1: { read: true, write: false }, }; expect(userController.convertPermissions(userTypePermissions)).to.deep.equal(expectedOutput); }); it('should handle multiple categories of permissions', () => { const userTypePermissions = { category1: { read: true, write: false }, category2: { edit: true, delete: false }, }; const expectedOutput = { category1: { read: true, write: false }, category2: { edit: true, delete: false }, }; expect(userController.convertPermissions(userTypePermissions)).to.deep.equal(expectedOutput); }); }); describe('convertPermissions', () => { const userService = new UserService(); it('should handle an empty permissions object', () => { const userTypePermissions = {}; const expectedOutput = {}; expect(userService.convertPermissions(userTypePermissions)).to.deep.equal(expectedOutput); }); it('should handle a single category of permissions', () => { const userTypePermissions = { category1: { read: true, write: false }, }; const expectedOutput = { category1: { read: true, write: false }, }; expect(userService.convertPermissions(userTypePermissions)).to.deep.equal(expectedOutput); }); it('should handle multiple categories of permissions', () => { const userTypePermissions = { category1: { read: true, write: false }, category2: { edit: true, delete: false }, }; const expectedOutput = { category1: { read: true, write: false }, category2: { edit: true, delete: false }, }; expect(userService.convertPermissions(userTypePermissions)).to.deep.equal(expectedOutput); }); }); describe('GET /users', () => { let userServiceStub; beforeEach(() => { // This stubs the UserService's getAllUsers method userServiceStub = sinon.stub(UserService.prototype, 'getAllUsers'); }); afterEach(() => { sinon.restore(); }); it('should return an error if user is not authenticated', async () => { const res = await request(app).get('/users/'); expect(res.status).to.equal(401); expect(res.body.message).to.equal('Authorization token is required'); }); it('should retrieve all users when the admin user is logged in', async () => { await UserModel.create(mockUser2); const loginResponse = await request(app).post('/users/loginUltimate').send({ email: mockUser2.email }); expect(loginResponse.status).to.equal(200); expect(loginResponse.headers).to.have.property('set-cookie'); const cookies = loginResponse.headers['set-cookie']; const accessTokenCookie = cookies.find((cookie) => cookie.startsWith('accessToken')); expect(accessTokenCookie).to.exist; const res = await request(app).get('/users').set('Cookie', accessTokenCookie); expect(res.status).to.equal(200); }); it('should return an error if no users are found', async () => { userServiceStub.resolves([]); // Simulate an empty user list const res = await request(app).get('/users'); // Adjust this if your route is different expect(res.status).to.equal(401); // Or whatever your logic is for no users found expect(res.body.error).to.equal(undefined); }); }); describe('POST /users/get-email-from-token', () => { let getEmailFromTokenStub; const userController = new UserController(); beforeEach(() => { getEmailFromTokenStub = sinon.stub(userController, 'getEmailFromToken'); // Stub ResponseHandler.internalServerError sinon.stub(ResponseHandler, 'internalServerError'); }); afterEach(() => { sinon.restore(); }); it('getEmailFromToken function should return email from a valid token', async () => { userController.getEmailFromToken; }); it('getEmailFromToken function should handle invalid token', async () => { // Stub extractEmailFromPayload to return null for invalid token const invalidToken = 'invalidToken'; getEmailFromTokenStub.returns(null); const response = await request(app).post('/users/get-email-from-token').send({ token: invalidToken }); expect(response.status).to.equal(400); // Expecting 400 for invalid token }); it('getEmailFromToken function should handle missing token', async () => { // Do not provide a token getEmailFromTokenStub.returns(null); const response = await request(app).post('/users/get-email-from-token').send({}); expect(response.status).to.equal(400); // Expecting 400 for missing token }); it('should successfully return an email and invoke ResponseHandler.success', async () => { // Set up a mock response object const res = { status: sinon.stub().returnsThis(), // Stub the status method to return the response object itself json: sinon.stub(), // Stub the json method }; // Call the success method of ResponseHandler ResponseHandler.success({ res, responseBody: { data: { email: 'test@example.com' }, message: 'Email extracted successfully' }, }); // Assert that the status method was called with 200 expect(res.status.calledWith(200)).to.be.true; // Additionally, assert that the json method was called with the correct body expect( res.json.calledWith({ data: { email: 'test@example.com' }, message: 'Email extracted successfully', }), ).to.be.true; }); it('should handle exceptions with ResponseHandler.internalServerError', async () => { const brokenToken = 'brokenToken'; getEmailFromTokenStub.withArgs(brokenToken).throws(new Error('Test error')); const response = await request(app).post('/users/get-email-from-token').send({ token: brokenToken }); expect(response.status).to.equal(400); // Internal Server Error // Adjust this line based on the actual error response format of your application const errorMessage = response.body.error || response.body.message || JSON.stringify(response.body); expect(errorMessage).to.include('Invalid token or email not found'); }); }); describe('GET /users/verify-email/:verificationToken', () => { beforeEach(async () => { // Clear the database before each test await UserModel.deleteMany({}); // Create and log in an admin user before each test const admin = await UserModel.create(mockUser2); // Assuming mockUser2 is an admin await request(app).post('/users/loginUltimate').send({ email: admin.email, // Add other necessary login fields if required }); }); afterEach(() => { sinon.restore(); }); it('should verify email successfully with valid and unexpired verification token', async () => { // Retrieve the logged-in user to get the verification token const loggedInUser = await UserModel.findOne({ email: mockUser2.email }); // Make the request to verify the email with the verification token from the logged-in user const res = await request(app).get(`/users/verify-email/${loggedInUser.verificationToken}`); // Assert that the email verification was successful expect(res.status).to.equal(200); expect(res.body.message).to.equal('Email verification successful. You can now log in.'); // Ensure that the user's verification status is updated in the database const updatedUser = await UserModel.findById(loggedInUser._id); expect(updatedUser.verificationToken).to.be.undefined; }); it('should handle expired verification token', async () => { // Retrieve the logged-in user to get the verification token const loggedInUser = await UserModel.findOne({ email: mockUser2.email }); // Simulate an expired verification token by setting it to an old value loggedInUser.verificationToken = 'expiredVerificationToken'; await loggedInUser.save(); // Make the request with an expired verification token const res = await request(app).get('/users/verify-email/expiredVerificationToken'); // Assert that the response indicates the token has expired expect(res.status).to.equal(500); expect(res.body.error).to.equal('Verification token has been expired redirect to login.'); }); it('should handle user not found with verification token', async () => { // Make the request with a non-existent verification token const res = await request(app).get('/users/verify-email/nonExistentVerificationToken'); // Assert that the response indicates the user was not found with the verification token expect(res.status).to.equal(404); expect(res.body.error).to.equal('User not found with this verification token.'); }); it('should handle internal server error', async () => { // Stub the UserModel.findOne method to throw an error, simulating an internal server error sinon.stub(UserModel, 'findOne').throws(new Error('Internal server error')); // Simulate a request to verify-email endpoint const res = await request(app).get(`/users/verify-email/${mockUser.verificationToken}`); // Assert that the response indicates an internal server error expect(res.status).to.equal(500); expect(res.body.error).to.equal('Verification token has been expired redirect to login.'); }); }); describe('POST /users/toggleBanStatus/:userId', () => { let accessToken, adminUser, normalUser; beforeEach(async () => { normalUser = await UserModel.create(mockUser1); // Assuming mockUser1 is a normal user // Create and log in as an admin user adminUser = await UserModel.create(mockUser2); // Assuming mockUser2 is an admin const loginResponse = await request(app).post('/users/loginUltimate').send({ email: adminUser.email, }); const cookies = loginResponse.headers['set-cookie']; accessToken = cookies.find((cookie) => cookie.startsWith('accessToken')).split(';')[0]; }); it('should handle route with userId parameter', async () => { const userId = normalUser._id; // Or any valid userId const response = await request(app) .post(`/users/toggleBanStatus/${userId}`) .set('Cookie', accessToken) .send({ banDuration: 30, banReason: 'Violation' }); expect(response.status).to.equal(200); // Check for successful response status // Other assertions based on your controller's functionality }); it('should return unauthorized error when no token provided', async () => { const response = await request(app) .post(`/users/toggleBanStatus/${normalUser._id}`) .send({ banDuration: 30, banReason: 'Violation' }); expect(response.status).to.equal(401); expect(response.body.error).to.equal('Authorization token is required.'); // Expect specific error message }); it('should handle invalid token or unable to extract email', async () => { const invalidToken = 'invalidToken'; const userId = normalUser._id; const response = await request(app) .post(`/users/toggleBanStatus/${userId}`) .set('Cookie', `accessToken=${invalidToken}`) .send({ banDuration: 30, banReason: 'Violation' }); expect(response.status).to.equal(401); expect(response.body.error).to.equal('Invalid token or unable to extract email.'); }); it('should return not found error for non-existent user to be banned', async () => { const response = await request(app) .post('/users/toggleBanStatus/60f6a1b5f3c1ac3dc0a0a800') .set('Cookie', accessToken) .send({ banDuration: 30, banReason: 'Violation' }); expect(response.status).to.equal(404); // Not found response expect(response.body.error).to.equal('User not found.'); // Expect specific error message for not found user }); it('should return not found error if user performing the ban is not found', async () => { // Mock the absence of the user performing the ban sinon.stub(UserModel, 'findOne').resolves(null); // Make a request to toggle ban status const response = await request(app) .post('/users/toggleBanStatus/nonExistentUserId') // Assuming nonExistentUserId doesn't exist .set('Cookie', accessToken) .send({ banDuration: 30, banReason: 'Violation' }); // Assert response status code expect(response.status).to.equal(404); // Assert response body contains the expected error message expect(response.body.error).to.equal('User performing the ban not found.'); }); afterEach(() => { sinon.restore(); }); }); describe('deleteUser', () => { afterEach(() => { sinon.restore(); }); it('should delete a user successfully', async () => { const userId = '123456789012345678901234'; const findByIdAndDeleteStub = sinon.stub(UserModel, 'findByIdAndDelete').resolves(); const userService = new UserService(); await userService.deleteUser(userId); expect(findByIdAndDeleteStub.calledOnceWithExactly(userId)).to.be.true; }); it('should throw an error when UserModel.findByIdAndDelete fails', async () => { const userId = '123456789012345678901234'; // eslint-disable-next-line @typescript-eslint/no-unused-vars const findByIdAndDeleteStub = sinon .stub(UserModel, 'findByIdAndDelete') .rejects(new Error('Some error occurred')); const userService = new UserService(); try { await userService.deleteUser(userId); expect.fail('Expected an error to be thrown'); } catch (error) { expect(error.message).to.equal('Some error occurred'); } }); }); describe('updateUser', () => { it('should update a user successfully', async () => { // Mock updated user data const updatedUserData = { name: 'Updated Name' }; // Stub the findByIdAndUpdate method of UserModel const findByIdAndUpdateStub = sinon.stub(UserModel, 'findByIdAndUpdate').resolves({ _id: 'mockUserId', name: 'Updated Name', }); // Create a new instance of UserService const userService = new UserService(); // Call the updateUser method with a mock userId and updatedUserData const updatedUser = await userService.updateUser('mockUserId', updatedUserData); // Expect findByIdAndUpdate method to have been called with the correct userId and updatedUserData expect(findByIdAndUpdateStub.calledOnceWithExactly('mockUserId', updatedUserData, { new: true })).to.be.true; // Expect the updated user to have the correct data expect(updatedUser).to.deep.equal({ _id: 'mockUserId', name: 'Updated Name', }); // Restore the stub findByIdAndUpdateStub.restore(); }); }); });
Editor is loading...
Leave a Comment