import { CustomAuthentication } from '@/use-cases/authentication' ; import { AuthenticationResult } from '@/use-cases/authentication/ports' ; import { UserData , UserRepository } from '@/use-cases/ports' ; import { SignIn } from '@/use-cases/sign-in' ; import { SignInOperation , WebController } from '@/presentation/controllers' ; import { HttpRequest , HttpResponse } from '@/presentation/controllers/ports' ; import { UserBuilder } from '@test/builders' ; import { FakeTokenManager } from '@test/doubles/authentication' ; import { FakeEncoder } from '@test/doubles/encoder' ; import { InMemoryUserRepository } from '@test/doubles/repositories' ; import { MissingParamError } from '@/presentation/controllers/errors' ; import { UserNotFoundError , WrongPasswordError } from '@/use-cases/authentication/errors' ; import { ErrorThrowingUseCaseStub } from '@test/doubles/usecases/error-throwing-use-case-stub' ; describe ( 'Sign in controller' , ( ) => { test ( 'should return 200 if valid credentials are provided' , async ( ) => { const singleUserUserRepository = await getSingleUserUserRepository ( ) ; const validUser = UserBuilder . aUser ( ) . build ( ) ; const usecase = new SignIn ( new CustomAuthentication ( singleUserUserRepository , new FakeEncoder ( ) , new FakeTokenManager ( ) ) ) ; const validUserSignInRequest = { body : { email : validUser . email , password : validUser . password } } ; const controller = new WebController ( new SignInOperation ( usecase ) ) ; const response = await controller . handle ( validUserSignInRequest ) ; const authResult = response . body as AuthenticationResult ; expect ( response . statusCode ) . toEqual ( 200 ) ; expect ( authResult . id ) . toEqual ( validUser . id ) ; expect ( authResult . accessToken ) . toBeDefined ( ) ; } ) ; test ( 'should return 400 if email is missing in the request' , async ( ) => { const singleUserUserRepository = await getSingleUserUserRepository ( ) ; const validUser = UserBuilder . aUser ( ) . build ( ) ; const usecase = new SignIn ( new CustomAuthentication ( singleUserUserRepository , new FakeEncoder ( ) , new FakeTokenManager ( ) ) ) ; const signInRequestWithoutEmail = { body : { password : validUser . password } } ; const controller = new WebController ( new SignInOperation ( usecase ) ) ; const response = await controller . handle ( signInRequestWithoutEmail ) ; expect ( response . statusCode ) . toEqual ( 400 ) ; expect ( response . body ) . toBeInstanceOf ( MissingParamError ) ; expect ( ( response . body as Error ) . message ) . toEqual ( 'Missing parameter: email.' ) ; } ) ; test ( 'should return 400 if password is missing in the request' , async ( ) => { const singleUserUserRepository = await getSingleUserUserRepository ( ) ; const validUser = UserBuilder . aUser ( ) . build ( ) ; const usecase = new SignIn ( new CustomAuthentication ( singleUserUserRepository , new FakeEncoder ( ) , new FakeTokenManager ( ) ) ) ; const signInRequestWithoutPassword = { body : { email : validUser . email } } ; const controller = new WebController ( new SignInOperation ( usecase ) ) ; const response = await controller . handle ( signInRequestWithoutPassword ) ; expect ( response . statusCode ) . toEqual ( 400 ) ; expect ( response . body ) . toBeInstanceOf ( MissingParamError ) ; expect ( ( response . body as Error ) . message ) . toEqual ( 'Missing parameter: password.' ) ; } ) ; test ( 'should return 400 if password and email are missing in the request' , async ( ) => { const singleUserUserRepository = await getSingleUserUserRepository ( ) ; const usecase = new SignIn ( new CustomAuthentication ( singleUserUserRepository , new FakeEncoder ( ) , new FakeTokenManager ( ) ) ) ; const signInRequestWithoutEmailAndPassword = { body : { } } ; const controller = new WebController ( new SignInOperation ( usecase ) ) ; const response = await controller . handle ( signInRequestWithoutEmailAndPassword ) ; expect ( response . statusCode ) . toEqual ( 400 ) ; expect ( response . body ) . toBeInstanceOf ( MissingParamError ) ; expect ( ( response . body as Error ) . message ) . toEqual ( 'Missing parameter: email, password.' ) ; } ) ; test ( 'should return 403 if password is incorrect' , async ( ) => { const singleUserUserRepository = await getSingleUserUserRepository ( ) ; const validUser = UserBuilder . aUser ( ) . build ( ) ; const usecase = new SignIn ( new CustomAuthentication ( singleUserUserRepository , new FakeEncoder ( ) , new FakeTokenManager ( ) ) ) ; const signInRequestWithIncorrectPassword = { body : { email : validUser . email , password : 'incorrect password' } } ; const controller = new WebController ( new SignInOperation ( usecase ) ) ; const response = await controller . handle ( signInRequestWithIncorrectPassword ) ; expect ( response . statusCode ) . toEqual ( 403 ) ; expect ( response . body ) . toBeInstanceOf ( WrongPasswordError ) ; } ) ; test ( 'should return 400 if user is not found' , async ( ) => { const singleUserUserRepository = await getSingleUserUserRepository ( ) ; const anotherUser = UserBuilder . aUser ( ) . withDifferentEmail ( ) . build ( ) ; const usecase = new SignIn ( new CustomAuthentication ( singleUserUserRepository , new FakeEncoder ( ) , new FakeTokenManager ( ) ) ) ; const signInRequestWithUnregisteredUser = { body : { email : anotherUser . email , password : anotherUser . email } } ; const controller = new WebController ( new SignInOperation ( usecase ) ) ; const response = await controller . handle ( signInRequestWithUnregisteredUser ) ; expect ( response . statusCode ) . toEqual ( 400 ) ; expect ( response . body ) . toBeInstanceOf ( UserNotFoundError ) ; } ) ; test ( 'should return 500 if an error is raised internally' , async ( ) => { const validUser = UserBuilder . aUser ( ) . build ( ) ; const validUserSignInRequest = { body : { email : validUser . email , password : validUser . password } } ; const errorThrowingSignInUseCaseStub = new ErrorThrowingUseCaseStub ( ) ; const controllerWithStubUseCase = new WebController ( new SignInOperation ( errorThrowingSignInUseCaseStub ) ) ; const response = await controllerWithStubUseCase . handle ( validUserSignInRequest ) ; expect ( response . statusCode ) . toEqual ( 500 ) ; expect ( response . body ) . toBeInstanceOf ( Error ) ; } ) ; async function getSingleUserUserRepository ( ) { const aUser = UserBuilder . aUser ( ) . build ( ) ; const userDataArrayWithSingleUser = new Array ( { email : aUser . email , password : await new FakeEncoder ( ) . encode ( aUser . password ) , id : aUser . id } ) ; return new InMemoryUserRepository ( userDataArrayWithSingleUser ) ; } } ) ;