From 74499ee89282874908fc9b8ae26a6e3b38bbfd76 Mon Sep 17 00:00:00 2001 From: zhumeisongsong Date: Wed, 4 Dec 2024 11:52:03 +0900 Subject: [PATCH 1/6] =?UTF-8?q?refactor:=20=E2=99=BB=EF=B8=8F=20rename=20G?= =?UTF-8?q?etUserUseCase=20to=20GetUserByIdUseCase?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ....use-case.spec.ts => get-user-by-id.use-case.spec.ts} | 0 .../{get-user.use-case.ts => get-user-by-id.use-case.ts} | 9 ++------- 2 files changed, 2 insertions(+), 7 deletions(-) rename libs/users/application/src/lib/use-cases/{get-user.use-case.spec.ts => get-user-by-id.use-case.spec.ts} (100%) rename libs/users/application/src/lib/use-cases/{get-user.use-case.ts => get-user-by-id.use-case.ts} (67%) diff --git a/libs/users/application/src/lib/use-cases/get-user.use-case.spec.ts b/libs/users/application/src/lib/use-cases/get-user-by-id.use-case.spec.ts similarity index 100% rename from libs/users/application/src/lib/use-cases/get-user.use-case.spec.ts rename to libs/users/application/src/lib/use-cases/get-user-by-id.use-case.spec.ts diff --git a/libs/users/application/src/lib/use-cases/get-user.use-case.ts b/libs/users/application/src/lib/use-cases/get-user-by-id.use-case.ts similarity index 67% rename from libs/users/application/src/lib/use-cases/get-user.use-case.ts rename to libs/users/application/src/lib/use-cases/get-user-by-id.use-case.ts index be0f1e8..aa6ba98 100644 --- a/libs/users/application/src/lib/use-cases/get-user.use-case.ts +++ b/libs/users/application/src/lib/use-cases/get-user-by-id.use-case.ts @@ -2,18 +2,13 @@ import { Inject, Injectable } from '@nestjs/common'; import { User, USERS_REPOSITORY, UsersRepository } from '@users/domain'; @Injectable() -export class GetUserUseCase { +export class GetUserByIdUseCase { constructor( @Inject(USERS_REPOSITORY) private readonly usersRepository: UsersRepository, ) {} async execute(id: string): Promise { - const user = await this.usersRepository.findById(id); - - if (!user) { - return null; - } - return user; + return await this.usersRepository.findById(id); } } From 52733d54dd4960b69151ea09f10ac35168245e72 Mon Sep 17 00:00:00 2001 From: zhumeisongsong Date: Wed, 4 Dec 2024 12:29:03 +0900 Subject: [PATCH 2/6] =?UTF-8?q?refactor:=20=E2=99=BB=EF=B8=8F=20move=20Apo?= =?UTF-8?q?lloFederationDriverConfig=20to=20app=20module?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/users/src/app/app.module.ts | 20 +++++++++++++ .../src/lib/users.module.ts | 29 ++++--------------- 2 files changed, 26 insertions(+), 23 deletions(-) diff --git a/apps/users/src/app/app.module.ts b/apps/users/src/app/app.module.ts index 31f1953..4dc918e 100644 --- a/apps/users/src/app/app.module.ts +++ b/apps/users/src/app/app.module.ts @@ -1,5 +1,11 @@ +import { ApolloServerPluginInlineTrace } from '@apollo/server/plugin/inlineTrace'; +import { + ApolloFederationDriver, + ApolloFederationDriverConfig, +} from '@nestjs/apollo'; import { Module } from '@nestjs/common'; import { ConfigModule } from '@nestjs/config'; +import { GraphQLModule } from '@nestjs/graphql'; import { databaseConfig, userAppConfig, @@ -18,6 +24,20 @@ import { AppService } from './app.service'; isGlobal: true, load: [userAppConfig, databaseConfig, awsConfig, authConfig], }), + GraphQLModule.forRoot({ + driver: ApolloFederationDriver, + autoSchemaFile: { + /** + * MEMO: + * Because of this problem, so mush need specify the version + * https://github.com/nestjs/graphql/issues/2646#issuecomment-1567381944 + */ + federation: 2, + }, + playground: process.env['NODE_ENV'] !== 'production', + sortSchema: true, + plugins: [ApolloServerPluginInlineTrace()], + }), UsersModule, AuthModule, ], diff --git a/libs/users/interface-adapters/src/lib/users.module.ts b/libs/users/interface-adapters/src/lib/users.module.ts index b5958e7..6bb1454 100644 --- a/libs/users/interface-adapters/src/lib/users.module.ts +++ b/libs/users/interface-adapters/src/lib/users.module.ts @@ -1,12 +1,6 @@ -import { ApolloServerPluginInlineTrace } from '@apollo/server/plugin/inlineTrace'; -import { - ApolloFederationDriver, - ApolloFederationDriverConfig, -} from '@nestjs/apollo'; import { Module } from '@nestjs/common'; -import { GraphQLModule } from '@nestjs/graphql'; import { DatabaseModule } from '@shared/infrastructure-mongoose'; -import { UsersService, GetUserUseCase } from '@users/application'; +import { UsersService, GetUserByIdUseCase, GetUserByEmailUseCase } from '@users/application'; import { MongooseUsersRepository, UserDocument, @@ -21,29 +15,18 @@ import { UsersResolver } from './resolver/users.resolver'; providers: [ UsersResolver, UsersService, - GetUserUseCase, + GetUserByIdUseCase, + GetUserByEmailUseCase, { provide: USERS_REPOSITORY, useClass: MongooseUsersRepository, }, ], imports: [ - GraphQLModule.forRoot({ - driver: ApolloFederationDriver, - autoSchemaFile: { - /** - * MEMO: - * Because of this problem, so mush need specify the version - * https://github.com/nestjs/graphql/issues/2646#issuecomment-1567381944 - */ - federation: 2, - }, - playground: process.env['NODE_ENV'] !== 'production', - sortSchema: true, - plugins: [ApolloServerPluginInlineTrace()], - }), DatabaseModule, - MongooseModule.forFeature([{ name: UserDocument.name, schema: UserSchema }]) + MongooseModule.forFeature([ + { name: UserDocument.name, schema: UserSchema }, + ]), ], exports: [UsersService], }) From 3c2a33117cda7f1eaee1aff3f51ed4f9ff52242f Mon Sep 17 00:00:00 2001 From: zhumeisongsong Date: Wed, 4 Dec 2024 12:29:36 +0900 Subject: [PATCH 3/6] =?UTF-8?q?test:=20=F0=9F=A7=AA=20fix=20import=20error?= =?UTF-8?q?=20in=20test=20cases?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lib/use-cases/get-user-by-id.use-case.spec.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/libs/users/application/src/lib/use-cases/get-user-by-id.use-case.spec.ts b/libs/users/application/src/lib/use-cases/get-user-by-id.use-case.spec.ts index 5426856..e786cfa 100644 --- a/libs/users/application/src/lib/use-cases/get-user-by-id.use-case.spec.ts +++ b/libs/users/application/src/lib/use-cases/get-user-by-id.use-case.spec.ts @@ -1,15 +1,15 @@ -import { GetUserUseCase } from './get-user.use-case'; +import { GetUserByIdUseCase } from './get-user-by-id.use-case'; import { UsersRepository } from '@users/domain'; -describe('GetUserUseCase', () => { - let getUserUseCase: GetUserUseCase; +describe('GetUserByIdUseCase', () => { + let getUserByIdUseCase: GetUserByIdUseCase; let usersRepository: UsersRepository; beforeEach(() => { usersRepository = { findById: jest.fn(), }; - getUserUseCase = new GetUserUseCase(usersRepository); + getUserByIdUseCase = new GetUserByIdUseCase(usersRepository); }); describe('execute', () => { @@ -22,7 +22,7 @@ describe('GetUserUseCase', () => { }; (usersRepository.findById as jest.Mock).mockResolvedValue(mockUser); - const result = await getUserUseCase.execute('1'); + const result = await getUserByIdUseCase.execute('1'); expect(result).toEqual(mockUser); expect(usersRepository.findById).toHaveBeenCalledWith('1'); @@ -31,7 +31,7 @@ describe('GetUserUseCase', () => { it('should return null when user not found', async () => { (usersRepository.findById as jest.Mock).mockResolvedValue(null); - const result = await getUserUseCase.execute('1'); + const result = await getUserByIdUseCase.execute('1'); expect(result).toBeNull(); expect(usersRepository.findById).toHaveBeenCalledWith('1'); From dec50d620f4b31729eda9bc960f92dd65ce1ede2 Mon Sep 17 00:00:00 2001 From: zhumeisongsong Date: Wed, 4 Dec 2024 13:02:15 +0900 Subject: [PATCH 4/6] =?UTF-8?q?feat:=20=E2=9C=A8=20add=20findByEmail=20use?= =?UTF-8?q?=20case?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../interface-adapters/src/lib/auth.module.ts | 5 ++- libs/users/application/src/index.ts | 3 +- .../use-cases/get-user-by-email.use-case.ts | 14 +++++++ .../application/src/lib/users.service.spec.ts | 38 +++++++++++++++---- .../application/src/lib/users.service.ts | 13 ++++--- .../domain/src/lib/users.repository.spec.ts | 19 ++++++++++ libs/users/domain/src/lib/users.repository.ts | 1 + .../src/lib/mongoose-users.repository.ts | 14 +++++++ 8 files changed, 92 insertions(+), 15 deletions(-) create mode 100644 libs/users/application/src/lib/use-cases/get-user-by-email.use-case.ts diff --git a/libs/auth/interface-adapters/src/lib/auth.module.ts b/libs/auth/interface-adapters/src/lib/auth.module.ts index 29ee385..f481c98 100644 --- a/libs/auth/interface-adapters/src/lib/auth.module.ts +++ b/libs/auth/interface-adapters/src/lib/auth.module.ts @@ -5,7 +5,7 @@ import { MongooseModule } from '@nestjs/mongoose'; import { JwtModule, JwtService } from '@nestjs/jwt'; import { AwsCognitoService } from '@shared/infrastructure-aws-cognito'; import { DatabaseModule } from '@shared/infrastructure-mongoose'; -import { GetUserUseCase, UsersService } from '@users/application'; +import { GetUserByEmailUseCase, GetUserByIdUseCase, UsersService } from '@users/application'; import { USERS_REPOSITORY } from '@users/domain'; import { MongooseUsersRepository, @@ -23,7 +23,8 @@ import { AuthResolver } from './resolver/auth.resolver'; AwsCognitoService, UsersService, JwtService, - GetUserUseCase, + GetUserByIdUseCase, + GetUserByEmailUseCase, { provide: USERS_REPOSITORY, useClass: MongooseUsersRepository, diff --git a/libs/users/application/src/index.ts b/libs/users/application/src/index.ts index 192fddd..5c3670a 100644 --- a/libs/users/application/src/index.ts +++ b/libs/users/application/src/index.ts @@ -1,4 +1,5 @@ -export * from './lib/use-cases/get-user.use-case'; +export * from './lib/use-cases/get-user-by-id.use-case'; +export * from './lib/use-cases/get-user-by-email.use-case'; // service export * from './lib/users.service'; diff --git a/libs/users/application/src/lib/use-cases/get-user-by-email.use-case.ts b/libs/users/application/src/lib/use-cases/get-user-by-email.use-case.ts new file mode 100644 index 0000000..5c01524 --- /dev/null +++ b/libs/users/application/src/lib/use-cases/get-user-by-email.use-case.ts @@ -0,0 +1,14 @@ +import { Inject, Injectable } from "@nestjs/common"; +import { User, USERS_REPOSITORY, UsersRepository } from "@users/domain"; + +@Injectable() +export class GetUserByEmailUseCase { + constructor( + @Inject(USERS_REPOSITORY) + private readonly usersRepository: UsersRepository, + ) {} + + async execute(email: string): Promise { + return this.usersRepository.findByEmail(email); + } +} diff --git a/libs/users/application/src/lib/users.service.spec.ts b/libs/users/application/src/lib/users.service.spec.ts index 8e7a651..93e13a4 100644 --- a/libs/users/application/src/lib/users.service.spec.ts +++ b/libs/users/application/src/lib/users.service.spec.ts @@ -1,18 +1,19 @@ import { Test, TestingModule } from '@nestjs/testing'; -import { UsersService } from './users.service'; -import { GetUserUseCase } from './use-cases/get-user.use-case'; import { User } from '@users/domain'; +import { UsersService } from './users.service'; +import { GetUserByIdUseCase } from './use-cases/get-user-by-id.use-case'; + describe('UsersService', () => { let service: UsersService; - let getUserUseCase: GetUserUseCase; + let getUserByIdUseCase: GetUserByIdUseCase; beforeEach(async () => { const module: TestingModule = await Test.createTestingModule({ providers: [ UsersService, { - provide: GetUserUseCase, + provide: GetUserByIdUseCase, useValue: { execute: jest.fn(), }, @@ -21,7 +22,7 @@ describe('UsersService', () => { }).compile(); service = module.get(UsersService); - getUserUseCase = module.get(GetUserUseCase); + getUserByIdUseCase = module.get(GetUserByIdUseCase); }); it('should be defined', () => { @@ -36,17 +37,40 @@ describe('UsersService', () => { firstName: 'John', lastName: 'Doe', }; - jest.spyOn(getUserUseCase, 'execute').mockResolvedValue(user); + jest.spyOn(getUserByIdUseCase, 'execute').mockResolvedValue(user); const result = await service.findById('1'); expect(result).toEqual(user); }); it('should return null if user not found', async () => { - jest.spyOn(getUserUseCase, 'execute').mockResolvedValue(null); + jest.spyOn(getUserByIdUseCase, 'execute').mockResolvedValue(null); const result = await service.findById('2'); expect(result).toBeNull(); }); }); + + describe('findByEmail', () => { + it('should return a user if found', async () => { + const user: User = { + id: '1', + email: 'test@example.com', + firstName: 'John', + lastName: 'Doe', + }; + jest.spyOn(getUserByIdUseCase, 'execute').mockResolvedValue(user); + + const result = await service.findByEmail('test@example.com'); + expect(result).toEqual(user); + }); + + it('should return null if user not found', async () => { + jest.spyOn(getUserByIdUseCase, 'execute').mockResolvedValue(null); + + const result = await service.findByEmail('test@example.com'); + expect(result).toBeNull(); + }); + }); + }); diff --git a/libs/users/application/src/lib/users.service.ts b/libs/users/application/src/lib/users.service.ts index 83c908f..87d2b50 100644 --- a/libs/users/application/src/lib/users.service.ts +++ b/libs/users/application/src/lib/users.service.ts @@ -1,18 +1,21 @@ import { Injectable } from '@nestjs/common'; import { User } from '@users/domain'; -import { GetUserUseCase } from './use-cases/get-user.use-case'; +import { GetUserByIdUseCase } from './use-cases/get-user-by-id.use-case'; +import { GetUserByEmailUseCase } from './use-cases/get-user-by-email.use-case'; @Injectable() export class UsersService { - constructor(private readonly getUserUseCase: GetUserUseCase) {} + constructor( + private readonly getUserByIdUseCase: GetUserByIdUseCase, + private readonly getUserByEmailUseCase: GetUserByEmailUseCase, + ) {} async findById(id: string): Promise { - return this.getUserUseCase.execute(id); + return this.getUserByIdUseCase.execute(id); } async findByEmail(email: string): Promise { - // TODO: refactor getUserUseCase - return this.getUserUseCase.execute(email); + return this.getUserByEmailUseCase.execute(email); } } diff --git a/libs/users/domain/src/lib/users.repository.spec.ts b/libs/users/domain/src/lib/users.repository.spec.ts index ba5e3b8..d560e1e 100644 --- a/libs/users/domain/src/lib/users.repository.spec.ts +++ b/libs/users/domain/src/lib/users.repository.spec.ts @@ -15,6 +15,10 @@ class MockUsersRepository implements UsersRepository { async findById(id: string): Promise { return this.users.find((user) => user.id === id) || null; } + + async findByEmail(email: string): Promise { + return this.users.find((user) => user.email === email) || null; + } } describe('UsersRepository', () => { @@ -38,4 +42,19 @@ describe('UsersRepository', () => { const user = await usersRepository.findById('3'); expect(user).toBeNull(); }); + + test('findByEmail should return a user by email', async () => { + const user = await usersRepository.findByEmail('jane@example.com'); + expect(user).toEqual({ + id: '2', + email: 'jane@example.com', + firstName: 'Jane', + lastName: 'Smith', + }); + }); + + test('findByEmail should return null if user not found', async () => { + const user = await usersRepository.findByEmail('nonexistent@example.com'); + expect(user).toBeNull(); + }); }); diff --git a/libs/users/domain/src/lib/users.repository.ts b/libs/users/domain/src/lib/users.repository.ts index 4af6be0..593a649 100644 --- a/libs/users/domain/src/lib/users.repository.ts +++ b/libs/users/domain/src/lib/users.repository.ts @@ -2,6 +2,7 @@ import { User } from './user.entity'; export interface UsersRepository { findById(id: string): Promise; + findByEmail(email: string): Promise; } export const USERS_REPOSITORY = Symbol('USERS_REPOSITORY'); \ No newline at end of file diff --git a/libs/users/infrastructure/mongoose/src/lib/mongoose-users.repository.ts b/libs/users/infrastructure/mongoose/src/lib/mongoose-users.repository.ts index 9a560ed..c61f9a8 100644 --- a/libs/users/infrastructure/mongoose/src/lib/mongoose-users.repository.ts +++ b/libs/users/infrastructure/mongoose/src/lib/mongoose-users.repository.ts @@ -25,4 +25,18 @@ export class MongooseUsersRepository implements UsersRepository { userDocument.lastName, ); } + + async findByEmail(email: string): Promise { + const userDocument = await this.userModel.findOne({ email }).exec(); + + if (!userDocument) { + return null; + } + return new User( + userDocument.id, + userDocument.email, + userDocument.firstName, + userDocument.lastName, + ); + } } From 46958c785aa46c818c7498d6378e72deabc85d69 Mon Sep 17 00:00:00 2001 From: zhumeisongsong Date: Wed, 4 Dec 2024 13:16:52 +0900 Subject: [PATCH 5/6] =?UTF-8?q?test:=20=F0=9F=A7=AA=20add=20test=20cases?= =?UTF-8?q?=20of=20GetUserByEmailUseCase?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../get-user-by-email.use-case.spec.ts | 41 +++++++++++++++++++ .../use-cases/get-user-by-id.use-case.spec.ts | 1 + 2 files changed, 42 insertions(+) create mode 100644 libs/users/application/src/lib/use-cases/get-user-by-email.use-case.spec.ts diff --git a/libs/users/application/src/lib/use-cases/get-user-by-email.use-case.spec.ts b/libs/users/application/src/lib/use-cases/get-user-by-email.use-case.spec.ts new file mode 100644 index 0000000..ad0da07 --- /dev/null +++ b/libs/users/application/src/lib/use-cases/get-user-by-email.use-case.spec.ts @@ -0,0 +1,41 @@ +import { GetUserByEmailUseCase } from './get-user-by-email.use-case'; +import { UsersRepository } from '@users/domain'; + +describe('GetUserByEmailUseCase', () => { + let getUserByEmailUseCase: GetUserByEmailUseCase; + let usersRepository: UsersRepository; + + beforeEach(() => { + usersRepository = { + findById: jest.fn(), + findByEmail: jest.fn(), + }; + getUserByEmailUseCase = new GetUserByEmailUseCase(usersRepository); + }); + + describe('execute', () => { + it('should return user when found', async () => { + const mockUser = { + id: '1', + email: 'test@example.com', + firstName: 'John', + lastName: 'Doe', + }; + (usersRepository.findByEmail as jest.Mock).mockResolvedValue(mockUser); + + const result = await getUserByEmailUseCase.execute('test@example.com'); + + expect(result).toEqual(mockUser); + expect(usersRepository.findByEmail).toHaveBeenCalledWith('1'); + }); + + it('should return null when user not found', async () => { + (usersRepository.findByEmail as jest.Mock).mockResolvedValue(null); + + const result = await getUserByEmailUseCase.execute('test@example.com'); + + expect(result).toBeNull(); + expect(usersRepository.findByEmail).toHaveBeenCalledWith('1'); + }); + }); +}); diff --git a/libs/users/application/src/lib/use-cases/get-user-by-id.use-case.spec.ts b/libs/users/application/src/lib/use-cases/get-user-by-id.use-case.spec.ts index e786cfa..e57326e 100644 --- a/libs/users/application/src/lib/use-cases/get-user-by-id.use-case.spec.ts +++ b/libs/users/application/src/lib/use-cases/get-user-by-id.use-case.spec.ts @@ -8,6 +8,7 @@ describe('GetUserByIdUseCase', () => { beforeEach(() => { usersRepository = { findById: jest.fn(), + findByEmail: jest.fn(), }; getUserByIdUseCase = new GetUserByIdUseCase(usersRepository); }); From 6635353a3f5b718a126396a906dc3032fe93d39e Mon Sep 17 00:00:00 2001 From: zhumeisongsong Date: Wed, 4 Dec 2024 13:24:34 +0900 Subject: [PATCH 6/6] =?UTF-8?q?test:=20=F0=9F=A7=AA=20add=20test=20cases?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../get-user-by-email.use-case.spec.ts | 4 +- .../application/src/lib/users.service.spec.ts | 54 +++++++++++-------- 2 files changed, 34 insertions(+), 24 deletions(-) diff --git a/libs/users/application/src/lib/use-cases/get-user-by-email.use-case.spec.ts b/libs/users/application/src/lib/use-cases/get-user-by-email.use-case.spec.ts index ad0da07..85c753e 100644 --- a/libs/users/application/src/lib/use-cases/get-user-by-email.use-case.spec.ts +++ b/libs/users/application/src/lib/use-cases/get-user-by-email.use-case.spec.ts @@ -26,7 +26,7 @@ describe('GetUserByEmailUseCase', () => { const result = await getUserByEmailUseCase.execute('test@example.com'); expect(result).toEqual(mockUser); - expect(usersRepository.findByEmail).toHaveBeenCalledWith('1'); + expect(usersRepository.findByEmail).toHaveBeenCalledWith("test@example.com"); }); it('should return null when user not found', async () => { @@ -35,7 +35,7 @@ describe('GetUserByEmailUseCase', () => { const result = await getUserByEmailUseCase.execute('test@example.com'); expect(result).toBeNull(); - expect(usersRepository.findByEmail).toHaveBeenCalledWith('1'); + expect(usersRepository.findByEmail).toHaveBeenCalledWith("test@example.com"); }); }); }); diff --git a/libs/users/application/src/lib/users.service.spec.ts b/libs/users/application/src/lib/users.service.spec.ts index 93e13a4..adb98d5 100644 --- a/libs/users/application/src/lib/users.service.spec.ts +++ b/libs/users/application/src/lib/users.service.spec.ts @@ -1,12 +1,12 @@ import { Test, TestingModule } from '@nestjs/testing'; -import { User } from '@users/domain'; - import { UsersService } from './users.service'; import { GetUserByIdUseCase } from './use-cases/get-user-by-id.use-case'; +import { GetUserByEmailUseCase } from './use-cases/get-user-by-email.use-case'; describe('UsersService', () => { let service: UsersService; let getUserByIdUseCase: GetUserByIdUseCase; + let getUserByEmailUseCase: GetUserByEmailUseCase; beforeEach(async () => { const module: TestingModule = await Test.createTestingModule({ @@ -18,59 +18,69 @@ describe('UsersService', () => { execute: jest.fn(), }, }, + { + provide: GetUserByEmailUseCase, + useValue: { + execute: jest.fn(), + }, + }, ], }).compile(); service = module.get(UsersService); getUserByIdUseCase = module.get(GetUserByIdUseCase); + getUserByEmailUseCase = module.get(GetUserByEmailUseCase); }); - it('should be defined', () => { - expect(service).toBeDefined(); - }); - - describe('findById', () => { - it('should return a user if found', async () => { - const user: User = { + describe('getUserById', () => { + it('should return user when found', async () => { + const mockUser = { id: '1', email: 'test@example.com', firstName: 'John', lastName: 'Doe', }; - jest.spyOn(getUserByIdUseCase, 'execute').mockResolvedValue(user); + (getUserByIdUseCase.execute as jest.Mock).mockResolvedValue(mockUser); const result = await service.findById('1'); - expect(result).toEqual(user); + + expect(result).toEqual(mockUser); + expect(getUserByIdUseCase.execute).toHaveBeenCalledWith('1'); }); - it('should return null if user not found', async () => { - jest.spyOn(getUserByIdUseCase, 'execute').mockResolvedValue(null); + it('should return null when user not found', async () => { + (getUserByIdUseCase.execute as jest.Mock).mockResolvedValue(null); + + const result = await service.findById('1'); - const result = await service.findById('2'); expect(result).toBeNull(); + expect(getUserByIdUseCase.execute).toHaveBeenCalledWith('1'); }); }); - describe('findByEmail', () => { - it('should return a user if found', async () => { - const user: User = { + describe('getUserByEmail', () => { + it('should return user when found', async () => { + const mockUser = { id: '1', email: 'test@example.com', firstName: 'John', lastName: 'Doe', }; - jest.spyOn(getUserByIdUseCase, 'execute').mockResolvedValue(user); + (getUserByEmailUseCase.execute as jest.Mock).mockResolvedValue(mockUser); const result = await service.findByEmail('test@example.com'); - expect(result).toEqual(user); + + expect(result).toEqual(mockUser); + expect(getUserByEmailUseCase.execute).toHaveBeenCalledWith('test@example.com'); }); - it('should return null if user not found', async () => { - jest.spyOn(getUserByIdUseCase, 'execute').mockResolvedValue(null); + it('should return null when user not found', async () => { + (getUserByEmailUseCase.execute as jest.Mock).mockResolvedValue(null); const result = await service.findByEmail('test@example.com'); + expect(result).toBeNull(); + expect(getUserByEmailUseCase.execute).toHaveBeenCalledWith('test@example.com'); }); }); - });