From a175718eec90cc80f751512de4e883e9df490152 Mon Sep 17 00:00:00 2001 From: "C. Fuhrman" Date: Tue, 1 Oct 2024 11:30:26 -0400 Subject: [PATCH] refactorings of users.js --- .gitignore | 1 + server/__mocks__/AppError.js | 8 ++++ server/__mocks__/bcrypt.js | 6 +++ server/__mocks__/db.js | 20 +++++++++ server/__mocks__/folders.js | 8 ++++ server/__tests__/users.test.js | 82 ++++++++++++++++++++++++++++++++++ server/controllers/users.js | 8 +++- server/models/users.js | 34 +++++++------- server/package-lock.json | 1 + server/package.json | 3 +- 10 files changed, 154 insertions(+), 17 deletions(-) create mode 100644 server/__mocks__/AppError.js create mode 100644 server/__mocks__/bcrypt.js create mode 100644 server/__mocks__/db.js create mode 100644 server/__mocks__/folders.js create mode 100644 server/__tests__/users.test.js diff --git a/.gitignore b/.gitignore index c6bba59..ae7f632 100644 --- a/.gitignore +++ b/.gitignore @@ -128,3 +128,4 @@ dist .yarn/build-state.yml .yarn/install-state.gz .pnp.* +db-backup/ diff --git a/server/__mocks__/AppError.js b/server/__mocks__/AppError.js new file mode 100644 index 0000000..0073aa4 --- /dev/null +++ b/server/__mocks__/AppError.js @@ -0,0 +1,8 @@ +class AppError extends Error { + constructor(message, statusCode) { + super(message); + this.statusCode = statusCode; + } +} + +module.exports = AppError; diff --git a/server/__mocks__/bcrypt.js b/server/__mocks__/bcrypt.js new file mode 100644 index 0000000..e03367e --- /dev/null +++ b/server/__mocks__/bcrypt.js @@ -0,0 +1,6 @@ +const mockBcrypt = { + hash: jest.fn().mockResolvedValue('hashedPassword'), + compare: jest.fn().mockResolvedValue(true), +}; + +module.exports = mockBcrypt; diff --git a/server/__mocks__/db.js b/server/__mocks__/db.js new file mode 100644 index 0000000..a8abb72 --- /dev/null +++ b/server/__mocks__/db.js @@ -0,0 +1,20 @@ +class MockDBConnection { + constructor() { + this.db = jest.fn().mockReturnThis(); + this.collection = jest.fn().mockReturnThis(); + this.insertOne = jest.fn(); + this.findOne = jest.fn(); + this.updateOne = jest.fn(); + this.deleteOne = jest.fn(); + } + + async connect() { + // Simulate successful connection + } + + getConnection() { + return this; + } +} + +module.exports = MockDBConnection; diff --git a/server/__mocks__/folders.js b/server/__mocks__/folders.js new file mode 100644 index 0000000..9bc3abe --- /dev/null +++ b/server/__mocks__/folders.js @@ -0,0 +1,8 @@ +const mockFolders = { + create: jest.fn(), + find: jest.fn(), + update: jest.fn(), + delete: jest.fn(), +}; + +module.exports = mockFolders; diff --git a/server/__tests__/users.test.js b/server/__tests__/users.test.js new file mode 100644 index 0000000..506d8ec --- /dev/null +++ b/server/__tests__/users.test.js @@ -0,0 +1,82 @@ +const Users = require('../models/users'); +const bcrypt = require('bcrypt'); +const AppError = require('../middleware/AppError'); +const Folders = require('../models/folders'); +const { ObjectId } = require('mongodb'); + +jest.mock('bcrypt'); +jest.mock('../middleware/AppError'); +jest.mock('../models/folders'); + +describe('Users', () => { + let users; + let db; + + beforeEach(() => { + jest.clearAllMocks(); // Clear any previous mock calls + + // Mock the database connection + db = { + connect: jest.fn(), + getConnection: jest.fn().mockReturnThis(), // Add getConnection method + collection: jest.fn().mockReturnThis(), + findOne: jest.fn(), + insertOne: jest.fn().mockResolvedValue({ _id: new ObjectId() }), // Mock insertOne to return an ObjectId + updateOne: jest.fn(), + deleteOne: jest.fn(), + }; + + users = new Users(db); + }); + + it('should register a new user', async () => { + db.collection().findOne.mockResolvedValue(null); // No user found + db.collection().insertOne.mockResolvedValue({ _id: new ObjectId() }); + bcrypt.hash.mockResolvedValue('hashedPassword'); + Folders.create.mockResolvedValue(true); + + const email = 'test@example.com'; + const password = 'password123'; + const result = await users.register(email, password); + + expect(db.connect).toHaveBeenCalled(); + expect(db.collection().findOne).toHaveBeenCalledWith({ email }); + expect(bcrypt.hash).toHaveBeenCalledWith(password, 10); + expect(db.collection().insertOne).toHaveBeenCalledWith({ + email, + password: 'hashedPassword', + created_at: expect.any(Date), + }); + expect(Folders.create).toHaveBeenCalledWith('Dossier par Défaut', expect.any(String)); + expect(result._id).toBeDefined(); // Ensure result has _id + }); + + // it('should update the user password', async () => { + // db.collection().updateOne.mockResolvedValue({ modifiedCount: 1 }); + // bcrypt.hash.mockResolvedValue('hashedPassword'); + + // const email = 'test@example.com'; + // const newPassword = 'newPassword123'; + // const result = await users.updatePassword(email, newPassword); + + // expect(db.connect).toHaveBeenCalled(); + // expect(db.collection().updateOne).toHaveBeenCalledWith( + // { email }, + // { $set: { password: 'hashedPassword' } } + // ); + // expect(result).toEqual(newPassword); + // }); + + // it('should delete a user', async () => { + // db.collection().deleteOne.mockResolvedValue({ deletedCount: 1 }); + + // const email = 'test@example.com'; + // const result = await users.delete(email); + + // expect(db.connect).toHaveBeenCalled(); + // expect(db.collection().deleteOne).toHaveBeenCalledWith({ email }); + // expect(result).toBe(true); + // }); + + // Add more tests as needed +}); diff --git a/server/controllers/users.js b/server/controllers/users.js index 4494f1d..8f102b1 100644 --- a/server/controllers/users.js +++ b/server/controllers/users.js @@ -1,12 +1,18 @@ const emailer = require('../config/email.js'); const model = require('../models/users.js'); const jwt = require('../middleware/jwtToken.js'); +const db = require('../config/db.js'); const AppError = require('../middleware/AppError.js'); const { MISSING_REQUIRED_PARAMETER, LOGIN_CREDENTIALS_ERROR, GENERATE_PASSWORD_ERROR, UPDATE_PASSWORD_ERROR, DELETE_USER_ERROR } = require('../constants/errorCodes'); class UsersController { + constructor() { + this.db = db; + this.users = new model(this.db); + } + async register(req, res, next) { try { const { email, password } = req.body; @@ -143,4 +149,4 @@ class UsersController { } -module.exports = new UsersController; \ No newline at end of file +module.exports = new UsersController; diff --git a/server/models/users.js b/server/models/users.js index 3790fce..1738424 100644 --- a/server/models/users.js +++ b/server/models/users.js @@ -1,11 +1,15 @@ //user -const db = require('../config/db.js'); +// const db = require('../config/db.js'); const bcrypt = require('bcrypt'); const AppError = require('../middleware/AppError.js'); const { USER_ALREADY_EXISTS } = require('../constants/errorCodes'); const Folders = require('../models/folders.js'); class Users { + constructor(db) { + console.log("Users constructor: db", db) + this.db = db; + } async hashPassword(password) { return await bcrypt.hash(password, 10) @@ -20,8 +24,8 @@ class Users { } async register(email, password) { - await db.connect() - const conn = db.getConnection(); + await this.db.connect() + const conn = this.db.getConnection(); const userCollection = conn.collection('users'); @@ -37,18 +41,18 @@ class Users { created_at: new Date() }; - await userCollection.insertOne(newUser); + const result = await userCollection.insertOne(newUser); + const userId = result._id.toString(); const folderTitle = 'Dossier par Défaut'; - const userId = newUser._id.toString(); await Folders.create(folderTitle, userId); - // TODO: verif if inserted properly... + return result; } async login(email, password) { - await db.connect() - const conn = db.getConnection(); + await this.db.connect() + const conn = this.db.getConnection(); const userCollection = conn.collection('users'); @@ -74,8 +78,8 @@ class Users { } async changePassword(email, newPassword) { - await db.connect() - const conn = db.getConnection(); + await this.db.connect() + const conn = this.db.getConnection(); const userCollection = conn.collection('users'); @@ -89,8 +93,8 @@ class Users { } async delete(email) { - await db.connect() - const conn = db.getConnection(); + await this.db.connect() + const conn = this.db.getConnection(); const userCollection = conn.collection('users'); @@ -102,8 +106,8 @@ class Users { } async getId(email) { - await db.connect() - const conn = db.getConnection(); + await this.db.connect() + const conn = this.db.getConnection(); const userCollection = conn.collection('users'); @@ -118,4 +122,4 @@ class Users { } -module.exports = new Users; +module.exports = Users; diff --git a/server/package-lock.json b/server/package-lock.json index 05f5480..e17d76d 100644 --- a/server/package-lock.json +++ b/server/package-lock.json @@ -22,6 +22,7 @@ }, "devDependencies": { "jest": "^29.7.0", + "jest-mock": "^29.7.0", "nodemon": "^3.0.1", "supertest": "^6.3.4" }, diff --git a/server/package.json b/server/package.json index bc3a830..a61dcfb 100644 --- a/server/package.json +++ b/server/package.json @@ -7,7 +7,7 @@ "build": "webpack --config webpack.config.js", "start": "node app.js", "dev": "nodemon app.js", - "test": "jest" + "test": "jest --colors" }, "keywords": [], "author": "", @@ -26,6 +26,7 @@ }, "devDependencies": { "jest": "^29.7.0", + "jest-mock": "^29.7.0", "nodemon": "^3.0.1", "supertest": "^6.3.4" },