diff --git a/backend/models/user.model.js b/backend/models/user.model.js index 99a64d1fa..1f753c666 100644 --- a/backend/models/user.model.js +++ b/backend/models/user.model.js @@ -1,4 +1,4 @@ -const mongoose = require("mongoose"); +const mongoose = require('mongoose'); // const bcrypt = require('bcrypt-nodejs'); mongoose.Promise = global.Promise; @@ -9,10 +9,10 @@ const userSchema = mongoose.Schema({ lastName: { type: String }, }, email: { type: String, unique: true, lowercase: true }, - accessLevel: { - type: String, - enum: ["user", "admin", "superadmin"], // restricts values to "user", "admin" and "superadmin" - default: "user" + accessLevel: { + type: String, + enum: ['user', 'admin', 'superadmin'], // restricts values to "user", "admin" and "superadmin" + default: 'user', }, createdDate: { type: Date, default: Date.now }, currentRole: { type: String }, // will remove but need to update check-in form @@ -23,11 +23,10 @@ const userSchema = mongoose.Schema({ skillsToMatch: [{ type: String }], // skills the user either has or wants to learn - will use to match to projects firstAttended: { type: String }, attendanceReason: { type: String }, - githubHandle: { type: String }, projects: [ { type: mongoose.Schema.Types.ObjectId, - ref: "Project", + ref: 'Project', }, ], githubHandle: { type: String }, // handle not including @, not the URL @@ -40,7 +39,7 @@ const userSchema = mongoose.Schema({ managedProjects: [{ type: String }], // Which projects managed by user. //currentProject: { type: String } // no longer need this as we can get it from Project Team Member table // password: { type: String, required: true } - isActive: { type: Boolean, default: true } + isActive: { type: Boolean, default: true }, }); userSchema.methods.serialize = function () { @@ -61,7 +60,6 @@ userSchema.methods.serialize = function () { skillsToMatch: this.skillsToMatch, firstAttended: this.firstAttended, attendanceReason: this.attendanceReason, - githubHandle: this.githubHandle, projects: this.projects, //currentProject: this.currentProject phone: this.phone, @@ -71,10 +69,10 @@ userSchema.methods.serialize = function () { githubPublic2FA: this.githubPublic2FA, availability: this.availability, managedProjects: this.managedProjects, - isActive: this.isActive + isActive: this.isActive, }; }; -const User = mongoose.model("User", userSchema); +const User = mongoose.model('User', userSchema); module.exports = { User }; diff --git a/backend/models/user.model.test.js b/backend/models/user.model.test.js index ed802e2e9..4a32e35be 100644 --- a/backend/models/user.model.test.js +++ b/backend/models/user.model.test.js @@ -28,7 +28,6 @@ describe('Unit tests for User Model', () => { skillsToMatch: ['Jest', 'Node.js'], firstAttended: '2025-01-01', attendanceReason: 'To learn and contribute', - githubHandle: 'mockuser', projects: ['ProjectId1', 'ProjectId2'], phone: '123-456-7890', textingOk: true, @@ -62,7 +61,6 @@ describe('Unit tests for User Model', () => { skillsToMatch: mockUser.skillsToMatch, firstAttended: mockUser.firstAttended, attendanceReason: mockUser.attendanceReason, - githubHandle: mockUser.githubHandle, projects: mockUser.projects, phone: mockUser.phone, textingOk: mockUser.textingOk, @@ -108,7 +106,6 @@ describe('Unit tests for User Model', () => { expect(mockUser.email).toBe(uppercaseEmail.toLowerCase()); }); - it('should pass validation with valid user data', async () => { // Create a mock user with valid data const mockUser = new User({ diff --git a/backend/models/user.test.js b/backend/models/user.test.js new file mode 100644 index 000000000..1ac16f083 --- /dev/null +++ b/backend/models/user.test.js @@ -0,0 +1,128 @@ +const mongoose = require('mongoose'); +const { User } = require('./user.model'); +const { setupIntegrationDB } = require('../setup-test'); + +setupIntegrationDB('user-model'); + +describe('User Model - Create and Read', () => { + test('Save a model instance and then read from the db', async () => { + const submittedData = { + name: { + firstName: 'Test', + lastName: 'User', + }, + email: 'test@test.com', + accessLevel: 'user', + createdDate: 1594023390039, + currentRole: 'mage', + desiredRole: 'warlock', + newMember: true, + currentJobTitle: 'freehand artist', + desiredJobTitle: 'textile factory worker', + skillsToMatch: ['marketing assistant'], + firstAttended: 'year 0', + attendanceReason: 'training', + phone: '867-5309', + textingOk: true, + slackName: 'slacktestuser', + }; + + await User.create(submittedData); + const savedData = await User.findOne({ email: submittedData.email }); + expect(savedData.name.firstName).toBe(submittedData.name.firstName); + expect(savedData.currentRole).toBe(submittedData.currentRole); + expect(savedData.desiredJobTitle).toBe(submittedData.desiredJobTitle); + }); + + test('Create a simple user', async () => { + const submittedData = { + name: { + firstName: 'Simple', + lastName: 'User', + }, + email: 'simple@test.com', + }; + + await User.create(submittedData); + const savedData = await User.findOne({ email: submittedData.email }); + expect(savedData.name.firstName).toBe(submittedData.name.firstName); + expect(savedData.email).toBe(submittedData.email); + }); +}); + +describe('User Model - Serialization', () => { + test('should serialize user data correctly', async () => { + const userData = { + name: { firstName: 'Serialize', lastName: 'Test' }, + email: 'serialize.test@example.com', + accessLevel: 'admin', + currentRole: 'Backend Developer', + desiredRole: 'Lead Developer', + newMember: false, + currentJobTitle: 'Actual Current Job Title', + desiredJobTitle: 'Actual Desired Job Title', + skillsToMatch: ['JavaScript', 'MongoDB'], + phone: '555-0101', + textingOk: true, + slackName: 'serializeslack', + isHflaGithubMember: true, + githubPublic2FA: false, + availability: 'Evenings', + managedProjects: ['ProjectGamma'], + isActive: true, + createdDate: new Date(2023, 0, 15), + }; + + const user = await User.create(userData); + const serializedUser = user.serialize(); + + expect(serializedUser.id.toString()).toBe(user._id.toString()); + expect(serializedUser.name.firstName).toBe(userData.name.firstName); + expect(serializedUser.name.lastName).toBe(userData.name.lastName); + expect(serializedUser.email).toBe(userData.email); + expect(serializedUser.accessLevel).toBe(userData.accessLevel); + expect(serializedUser.createdDate).toEqual(userData.createdDate); + expect(serializedUser.currentRole).toBe(userData.currentRole); + expect(serializedUser.desiredRole).toBe(userData.desiredRole); + expect(serializedUser.newMember).toBe(userData.newMember); + expect([...serializedUser.skillsToMatch]).toEqual(userData.skillsToMatch); + expect(serializedUser.phone).toBe(userData.phone); + expect(serializedUser.textingOk).toBe(userData.textingOk); + expect(serializedUser.slackName).toBe(userData.slackName); + expect(serializedUser.isHflaGithubMember).toBe(userData.isHflaGithubMember); + expect(serializedUser.githubPublic2FA).toBe(userData.githubPublic2FA); + expect(serializedUser.availability).toBe(userData.availability); + expect([...serializedUser.managedProjects]).toEqual(userData.managedProjects); + expect(serializedUser.isActive).toBe(userData.isActive); + }); +}); + +describe('User Model - Validation', () => { + test('should fail if email is not unique', async () => { + const email = 'unique.validation@example.com'; + await User.create({ + name: { firstName: 'First', lastName: 'User' }, + email: email, + accessLevel: 'user', + }); + + await expect( + User.create({ + name: { firstName: 'Second', lastName: 'User' }, + email: email, + accessLevel: 'user', + }), + ).rejects.toMatchObject({ code: 11000 }); + }); + + test('should fail if accessLevel is not in enum', async () => { + const userData = { + name: { firstName: 'Enum', lastName: 'Test' }, + email: 'enum.test@example.com', + accessLevel: 'invalid_access_level', + }; + + const user = new User(userData); + await expect(user.save()).rejects.toBeInstanceOf(mongoose.Error.ValidationError); + }); +});