From d21442b3c1753e3f5228744f6fb3a64394398fc6 Mon Sep 17 00:00:00 2001 From: JamesNg Date: Wed, 4 Jun 2025 17:29:25 -0400 Subject: [PATCH 1/3] wrote unit tests for user model --- backend/models/user.model.test.js | 165 ++++++++++++++++++++++++++++++ 1 file changed, 165 insertions(+) create mode 100644 backend/models/user.model.test.js diff --git a/backend/models/user.model.test.js b/backend/models/user.model.test.js new file mode 100644 index 000000000..d227a662d --- /dev/null +++ b/backend/models/user.model.test.js @@ -0,0 +1,165 @@ +// import necessary modules +const mongoose = require('mongoose'); +const { User } = require('./user.model'); +// MongoDB Memory Server is used for testing purposes to avoid using a real database +const { MongoMemoryServer } = require('mongodb-memory-server'); + + +describe('Unit tests for User Model', () => { + let mongoServer; + // Set up in-memory MongoDB server before all tests + beforeAll(async () => { + mongoServer = await MongoMemoryServer.create(); + const uri = await mongoServer.getUri(); + await mongoose.connect(uri, { useNewUrlParser: true, useUnifiedTopology: true }); + }); + // Disconnect and stop the in-memory MongoDB server after all tests + afterAll(async () => { + await mongoose.disconnect(); + await mongoServer.stop(); + }); + // Clear all collections after each test + afterEach(async () => { + // Clean up all collections after each test + const collections = mongoose.connection.collections; + for (const key in collections) { + await collections[key].deleteMany({}); + } + }); + + describe('Serialization test', () => { + it('should return the correct serialized user object', async () => { + // Create mock user data + const userObj = { + _id: new mongoose.Types.ObjectId(), + name: { + firstName: 'mock', + lastName: 'user', + }, + email: 'mock.user@example.com', + accessLevel: 'user', + createdDate: new Date(), + currentRole: 'developer', + desiredRole: 'lead developer', + newMember: false, + currentJobTitle: 'Software Engineer', + desiredJobTitle: 'Senior Software Engineer', + skillsToMatch: ['Jest', 'Node.js'], + firstAttended: '2025-01-01', + attendanceReason: 'To learn and contribute', + githubHandle: 'mockuser', + projects: ['ProjectId1', 'ProjectId2'], + phone: '123-456-7890', + textingOk: true, + slackName: 'mockuser', + isHflaGithubMember: true, + githubPublic2FA: true, + availability: 'Weekdays', + managedProjects: ['Project1', 'Project2'], + isActive: true, + }; + + // Create a mock user instance + const mockUser = new User(userObj); + const serializedUser = mockUser.serialize(); + + // Test + expect(serializedUser).toEqual({ + id: mockUser._id, + name: { + firstName: mockUser.name.firstName, + lastName: mockUser.name.lastName, + }, + email: mockUser.email, + accessLevel: mockUser.accessLevel, + createdDate: mockUser.createdDate, + currentRole: mockUser.currentRole, + desiredRole: mockUser.desiredRole, + newMember: mockUser.newMember, + currentJobTitle: mockUser.currentRole, + desiredJobTitle: mockUser.desiredRole, + skillsToMatch: mockUser.skillsToMatch, + firstAttended: mockUser.firstAttended, + attendanceReason: mockUser.attendanceReason, + githubHandle: mockUser.githubHandle, + projects: mockUser.projects, + phone: mockUser.phone, + textingOk: mockUser.textingOk, + slackName: mockUser.slackName, + isHflaGithubMember: mockUser.isHflaGithubMember, + githubPublic2FA: mockUser.githubPublic2FA, + availability: mockUser.availability, + managedProjects: mockUser.managedProjects, + isActive: mockUser.isActive, + }); + }); + }); + + describe('Validation test', () => { + it('should fail validation check if user email is not unique', async () => { + // Create and save a mock user with a specific email + const mockUser1 = new User({ email: 'mockuser@example.com' }); + await mockUser1.save(); + + // Create another mock user with the same email + const mockUser2 = new User({ email: 'mockuser@example.com' }); + + // Attempt to validate the mock user 2 by checking for uniqueness in email + let error; + try { + await mockUser2.save(); + } catch (err) { + error = err; + } + + // Tests + expect(error).toBeDefined(); + expect(error.code).toBe(11000); + }); + + it('should fail validation check if accessLevel is invalid', async () => { + // Create a mock user with an invalid accessLevel + const mockuser = new User({ + accessLevel: 'projectleader', // not 'user', 'admin', or 'superadmin' + }); + + // Attempt to validate the mock user by checking for valid accessLevel + let error; + try { + await mockuser.save(); + } catch (err) { + error = err; + } + + // Tests + expect(error).toBeDefined(); + expect(error.errors.accessLevel).toBeDefined(); + }); + + it('should pass validation with valid user data', async () => { + // Create a mock user with valid data + const mockUser = new User({ + name: { + firstName: 'Valid', + lastName: 'User', + }, + email: 'mockuser@gmail.com', + accessLevel: 'user', + }); + + // Attempt to save the mock user + let error; + try { + await mockUser.save(); + } catch (err) { + error = err; + } + + // Tests + expect(error).toBeUndefined(); + expect(mockUser.email).toBe('mockuser@gmail.com'); + expect(mockUser.accessLevel).toBe('user'); + await expect(mockUser.validate()).resolves.toBeUndefined(); // async validation check + }); + }); +}); From e9024081927f83daa0d0c754462cab3b0e2de092 Mon Sep 17 00:00:00 2001 From: JamesNg Date: Tue, 17 Jun 2025 00:53:20 -0400 Subject: [PATCH 2/3] removed dependency of tests on mock mongoDb server, --- backend/models/user.model.test.js | 63 ++++++++++++------------------- 1 file changed, 25 insertions(+), 38 deletions(-) diff --git a/backend/models/user.model.test.js b/backend/models/user.model.test.js index d227a662d..8f38015c3 100644 --- a/backend/models/user.model.test.js +++ b/backend/models/user.model.test.js @@ -1,30 +1,11 @@ // import necessary modules const mongoose = require('mongoose'); const { User } = require('./user.model'); -// MongoDB Memory Server is used for testing purposes to avoid using a real database -const { MongoMemoryServer } = require('mongodb-memory-server'); - describe('Unit tests for User Model', () => { - let mongoServer; - // Set up in-memory MongoDB server before all tests - beforeAll(async () => { - mongoServer = await MongoMemoryServer.create(); - const uri = await mongoServer.getUri(); - await mongoose.connect(uri, { useNewUrlParser: true, useUnifiedTopology: true }); - }); - // Disconnect and stop the in-memory MongoDB server after all tests - afterAll(async () => { - await mongoose.disconnect(); - await mongoServer.stop(); - }); - // Clear all collections after each test - afterEach(async () => { - // Clean up all collections after each test - const collections = mongoose.connection.collections; - for (const key in collections) { - await collections[key].deleteMany({}); - } + // Clears all mocks after each test + afterEach(() => { + jest.restoreAllMocks(); }); describe('Serialization test', () => { @@ -97,24 +78,30 @@ describe('Unit tests for User Model', () => { describe('Validation test', () => { it('should fail validation check if user email is not unique', async () => { - // Create and save a mock user with a specific email - const mockUser1 = new User({ email: 'mockuser@example.com' }); - await mockUser1.save(); + const mockData = { email: 'mockUser@test.com' }; + // Mock findOne method + const findOneSpy = jest.spyOn(User, 'findOne').mockResolvedValue(mockData); + // Mock create method + const createSpy = jest.spyOn(User, 'create').mockResolvedValue(mockData); - // Create another mock user with the same email - const mockUser2 = new User({ email: 'mockuser@example.com' }); + // Create a function to simulate validation of User documents + // if User with email exists, throw an error. Else create a new User. + const createUser = async (email) => { + const existing = await User.findOne(email); + if (existing) throw new Error('Email already exists'); + return await User.create(email); + }; - // Attempt to validate the mock user 2 by checking for uniqueness in email - let error; - try { - await mockUser2.save(); - } catch (err) { - error = err; - } + const result = createUser(mockData); // Tests - expect(error).toBeDefined(); - expect(error.code).toBe(11000); + expect(findOneSpy).toHaveBeenCalledWith(mockData); + expect(findOneSpy).toHaveBeenCalledTimes(1); + // User.create should not have been called + expect(createSpy).toHaveBeenCalledTimes(0); + // Checks if unique property is set to true + expect(User.schema.paths.email.options.unique).toBe(true); + expect(result).rejects.toThrow('Email already exists'); }); it('should fail validation check if accessLevel is invalid', async () => { @@ -126,7 +113,7 @@ describe('Unit tests for User Model', () => { // Attempt to validate the mock user by checking for valid accessLevel let error; try { - await mockuser.save(); + await mockuser.validate(); } catch (err) { error = err; } @@ -150,7 +137,7 @@ describe('Unit tests for User Model', () => { // Attempt to save the mock user let error; try { - await mockUser.save(); + await mockUser.validate(); } catch (err) { error = err; } From 4467c1714e840d7888cbca9dfb1fc65b0363a6eb Mon Sep 17 00:00:00 2001 From: JamesNg Date: Mon, 14 Jul 2025 23:31:53 -0400 Subject: [PATCH 3/3] remove unnecessary test --- backend/models/user.model.test.js | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/backend/models/user.model.test.js b/backend/models/user.model.test.js index 8f38015c3..03d37f79e 100644 --- a/backend/models/user.model.test.js +++ b/backend/models/user.model.test.js @@ -77,33 +77,6 @@ describe('Unit tests for User Model', () => { }); describe('Validation test', () => { - it('should fail validation check if user email is not unique', async () => { - const mockData = { email: 'mockUser@test.com' }; - // Mock findOne method - const findOneSpy = jest.spyOn(User, 'findOne').mockResolvedValue(mockData); - // Mock create method - const createSpy = jest.spyOn(User, 'create').mockResolvedValue(mockData); - - // Create a function to simulate validation of User documents - // if User with email exists, throw an error. Else create a new User. - const createUser = async (email) => { - const existing = await User.findOne(email); - if (existing) throw new Error('Email already exists'); - return await User.create(email); - }; - - const result = createUser(mockData); - - // Tests - expect(findOneSpy).toHaveBeenCalledWith(mockData); - expect(findOneSpy).toHaveBeenCalledTimes(1); - // User.create should not have been called - expect(createSpy).toHaveBeenCalledTimes(0); - // Checks if unique property is set to true - expect(User.schema.paths.email.options.unique).toBe(true); - expect(result).rejects.toThrow('Email already exists'); - }); - it('should fail validation check if accessLevel is invalid', async () => { // Create a mock user with an invalid accessLevel const mockuser = new User({