Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion backend/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
{
"root": true,
"parser": "@babel/eslint-parser",
"parserOptions": {
"sourceType": "module",
"allowImportExportEverywhere": false,
"codeFrame": false
"codeFrame": false,
"requireConfigFile": false
},
"plugins": ["@babel"],
"extends": ["airbnb", "prettier"],
Expand Down
1 change: 0 additions & 1 deletion backend/models/user.model.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
166 changes: 166 additions & 0 deletions backend/models/user.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
const mongoose = require('mongoose');
const { User } = require('./user.model');
const { setupDB } = require("../setup-test");

setupDB("user-model");

// Clean up before each test
beforeEach(async () => {
await User.deleteMany({});
});

// 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 () => {
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);
});

test('Create a simple user', async () => {
// 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);
});
});

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', // 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.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);

// 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();
});
});

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',
});

try {
await User.create({
name: { firstName: 'Second', lastName: 'User' },
email: email, // Same email
accessLevel: 'user',
});
// If create doesn't throw, the test should fail
throw new Error('Should have thrown a duplicate key error for email.');
} catch (error) {
if (error.message === 'Should have thrown a duplicate key error for email.') {
throw error;
}
expect(error.code).toBe(11000); // MongoDB duplicate key error code
}
});

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', // Not in ["user", "admin", "superadmin"]
};

