From c49100afd67a544b850b97d722bf18ce8b0c8e31 Mon Sep 17 00:00:00 2001 From: JamesNg Date: Wed, 30 Apr 2025 16:48:35 -0400 Subject: [PATCH 1/3] wrote unit tests for Auth router --- backend/package.json | 1 + backend/routers/auth.router.test.js | 80 +++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+) create mode 100644 backend/routers/auth.router.test.js diff --git a/backend/package.json b/backend/package.json index 689f0d962..5acf65552 100644 --- a/backend/package.json +++ b/backend/package.json @@ -8,6 +8,7 @@ "format": "prettier --check .", "test": "jest", "test:watch": "jest --watch", + "test:auth": "jest --watch auth.router.test.js", "start": "node server.js", "dev": "nodemon server.js", "client": "npm run start --prefix client", diff --git a/backend/routers/auth.router.test.js b/backend/routers/auth.router.test.js new file mode 100644 index 000000000..8e0cbad11 --- /dev/null +++ b/backend/routers/auth.router.test.js @@ -0,0 +1,80 @@ +// Set up mocks for UserController +const { User } = require('../models/user.model'); +const { UserController } = require('../controllers'); +const { verifyUser, verifyToken } = require('../middleware'); +const { authApiValidator } = require('../validators'); + +jest.mock('../controllers/user.controller'); +jest.mock('../models/user.model'); +jest.mock('../middleware/user.middleware'); + +// Import auth router +const express = require('express'); +const supertest = require('supertest'); +const authRouter = require('../routers/auth.router'); + +// Create a new Express application for testing +const testapp = express(); +// Use body parser to extract params in API calls +testapp.use(express.json()); +testapp.use('/api/auth', authRouter); +const request = supertest(testapp); + +describe('Unit tests for auth router', () => { + // Mocker user for test + const mockUser = { + id: 1, + name: { + firstName: 'mock', + lastName: 'user', + }, + email: 'mockUser@test.com', + accessLevel: 'user', + }; + + // Clear all mocks after each test + afterEach(() => { + jest.clearAllMocks(); + }); + + describe('CREATE', () => { + // it('should sign up new user with POST /api/auth/signup', async (done) => { + // // Mock successful save + // User.mockImplementation(() => ({ + // save: jest.fn().mockImplementationOnce((callback) => { + // callback(null, mockUser); + // }), + // })); + + // const response = await request.post('/api/auth/signup').send({ + // name: { + // firstName: mockUser.firstName, + // lastName: mockUser.lastName, + // }, + // email: mockUser.email.toLowerCase(), + // }); + + // // Tests + // // expect(UserController.createUser).toHaveBeenCalled(); + // expect(response.sendStatus).toBe(201); + // // expect(response.status).toBe(201); + + // // Marks completion of tests + // done(); + // }); + + it('should sign in existing user with POST /api/auth/signin', async (done) => { + const response = await request + .post('/api/auth/signin') + .set('Authorization', 'Bearer valid-token') + .send({ + firstName: 'Jane', + lastName: 'Smith', + email: 'mockuser@gmail.com', + }); + + expect(response.statusCode).toBe(201); + done(); + }) + }); +}); From a3277f963ba1d2ca49b5d6a1fee3f3ade4ed93b3 Mon Sep 17 00:00:00 2001 From: JamesNg Date: Mon, 12 May 2025 22:37:23 -0400 Subject: [PATCH 2/3] wrote unit tests --- backend/routers/auth.router.test.js | 154 +++++++++++++++++++--------- 1 file changed, 107 insertions(+), 47 deletions(-) diff --git a/backend/routers/auth.router.test.js b/backend/routers/auth.router.test.js index 8e0cbad11..657adf5e6 100644 --- a/backend/routers/auth.router.test.js +++ b/backend/routers/auth.router.test.js @@ -1,12 +1,29 @@ -// Set up mocks for UserController -const { User } = require('../models/user.model'); -const { UserController } = require('../controllers'); -const { verifyUser, verifyToken } = require('../middleware'); -const { authApiValidator } = require('../validators'); - +// Set up mocks for User model and controller jest.mock('../controllers/user.controller'); +jest.mock('../controllers/email.controller'); jest.mock('../models/user.model'); -jest.mock('../middleware/user.middleware'); +// Set up mocks for middleware +jest.mock('../middleware', () => ({ + AuthUtil: { + verifyCookie: jest.fn((req, res, next) => next()), + }, + verifyUser: { + checkDuplicateEmail: jest.fn((req, res, next) => next()), + isAdminByEmail: jest.fn((req, res, next) => next()), + }, + verifyToken: { + isTokenValid: jest.fn((req, res, next) => next()), + }, +})); +// Set up mocks for authApiValidator +jest.mock('../validators/user.api.validator', () => ({ + validateCreateUserAPICall: jest.fn((req, res, next) => next()), + validateSigninUserAPICall: jest.fn((req, res, next) => next()), +})); + +// Import User model and controller +const { User } = require('../models/user.model'); +const { UserController, EmailController } = require('../controllers'); // Import auth router const express = require('express'); @@ -21,6 +38,11 @@ testapp.use('/api/auth', authRouter); const request = supertest(testapp); describe('Unit tests for auth router', () => { + // Clear all mocks after each test + afterEach(() => { + jest.clearAllMocks(); + }); + // Mocker user for test const mockUser = { id: 1, @@ -32,49 +54,87 @@ describe('Unit tests for auth router', () => { accessLevel: 'user', }; - // Clear all mocks after each test - afterEach(() => { - jest.clearAllMocks(); - }); - describe('CREATE', () => { - // it('should sign up new user with POST /api/auth/signup', async (done) => { - // // Mock successful save - // User.mockImplementation(() => ({ - // save: jest.fn().mockImplementationOnce((callback) => { - // callback(null, mockUser); - // }), - // })); - - // const response = await request.post('/api/auth/signup').send({ - // name: { - // firstName: mockUser.firstName, - // lastName: mockUser.lastName, - // }, - // email: mockUser.email.toLowerCase(), - // }); - - // // Tests - // // expect(UserController.createUser).toHaveBeenCalled(); - // expect(response.sendStatus).toBe(201); - // // expect(response.status).toBe(201); - - // // Marks completion of tests - // done(); - // }); + it('should sign up new user with POST /api/auth/signup', async (done) => { + // Mock implementation of UserController.createUser + UserController.createUser.mockImplementationOnce((req, res) => { + res.status(201).send({ message: 'User created successfully' }); + }); + + // Mock POST API call + const response = await request.post('/api/auth/signup').send({ + name: { + firstName: mockUser.firstName, + lastName: mockUser.lastName, + }, + email: mockUser.email.toLowerCase(), + }); + + // Tests + expect(UserController.createUser).toHaveBeenCalled(); + expect(response.status).toBe(201); + 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) => { - const response = await request - .post('/api/auth/signin') - .set('Authorization', 'Bearer valid-token') - .send({ - firstName: 'Jane', - lastName: 'Smith', - email: 'mockuser@gmail.com', - }); - - expect(response.statusCode).toBe(201); + // Mock implementation for UserController.signin + const jsonToken = 'mockedToken'; + const email = mockUser.email.toLowerCase(); + const auth_origin = 'web'; + const cookie = 'mockedCookie'; + const headers = { + origin: 'http://localhost:3000', + }; + + UserController.signin.mockImplementation((req, res) => { + // Set a cookie in the response + res.cookie('token', cookie, { httpOnly: true }); + + // Set custom headers in the response + res.set('origin', headers.origin); + + EmailController.sendLoginLink( + req.body.email, + req.body.auth_origin, + mockUser.name.firstName, + jsonToken, + cookie, + headers.origin, + ); + + res.status(200).send({ message: 'Signin successful' }); + }); + + // Mock implementation for EmailController.sendLoginLink + EmailController.sendLoginLink.mockImplementation(() => { + console.log('Mocked EmailController.sendLoginLink called'); + }); + + const response = await request.post('/api/auth/signin').send({ + email: email, + auth_origin: auth_origin, + }); + + // Tests + expect(UserController.signin).toHaveBeenCalled(); + expect(EmailController.sendLoginLink).toHaveBeenCalledWith( + email, + auth_origin, + mockUser.name.firstName, + jsonToken, + cookie, + headers.origin, + ); + expect(response.status).toBe(200); + // Verify that the cookie is set + expect(response.headers['set-cookie']).toBeDefined(); + expect(response.headers['set-cookie'][0]).toContain('token=mockedCookie'); + + // Marks completion of tests done(); - }) + }); }); }); From f260bd6a9a22d7d454a653d132fc21ea04c10344 Mon Sep 17 00:00:00 2001 From: JamesNg Date: Tue, 13 May 2025 14:22:05 -0400 Subject: [PATCH 3/3] wrote unit tests for Auth router --- backend/package.json | 1 - backend/routers/auth.router.test.js | 77 ++++++++++++++++++++++++++++- 2 files changed, 75 insertions(+), 3 deletions(-) diff --git a/backend/package.json b/backend/package.json index 5acf65552..689f0d962 100644 --- a/backend/package.json +++ b/backend/package.json @@ -8,7 +8,6 @@ "format": "prettier --check .", "test": "jest", "test:watch": "jest --watch", - "test:auth": "jest --watch auth.router.test.js", "start": "node server.js", "dev": "nodemon server.js", "client": "npm run start --prefix client", diff --git a/backend/routers/auth.router.test.js b/backend/routers/auth.router.test.js index 657adf5e6..8be2688ff 100644 --- a/backend/routers/auth.router.test.js +++ b/backend/routers/auth.router.test.js @@ -29,6 +29,8 @@ const { UserController, EmailController } = require('../controllers'); const express = require('express'); const supertest = require('supertest'); const authRouter = require('../routers/auth.router'); +const { verifyToken, verifyUser, AuthUtil } = require('../middleware'); +const { authApiValidator } = require('../validators'); // Create a new Express application for testing const testapp = express(); @@ -37,6 +39,7 @@ testapp.use(express.json()); testapp.use('/api/auth', authRouter); const request = supertest(testapp); + describe('Unit tests for auth router', () => { // Clear all mocks after each test afterEach(() => { @@ -71,6 +74,8 @@ describe('Unit tests for auth router', () => { }); // Tests + expect(authApiValidator.validateCreateUserAPICall).toHaveBeenCalled(); + expect(verifyUser.checkDuplicateEmail).toHaveBeenCalled(); expect(UserController.createUser).toHaveBeenCalled(); expect(response.status).toBe(201); expect(response.body).toEqual({ message: 'User created successfully' }); @@ -105,7 +110,7 @@ describe('Unit tests for auth router', () => { headers.origin, ); - res.status(200).send({ message: 'Signin successful' }); + res.status(200).send('Signin successful'); }); // Mock implementation for EmailController.sendLoginLink @@ -119,6 +124,8 @@ describe('Unit tests for auth router', () => { }); // Tests + expect(authApiValidator.validateSigninUserAPICall).toHaveBeenCalled(); + expect(verifyUser.isAdminByEmail).toHaveBeenCalled(); expect(UserController.signin).toHaveBeenCalled(); expect(EmailController.sendLoginLink).toHaveBeenCalledWith( email, @@ -131,10 +138,76 @@ describe('Unit tests for auth router', () => { expect(response.status).toBe(200); // Verify that the cookie is set expect(response.headers['set-cookie']).toBeDefined(); - expect(response.headers['set-cookie'][0]).toContain('token=mockedCookie'); + expect(response.headers['set-cookie'][0]).toContain(`token=${cookie}`); + expect(response.text).toBe('Signin successful'); + + // Marks completion of tests + done(); + }); + + it('should verify sign in with POST /api/auth/verify-signin', async (done) => { + // Mock implementation for UserController.verifySignIn + UserController.verifySignIn.mockImplementation((req, res) => { + res.status(200).send(mockUser); + }); + + // Mock POST API call + const response = await request.post('/api/auth/verify-signin').send({ + token: 'mockedToken', + }); + + // Tests + expect(verifyToken.isTokenValid).toHaveBeenCalled(); + expect(UserController.verifySignIn).toHaveBeenCalled(); + expect(response.status).toBe(200); + expect(response.body).toEqual(mockUser); + + // Marks completion of tests + done(); + }); + + it('should verify me with POST /api/auth/me', async (done) => { + // Mock implementation for UserController.verifyMe + UserController.verifyMe.mockImplementation((req, res) => { + res.status(200).send(mockUser); + }); + + // Mock POST API call + const response = await request.post('/api/auth/me').send({ + token: 'mockedToken', + }); + + // Tests + expect(AuthUtil.verifyCookie).toHaveBeenCalled(); + expect(UserController.verifyMe).toHaveBeenCalled(); + expect(response.status).toBe(200); + expect(response.body).toEqual(mockUser); // Marks completion of tests done(); }); + + it('should log out with POST /api/auth/logout', async (done) => { + const token = 'token'; + // Mock implementation for UserController.logout + UserController.logout.mockImplementation((req, res) => { + res.clearCookie(token); + res.status(200).send('Successfully logged out.'); + }); + + // Mock POST API call + const response = await request.post('/api/auth/logout').set('Cookie', token); + + // Tests + expect(AuthUtil.verifyCookie).toHaveBeenCalled(); + expect(UserController.logout).toHaveBeenCalled(); + expect(response.headers['set-cookie'][0]).toMatch(/token=;/); + expect(response.status).toBe(200); + expect(response.text).toBe('Successfully logged out.'); + + // Marks completion of tests + done(); + }); }); + });