diff --git a/backend/models/user.model.js b/backend/models/user.model.js index 4c2005cc6..c8efb0c89 100644 --- a/backend/models/user.model.js +++ b/backend/models/user.model.js @@ -23,7 +23,6 @@ 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, diff --git a/backend/models/user.test.js b/backend/models/user.test.js new file mode 100644 index 000000000..bef82cb76 --- /dev/null +++ b/backend/models/user.test.js @@ -0,0 +1,161 @@ +const mongoose = require('mongoose'); +const { User } = require('./user.model'); +const { setupDB } = require("../setup-test"); + +setupDB("user-model"); + +// Please add and expand on this simple test. +describe("User Model - Create and Read", () => { + test('Save a model instance and then read from the db', async (done) => { + 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', + githubHandle: '@testuser', + phone: '867-5309', + textingOk: true, + slackName: 'slacktestuser', + }; + + await User.create(submittedData); + const savedDataArray = await User.find(); + const savedData = savedDataArray[0]; + expect(savedData.name.firstName).toBe(submittedData.name.firstName); + expect(savedData.currentRole).toBe(submittedData.currentRole); + expect(savedData.desiredJobTitle).toBe(submittedData.desiredJobTitle); + done(); + }); + + test('Create a simple user', async (done) => { + // Test Data + const submittedData = { + name: { + firstName: 'test', + lastName: 'user', + }, + email: 'newtest@test.com', + }; + + await User.create(submittedData); + const savedDataArray = await User.find(); + const savedData = savedDataArray[0]; + expect(savedData.name.firstName).toBe(submittedData.name.firstName); + expect(savedData.currentRole).toBe(submittedData.currentRole); + expect(savedData.desiredJobTitle).toBe(submittedData.desiredJobTitle); + done(); + }); +}); + +describe("User Model - Serialization", () => { + test('should serialize user data correctly', async (done) => { + 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', // This value is stored in DB + desiredJobTitle: 'Actual Desired Job Title', // This value is stored in DB + skillsToMatch: ['JavaScript', 'MongoDB'], + githubHandle: 'serializeTestGH', + phone: '555-0101', + textingOk: true, + slackName: 'serializeslack', + isHflaGithubMember: true, + githubPublic2FA: false, + availability: 'Evenings', + managedProjects: ['ProjectGamma'], + isActive: true, + createdDate: new Date(2023, 0, 15) // Example date + }; + + const user = await User.create(userData); + const serializedUser = user.serialize(); + + expect(serializedUser.id).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); + + // Note: Serialized job titles are mapped from roles as per current serialize method + expect(serializedUser.currentJobTitle).toBe(userData.currentRole); + expect(serializedUser.desiredJobTitle).toBe(userData.desiredRole); + + expect(serializedUser.skillsToMatch).toEqual(userData.skillsToMatch); + expect(serializedUser.githubHandle).toBe(userData.githubHandle); + 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); + + // Ensure fields that shouldn't be there are absent (e.g., password if it existed) + expect(serializedUser.password).toBeUndefined(); + + done(); + }); +}); + +describe("User Model - Validation", () => { + test('should fail if email is not unique', async (done) => { + const email = 'unique.validation@example.com'; + await User.create({ + name: { firstName: 'First', lastName: 'User' }, + email: email, + accessLevel: 'user', + }); + + try { + await User.create({ + name: { firstName: 'Second', lastName: 'User' }, + email: email, // Same email + accessLevel: 'user', + }); + // If create doesn't throw, the test should fail + done.fail('Should have thrown a duplicate key error for email.'); + } catch (error) { + expect(error.code).toBe(11000); // MongoDB duplicate key error code + done(); + } + }); + + test('should fail if accessLevel is not in enum', async (done) => { + const userData = { + name: { firstName: 'Enum', lastName: 'Test' }, + email: 'enum.test@example.com', + accessLevel: 'invalid_access_level', // Not in ["user", "admin", "superadmin"] + }; + + try { + const user = new User(userData); + await user.save(); + done.fail('Should have thrown a validation error for accessLevel.'); + } catch (error) { + expect(error).toBeInstanceOf(mongoose.Error.ValidationError); + expect(error.errors.accessLevel).toBeDefined(); + expect(error.errors.accessLevel.kind).toBe('enum'); + done(); + } + }); +}); diff --git a/backend/yarn.lock b/backend/yarn.lock index 26b84d334..8b8bd2977 100644 --- a/backend/yarn.lock +++ b/backend/yarn.lock @@ -770,15 +770,6 @@ "@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/sourcemap-codec" "^1.4.14" -"@shelf/jest-mongodb@^1.2.3": - version "1.2.3" - resolved "https://registry.yarnpkg.com/@shelf/jest-mongodb/-/jest-mongodb-1.2.3.tgz#7cb34f0bcb71871b0d1c8d16a4f1fdb18b1620df" - integrity sha512-RGECov7b9anpHqrEoegYeZFWN3WEOw/3hPu3fQUi4gnNIGH0jyMVCQd4DgB37n2aoEWFfe7Kq59aQUrgIQRITA== - dependencies: - debug "4.1.1" - mongodb-memory-server "6.6.7" - uuid "8.3.0" - "@sindresorhus/is@^0.14.0": version "0.14.0" resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" @@ -913,23 +904,6 @@ dependencies: "@types/node" "*" -"@types/cross-spawn@^6.0.2": - version "6.0.2" - resolved "https://registry.yarnpkg.com/@types/cross-spawn/-/cross-spawn-6.0.2.tgz#168309de311cd30a2b8ae720de6475c2fbf33ac7" - integrity sha512-KuwNhp3eza+Rhu8IFI5HUXRP0LIhqH5cAjubUvGXXthh4YYBuP2ntwEX+Cz8GJoZUHlKo247wPWOfA9LYEq4cw== - dependencies: - "@types/node" "*" - -"@types/debug@^4.1.5": - version "4.1.5" - resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.5.tgz#b14efa8852b7768d898906613c23f688713e02cd" - integrity sha512-Q1y515GcOdTHgagaVFhHnIFQ38ygs/kmxdNpvpou+raI9UO3YZcHDngBSYKQklcKlvA7iuQlmIKbzvmxcOE9CQ== - -"@types/dedent@^0.7.0": - version "0.7.0" - resolved "https://registry.yarnpkg.com/@types/dedent/-/dedent-0.7.0.tgz#155f339ca404e6dd90b9ce46a3f78fd69ca9b050" - integrity sha512-EGlKlgMhnLt/cM4DbUSafFdrkeJoC9Mvnj0PUCU7tFmTjMjNRT957kXCx0wYm3JuEq4o4ZsS5vG+NlkM2DMd2A== - "@types/express-serve-static-core@*": version "4.17.13" resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.13.tgz#d9af025e925fc8b089be37423b8d1eac781be084" @@ -949,18 +923,6 @@ "@types/qs" "*" "@types/serve-static" "*" -"@types/find-cache-dir@^3.2.0": - version "3.2.0" - resolved "https://registry.yarnpkg.com/@types/find-cache-dir/-/find-cache-dir-3.2.0.tgz#eaaf331699dccf52c47926e4d4f8f3ed8db33f3c" - integrity sha512-+JeT9qb2Jwzw72WdjU+TSvD5O1QRPWCeRpDJV+guiIq+2hwR0DFGw+nZNbTFjMIVe6Bf4GgAKeB/6Ytx6+MbeQ== - -"@types/find-package-json@^1.1.1": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@types/find-package-json/-/find-package-json-1.1.1.tgz#c0d296ac74fe3309ed0fe75a9c3edb42a776d30c" - integrity sha512-XMCocYkg6VUpkbOQMKa3M5cgc3MvU/LJKQwd3VUJrWZbLr2ARUggupsCAF8DxjEEIuSO6HlnH+vl+XV4bgVeEQ== - dependencies: - "@types/node" "*" - "@types/graceful-fs@^4.1.2": version "4.1.3" resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.3.tgz#039af35fe26bec35003e8d86d2ee9c586354348f" @@ -1006,16 +968,6 @@ dependencies: "@types/node" "*" -"@types/lockfile@^1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@types/lockfile/-/lockfile-1.0.1.tgz#434a3455e89843312f01976e010c60f1bcbd56f7" - integrity sha512-65WZedEm4AnOsBDdsapJJG42MhROu3n4aSSiu87JXF/pSdlubxZxp3S1yz3kTfkJ2KBPud4CpjoHVAptOm9Zmw== - -"@types/md5-file@^4.0.2": - version "4.0.2" - resolved "https://registry.yarnpkg.com/@types/md5-file/-/md5-file-4.0.2.tgz#c7241e88f4aa17218c774befb0fc34f33f21fe36" - integrity sha512-8gacRfEqLrmZ6KofpFfxyjsm/LYepeWUWUJGaf5A9W9J5B2/dRZMdkDqFDL6YDa9IweH12IO76jO7mpsK2B3wg== - "@types/mime@*": version "2.0.3" resolved "https://registry.yarnpkg.com/@types/mime/-/mime-2.0.3.tgz#c893b73721db73699943bfc3653b1deb7faa4a3a" @@ -1026,13 +978,6 @@ resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA== -"@types/mkdirp@^1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@types/mkdirp/-/mkdirp-1.0.1.tgz#0930b948914a78587de35458b86c907b6e98bbf6" - integrity sha512-HkGSK7CGAXncr8Qn/0VqNtExEE+PHMWb+qlR1faHMao7ng6P3tAaoWWBMdva0gL5h4zprjIO89GJOLXsMcDm1Q== - dependencies: - "@types/node" "*" - "@types/node@*", "@types/node@>=10", "@types/node@>=6.0.0", "@types/node@>=8.9.0": version "14.11.8" resolved "https://registry.yarnpkg.com/@types/node/-/node-14.11.8.tgz#fe2012f2355e4ce08bca44aeb3abbb21cf88d33f" @@ -1073,11 +1018,6 @@ resolved "https://registry.yarnpkg.com/@types/retry/-/retry-0.12.0.tgz#2b35eccfcee7d38cd72ad99232fbd58bffb3c84d" integrity sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA== -"@types/semver@^7.3.3": - version "7.3.4" - resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.4.tgz#43d7168fec6fa0988bb1a513a697b29296721afb" - integrity sha512-+nVsLKlcUCeMzD2ufHEYuJ9a2ovstb6Dp52A5VsoKxDXgvE051XgHI/33I1EymwkRGQkwnA0LkhnUzituGs4EQ== - "@types/serve-static@*": version "1.13.5" resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.5.tgz#3d25d941a18415d3ab092def846e135a08bbcf53" @@ -1096,11 +1036,6 @@ resolved "https://registry.yarnpkg.com/@types/tmp/-/tmp-0.2.0.tgz#e3f52b4d7397eaa9193592ef3fdd44dc0af4298c" integrity sha512-flgpHJjntpBAdJD43ShRosQvNC0ME97DCfGvZEDlAThQmnerRXrLbX6YgzRBQCZTthET9eAWFAMaYP0m0Y4HzQ== -"@types/uuid@^8.0.0": - version "8.3.0" - resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.0.tgz#215c231dff736d5ba92410e6d602050cce7e273f" - integrity sha512-eQ9qFW/fhfGJF8WKHGEHZEyVWfZxrT+6CLIJGBcZPfxUh/+BnEj+UCGYMlr9qZuX/2AltsvwrGqp0LhEW8D0zQ== - "@types/yargs-parser@*": version "15.0.0" resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-15.0.0.tgz#cb3f9f741869e20cce330ffbeb9271590483882d" @@ -2101,13 +2036,6 @@ debug@4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.2.0, debug@^4.3.1: dependencies: ms "2.1.2" -debug@4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" - integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== - dependencies: - ms "^2.1.1" - debug@^3.1.0, debug@^3.2.6: version "3.2.6" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" @@ -4823,40 +4751,6 @@ mockdate@^3.0.5: resolved "https://registry.yarnpkg.com/mockdate/-/mockdate-3.0.5.tgz#789be686deb3149e7df2b663d2bc4392bc3284fb" integrity sha512-iniQP4rj1FhBdBYS/+eQv7j1tadJ9lJtdzgOpvsOHng/GbcDh2Fhdeq+ZRldrPYdXvCyfFUmFeEwEGXZB5I/AQ== -mongodb-memory-server-core@6.6.7: - version "6.6.7" - resolved "https://registry.yarnpkg.com/mongodb-memory-server-core/-/mongodb-memory-server-core-6.6.7.tgz#f402bb5808f052e20d040cd9ce03a64dde94fc62" - integrity sha512-21g2FpQdgqN3sFsj5lbGje1BhrSRGNHgz6gMAl8bvmdpRpoZErclkImVtjBXNHCNmCc1Dxr+EBvH11KaVE+9iQ== - dependencies: - "@types/cross-spawn" "^6.0.2" - "@types/debug" "^4.1.5" - "@types/dedent" "^0.7.0" - "@types/find-cache-dir" "^3.2.0" - "@types/find-package-json" "^1.1.1" - "@types/lockfile" "^1.0.1" - "@types/md5-file" "^4.0.2" - "@types/mkdirp" "^1.0.1" - "@types/semver" "^7.3.3" - "@types/tmp" "^0.2.0" - "@types/uuid" "^8.0.0" - camelcase "^6.0.0" - cross-spawn "^7.0.3" - debug "^4.1.1" - find-cache-dir "^3.3.1" - find-package-json "^1.2.0" - get-port "^5.1.1" - https-proxy-agent "^5.0.0" - lockfile "^1.0.4" - md5-file "^5.0.0" - mkdirp "^1.0.4" - semver "^7.3.2" - tar-stream "^2.1.3" - tmp "^0.2.1" - uuid "^8.2.0" - yauzl "^2.10.0" - optionalDependencies: - mongodb "^3.5.9" - mongodb-memory-server-core@6.9.2: version "6.9.2" resolved "https://registry.yarnpkg.com/mongodb-memory-server-core/-/mongodb-memory-server-core-6.9.2.tgz#a064602e85c065c63776cef20ec7311d2b2da206" @@ -4881,13 +4775,6 @@ mongodb-memory-server-core@6.9.2: optionalDependencies: mongodb "3.6.2" -mongodb-memory-server@6.6.7: - version "6.6.7" - resolved "https://registry.yarnpkg.com/mongodb-memory-server/-/mongodb-memory-server-6.6.7.tgz#fa5f1e8153f4248c7c166f99b5143662699f40d6" - integrity sha512-azRGr5csTAl0MCLR/amPCJrmV5TFwRcVtal56dHrPy1o2T8wZRc3AaJyukob8a/JP38JYa/pQnw1AQH7lFA2Cg== - dependencies: - mongodb-memory-server-core "6.6.7" - mongodb-memory-server@^6.9.0: version "6.9.2" resolved "https://registry.yarnpkg.com/mongodb-memory-server/-/mongodb-memory-server-6.9.2.tgz#75880bf5f485deceba2d7df20659b2796ff703cf" @@ -4895,7 +4782,7 @@ mongodb-memory-server@^6.9.0: dependencies: mongodb-memory-server-core "6.9.2" -mongodb@3.6.2, mongodb@^3.5.9: +mongodb@3.6.2: version "3.6.2" resolved "https://registry.yarnpkg.com/mongodb/-/mongodb-3.6.2.tgz#1154a4ac107bf1375112d83a29c5cf97704e96b6" integrity sha512-sSZOb04w3HcnrrXC82NEh/YGCmBuRgR+C1hZgmmv4L6dBz4BkRse6Y8/q/neXer9i95fKUBbFi4KgeceXmbsOA== @@ -6578,7 +6465,7 @@ table@^5.2.3: slice-ansi "^2.1.0" string-width "^3.0.0" -tar-stream@^2.1.3, tar-stream@^2.1.4: +tar-stream@^2.1.4: version "2.1.4" resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.1.4.tgz#c4fb1a11eb0da29b893a5b25476397ba2d053bfa" integrity sha512-o3pS2zlG4gxr67GmFYBLlq+dM8gyRGUOvsrHclSkvtVtQbjV0s/+ZE8OpICbaj8clrX3tjeHngYGP7rweaBnuw== @@ -6917,7 +6804,7 @@ uuid@^3.3.2: resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== -uuid@^8.0.0, uuid@^8.2.0, uuid@^8.3.0: +uuid@^8.0.0, uuid@^8.3.0: version "8.3.2" resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==