try {
const user = new User(userData);
await user.save();
throw new Error('Should have thrown a validation error for accessLevel.');
} catch (error) {
if (error.message === 'Should have thrown a validation error for accessLevel.') {
throw error;
}
expect(error).toBeInstanceOf(mongoose.Error.ValidationError);
expect(error.errors.accessLevel).toBeDefined();
expect(error.errors.accessLevel.kind).toBe('enum');
}
});
});
4 changes: 2 additions & 2 deletions backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
"eslint-plugin-import": "^2.22.0",
"eslint-plugin-jsx-a11y": "^6.3.1",
"eslint-plugin-react": "^7.20.6",
"jest": "^26.4.0",
"jest": "^29.7.0",
"mockdate": "^3.0.5",
"nodemon": "^2.0.2",
"prettier": "^2.1.1",
Expand All @@ -51,7 +51,7 @@
"googleapis": "^59.0.0",
"helmet": "^3.22.0",
"jsonwebtoken": "^8.5.1",
"mongodb-memory-server": "^6.9.0",
"mongodb-memory-server": "^8.2.3",
"mongoose": "^8.9.5",
"morgan": "^1.10.0",
"node-cron": "^2.0.3",
Expand Down
15 changes: 5 additions & 10 deletions backend/routers/auth.router.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ describe('Unit tests for auth router', () => {
};

describe('CREATE', () => {
it('should sign up new user with POST /api/auth/signup', async (done) => {
it('should sign up new user with POST /api/auth/signup', async () => {
// Mock implementation of UserController.createUser
UserController.createUser.mockImplementationOnce((req, res) => {
res.status(201).send({ message: 'User created successfully' });
Expand All @@ -81,10 +81,9 @@ describe('Unit tests for auth router', () => {
expect(response.body).toEqual({ message: 'User created successfully' });

// Marks completion of tests
done();
});

it('should sign in existing user with POST /api/auth/signin', async (done) => {
it('should sign in existing user with POST /api/auth/signin', async () => {
// Mock implementation for UserController.signin
const jsonToken = 'mockedToken';
const email = mockUser.email.toLowerCase();
Expand Down Expand Up @@ -142,10 +141,9 @@ describe('Unit tests for auth router', () => {
expect(response.text).toBe('Signin successful');

// Marks completion of tests
done();
});

it('should verify sign in with POST /api/auth/verify-signin', async (done) => {
it('should verify sign in with POST /api/auth/verify-signin', async () => {
// Mock implementation for UserController.verifySignIn
UserController.verifySignIn.mockImplementation((req, res) => {
res.status(200).send(mockUser);
Expand All @@ -163,10 +161,9 @@ describe('Unit tests for auth router', () => {
expect(response.body).toEqual(mockUser);

// Marks completion of tests
done();
});

it('should verify me with POST /api/auth/me', async (done) => {
it('should verify me with POST /api/auth/me', async () => {
// Mock implementation for UserController.verifyMe
UserController.verifyMe.mockImplementation((req, res) => {
res.status(200).send(mockUser);
Expand All @@ -184,10 +181,9 @@ describe('Unit tests for auth router', () => {
expect(response.body).toEqual(mockUser);

// Marks completion of tests
done();
});

it('should log out with POST /api/auth/logout', async (done) => {
it('should log out with POST /api/auth/logout', async () => {
const token = 'token';
// Mock implementation for UserController.logout
UserController.logout.mockImplementation((req, res) => {
Expand All @@ -206,7 +202,6 @@ describe('Unit tests for auth router', () => {
expect(response.text).toBe('Successfully logged out.');

// Marks completion of tests
done();
});
});

Expand Down
12 changes: 4 additions & 8 deletions backend/routers/checkIns.router.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ describe('Unit tests for checkIns router', () => {
});

describe('READ', () => {
it('should return a list of check-ins with GET /api/checkins', async (done) => {
it('should return a list of check-ins with GET /api/checkins', async () => {
// Mock Mongoose method
CheckIn.find.mockResolvedValue(mockCheckIns);

Expand All @@ -39,10 +39,9 @@ describe('Unit tests for checkIns router', () => {
expect(response.body).toEqual(mockCheckIns);

// Marks completion of test
done();
});

it('should return a single check-in by id with GET /api/checkins/:id', async (done) => {
it('should return a single check-in by id with GET /api/checkins/:id', async () => {
// Mock Mongoose method
CheckIn.findById.mockResolvedValue(mockCheckIns[0]);

Expand All @@ -54,10 +53,9 @@ describe('Unit tests for checkIns router', () => {
expect(response.body).toEqual(mockCheckIns[0]);

// Marks completion of test
done();
});

it('should return a list of users who have checked into a specific event with GET /api/checkins/findEvent/:id', async (done) => {
it('should return a list of users who have checked into a specific event with GET /api/checkins/findEvent/:id', async () => {
// Mock specific checkIn
const mockCheckIn = mockCheckIns[1];
const { eventId } = mockCheckIn;
Expand All @@ -79,12 +77,11 @@ describe('Unit tests for checkIns router', () => {
expect(response.body).toEqual(mockCheckIn);

// Marks completion of test
done();
});
});

describe('CREATE', () => {
it('should create a new check-in with POST /api/checkins', async (done) => {
it('should create a new check-in with POST /api/checkins', async () => {
// Mock new check-in data
const newCheckIn = {
id: 3,
Expand All @@ -104,7 +101,6 @@ describe('Unit tests for checkIns router', () => {
expect(response.status).toBe(201);

// Marks completion of test
done();
});
});
});
6 changes: 2 additions & 4 deletions backend/routers/checkUser.router.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ describe('Unit tests for checkUser router', () => {
});

describe('CREATE', () => {
it('should authenticate user with POST /api/checkuser', async (done) => {
it('should authenticate user with POST /api/checkuser', async () => {
// Mock Mongoose method
User.findOne.mockResolvedValue(mockUser);

Expand All @@ -61,12 +61,11 @@ describe('Unit tests for checkUser router', () => {
expect(response.body).toEqual({ user: mockUser, auth_origin: auth_origin });

// Marks completion of tests
done();
});
});

describe('READ', () => {
it('should return a user by id with GET /api/checkuser/:id', async (done) => {
it('should return a user by id with GET /api/checkuser/:id', async () => {
// Mock Mongoose method
User.findById.mockResolvedValue(mockUser);

Expand All @@ -78,7 +77,6 @@ describe('Unit tests for checkUser router', () => {
expect(response.body).toEqual(mockUser);

// Marks completion of tests
done();
});
});
});
Loading