From afd777b2967ab2a0be6e6a68236c56d2f0c4d7f0 Mon Sep 17 00:00:00 2001 From: Anas Abbal Date: Thu, 11 Jul 2024 05:21:50 +0100 Subject: [PATCH 1/4] add npm test --- .github/workflows/ci.yml | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c44a508..856a7bd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,26 +26,28 @@ jobs: app: [driver, notification, gateway, ride, user-service, auth, user] steps: - - name: Checkout code - uses: actions/checkout@v2 + - name: Checkout code + uses: actions/checkout@v2 - - name: Use Node.js - uses: actions/setup-node@v2 - with: - node-version: '20' + - name: Use Node.js + uses: actions/setup-node@v2 + with: + node-version: '20' - - name: Install dependencies - run: npm install + - name: Install dependencies + run: npm install - - name: Install dependencies for ${{ matrix.app }} - working-directory: apps/${{ matrix.app }} - run: npm install + - name: Run tests for all apps + run: npm run test + + - name: Install dependencies for ${{ matrix.app }} + working-directory: apps/${{ matrix.app }} + run: npm install - - name: Start ${{ matrix.app }} - working-directory: apps/${{ matrix.app }} - run: nest start ${{ matrix.app }} & + - name: Start ${{ matrix.app }} + working-directory: apps/${{ matrix.app }} + run: nest start ${{ matrix.app }} & - - name: Run tests for all apps - run: npm run test + From 06c28f25331659e76bad384486e79cb62ed12f08 Mon Sep 17 00:00:00 2001 From: Anas Abbal Date: Thu, 11 Jul 2024 05:23:23 +0100 Subject: [PATCH 2/4] add npm test --- .github/workflows/ci.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 856a7bd..6334715 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -34,11 +34,9 @@ jobs: with: node-version: '20' - - name: Install dependencies - run: npm install + - run: npm install + - run: npm test - - name: Run tests for all apps - run: npm run test - name: Install dependencies for ${{ matrix.app }} working-directory: apps/${{ matrix.app }} From 654fae75de895bfc06c9d5e21963f99b3ede7258 Mon Sep 17 00:00:00 2001 From: Anas Abbal Date: Thu, 11 Jul 2024 05:24:14 +0100 Subject: [PATCH 3/4] add npm test --- libs/database/src/database.module.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/database/src/database.module.ts b/libs/database/src/database.module.ts index 86a0a10..f956e13 100644 --- a/libs/database/src/database.module.ts +++ b/libs/database/src/database.module.ts @@ -8,6 +8,7 @@ import { MongooseModule, MongooseModuleOptions } from '@nestjs/mongoose'; @Module({}) export class DatabaseModule { + private static logger = new Logger(DatabaseModule.name); static forRoot(uri: string, dbName: string, dbType: 'mongodb' | 'postgres'): DynamicModule { From b5f14a2e407dd7afc7dcbedc0c4f8384cc5f1716 Mon Sep 17 00:00:00 2001 From: Anas Abbal Date: Wed, 7 Aug 2024 16:37:05 +0100 Subject: [PATCH 4/4] add some tests --- apps/notification/src/notification.module.ts | 11 +- apps/user/src/__tests__/user.service.spec.ts | 213 +++++++++++++++++++ apps/user/src/user.controller.ts | 1 + 3 files changed, 224 insertions(+), 1 deletion(-) create mode 100644 apps/user/src/__tests__/user.service.spec.ts diff --git a/apps/notification/src/notification.module.ts b/apps/notification/src/notification.module.ts index fbe5fd6..dc38049 100644 --- a/apps/notification/src/notification.module.ts +++ b/apps/notification/src/notification.module.ts @@ -1,9 +1,18 @@ import { Module } from '@nestjs/common'; import { NotificationController } from './notification.controller'; import { NotificationService } from './notification.service'; +import { TypeOrmModule } from '@nestjs/typeorm'; +import { DatabaseModule } from '@app/database'; @Module({ - imports: [], + imports: [ + TypeOrmModule.forFeature([]), + DatabaseModule.forRoot( + process.env.DATABASE_URI, + process.env.DATABASE_NAME, + process.env.DATABASE_TYPE as 'mongodb' | 'postgres' + ), + ], controllers: [NotificationController], providers: [NotificationService], }) diff --git a/apps/user/src/__tests__/user.service.spec.ts b/apps/user/src/__tests__/user.service.spec.ts new file mode 100644 index 0000000..eae12d5 --- /dev/null +++ b/apps/user/src/__tests__/user.service.spec.ts @@ -0,0 +1,213 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { getRepositoryToken } from '@nestjs/typeorm'; +import { Repository } from 'typeorm'; +import { CACHE_MANAGER } from '@nestjs/cache-manager'; +import { ClientProxy, ClientProxyFactory, Transport } from '@nestjs/microservices'; +import { UserService } from '../user.service'; +import { User } from '../model/user.entity'; +import { UserCreateCommand } from '../command/user.create.cmd'; +import { hashPassword } from '../util/hash.pass'; + + + +const mockDriverServiceClient = { + send: jest.fn().mockResolvedValue('Driver created successfully'), +}; + +describe('UserService', () => { + let service: UserService; + let userRepository: Repository; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [ + UserService, + { + provide: getRepositoryToken(User), + useClass: Repository, + }, + { + provide: CACHE_MANAGER, + useValue: { + get: jest.fn(), + set: jest.fn(), + }, + }, + { + provide: ClientProxy, + useValue: mockDriverServiceClient, + }, + ], + }).compile(); + + service = module.get(UserService); + userRepository = module.get(getRepositoryToken(User)); + }); + + describe('createUser', () => { + it('should create a new user and call the DriverService', async () => { + const command: UserCreateCommand = { + firstName: 'John', + lastName: 'Doe', + email: 'john.doe@example.com', + password: 'password123', + confirmPassword: 'password123', + }; + + const hashedPassword = await hashPassword(command.password); + const mockUser = { + id: '123', + firstName: command.firstName, + lastName: command.lastName, + email: command.email, + password: hashedPassword, + } as User; + + // Mock the repository methods + userRepository.create = jest.fn().mockReturnValue(mockUser); + userRepository.save = jest.fn().mockResolvedValue(mockUser); + userRepository.findOne = jest.fn().mockResolvedValue(null); // Ensure no user exists + + const createdUser = await service.createUser(command); + + expect(userRepository.create).toHaveBeenCalledWith({ + firstName: command.firstName, + lastName: command.lastName, + email: command.email, + password: hashedPassword, + }); + expect(userRepository.save).toHaveBeenCalledWith(mockUser); + expect(createdUser).toEqual(mockUser); + expect(mockDriverServiceClient.send).toHaveBeenCalledWith({ cmd: 'create' }, mockUser.id); + }); + + it('should throw an error if the email already exists', async () => { + const command: UserCreateCommand = { + firstName: 'John', + lastName: 'Doe', + email: 'john.doe@example.com', + password: 'password123', + confirmPassword: 'password123', + }; + + // Mock the findOne method to simulate existing user + userRepository.findOne = jest.fn().mockResolvedValue({ + id: '123', + firstName: 'John', + lastName: 'Doe', + email: 'john.doe@example.com', + } as User); + + await expect(service.createUser(command)).rejects.toThrowError(); + }); + }); + + describe('findUserById', () => { + it('should find a user by id and return the user from cache', async () => { + const userId = '123'; + const mockUser = { + id: userId, + firstName: 'John', + lastName: 'Doe', + email: 'john.doe@example.com', + } as User; + + // Mock the cache manager methods + const cacheManager = service['cacheManager']; + cacheManager.get = jest.fn().mockResolvedValue(mockUser); + + // Mock the findOne method (not called in this case) + userRepository.findOne = jest.fn(); + + const user = await service.findUserById(userId); + + expect(cacheManager.get).toHaveBeenCalledWith(`user-${userId}`); + expect(user).toEqual(mockUser); + expect(userRepository.findOne).not.toHaveBeenCalled(); // Ensure repository is not called + }); + + it('should find a user by id and store in cache', async () => { + const userId = '123'; + const mockUser = { + id: userId, + firstName: 'John', + lastName: 'Doe', + email: 'john.doe@example.com', + } as User; + + // Mock the cache manager methods + const cacheManager = service['cacheManager']; + cacheManager.get = jest.fn().mockResolvedValue(null); // Simulate no cached user + cacheManager.set = jest.fn(); + + // Mock the findOne method + userRepository.findOne = jest.fn().mockResolvedValue(mockUser); + + const user = await service.findUserById(userId); + + expect(cacheManager.get).toHaveBeenCalledWith(`user-${userId}`); + expect(cacheManager.set).toHaveBeenCalledWith(`user-${userId}`, mockUser, 600); + expect(userRepository.findOne).toHaveBeenCalledWith({ where: { id: userId } }); + expect(user).toEqual(mockUser); + }); + + it('should throw an error if the user is not found', async () => { + const userId = '123'; + userRepository.findOne = jest.fn().mockResolvedValue(null); + + await expect(service.findUserById(userId)).rejects.toThrowError(); + }); + }); + + describe('getAll', () => { + it('should fetch all users and return from cache', async () => { + const mockUsers = [ + { + id: '123', + firstName: 'John', + lastName: 'Doe', + email: 'john.doe@example.com', + } as User, + ]; + + // Mock the cache manager methods + const cacheManager = service['cacheManager']; + cacheManager.get = jest.fn().mockResolvedValue(mockUsers); + + // Mock the find method (not called in this case) + userRepository.find = jest.fn(); + + const users = await service.getAll(); + + expect(cacheManager.get).toHaveBeenCalledWith('all-users'); + expect(users).toEqual(mockUsers); + expect(userRepository.find).not.toHaveBeenCalled(); // Ensure repository is not called + }); + + it('should fetch all users and store in cache', async () => { + const mockUsers = [ + { + id: '123', + firstName: 'John', + lastName: 'Doe', + email: 'john.doe@example.com', + } as User, + ]; + + // Mock the cache manager methods + const cacheManager = service['cacheManager']; + cacheManager.get = jest.fn().mockResolvedValue(null); // Simulate no cached users + cacheManager.set = jest.fn(); + + // Mock the find method + userRepository.find = jest.fn().mockResolvedValue(mockUsers); + + const users = await service.getAll(); + + expect(cacheManager.get).toHaveBeenCalledWith('all-users'); + expect(cacheManager.set).toHaveBeenCalledWith('all-users', mockUsers, 600); + expect(userRepository.find).toHaveBeenCalled(); + expect(users).toEqual(mockUsers); + }); + }); +}); \ No newline at end of file diff --git a/apps/user/src/user.controller.ts b/apps/user/src/user.controller.ts index 40ef40a..cf956c7 100644 --- a/apps/user/src/user.controller.ts +++ b/apps/user/src/user.controller.ts @@ -4,6 +4,7 @@ import { MessagePattern } from '@nestjs/microservices'; import { User } from './model/user.entity'; import { UserCreateCommand } from './command/user.create.cmd'; + @Controller('user') export class UserController {