Untitled
unknown
plain_text
2 years ago
27 kB
15
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