import { mocked } from 'jest-mock' ; import { lastValueFrom } from 'rxjs' ; import { HttpService } from '@nestjs/axios' ; import { ValidationError } from '@nestjs/common' ; import { Test , TestingModule } from '@nestjs/testing' ; import { validateDto } from '@fc/common' ; import { ConfigService } from '@fc/config' ; import { LoggerService } from '@fc/logger' ; import { CheckTokenResponseDto } from '../dto' ; import { CheckTokenFailedException , InvalidIdentityException , ReceivedInvalidScopeException , } from '../exceptions' ; import { DataProviderCoreAuthService } from './data-provider-core-auth.service' ; jest . mock ( '@fc/common' , ( ) => ( { ... ( jest . requireActual ( '@fc/common' ) as any ) , validateDto : jest . fn ( ) , } ) ) ; jest . mock ( 'rxjs' ) ; describe ( 'DataProviderCoreAuthService' , ( ) => { let service ; const validateDtoMock = mocked ( validateDto ) ; const lastValueFromMock = mocked ( lastValueFrom ) ; const checkTokenResponseMock = { scope : [ 'configuredScopeMockValue' ] , identity : { } , } as CheckTokenResponseDto ; const axiosResponseMock = { status : 200 , data : checkTokenResponseMock , } ; const configServiceMock = { get : jest . fn ( ) , } ; const configValueMock = { tokenEndpoint : 'tokenEndpointMockValue' , scope : 'configuredScopeMockValue' , } ; const loggerServiceMock = { setContext : jest . fn ( ) , trace : jest . fn ( ) , } ; const httpServiceMock = { post : jest . fn ( ) , } ; beforeEach ( async ( ) => { jest . resetAllMocks ( ) ; const module = await Test . createTestingModule ( { providers : [ DataProviderCoreAuthService , ConfigService , LoggerService , HttpService , ] , } ) . overrideProvider ( ConfigService ) . useValue ( configServiceMock ) . overrideProvider ( LoggerService ) . useValue ( loggerServiceMock ) . overrideProvider ( HttpService ) . useValue ( httpServiceMock ) . compile ( ) ; service = module . get < DataProviderCoreAuthService > ( DataProviderCoreAuthService ) ; configServiceMock . get . mockReturnValue ( configValueMock ) ; validateDtoMock . mockResolvedValue ( [ ] ) ; lastValueFromMock . mockResolvedValue ( axiosResponseMock ) ; } ) ; it ( 'should be defined' , ( ) => { expect ( service ) . toBeDefined ( ) ; } ) ; describe ( 'getIdentity' , ( ) => { const tokenMock = 'tokenMockValue' ; const checkTokenMock = jest . fn ( ) ; beforeEach ( ( ) => { service [ 'checkToken' ] = checkTokenMock ; checkTokenMock . mockResolvedValue ( checkTokenResponseMock ) ; } ) ; it ( 'should call checkToken() with token' , async ( ) => { await service . getIdentity ( tokenMock ) ; expect ( checkTokenMock ) . toHaveBeenCalledTimes ( 1 ) ; expect ( checkTokenMock ) . toHaveBeenCalledWith ( tokenMock ) ; } ) ; it ( 'should call validateDto with DTO and return from checkToken' , async ( ) => { await service . getIdentity ( tokenMock ) ; expect ( validateDtoMock ) . toHaveBeenCalledTimes ( 1 ) ; expect ( validateDtoMock ) . toHaveBeenCalledWith ( checkTokenResponseMock , CheckTokenResponseDto , expect . any ( Object ) ) ; } ) ; it ( 'should throw if DTO validation returns error' , async ( ) => { validateDtoMock . mockResolvedValueOnce ( [ { } as ValidationError ] ) ; await expect ( service . getIdentity ( tokenMock ) ) . rejects . toThrow ( InvalidIdentityException ) ; } ) ; it ( 'should call configService.get() with lib name' , async ( ) => { await service . getIdentity ( tokenMock ) ; expect ( configServiceMock . get ) . toHaveBeenCalledTimes ( 1 ) ; expect ( configServiceMock . get ) . toHaveBeenCalledWith ( 'DataProviderCoreAuth' ) ; } ) ; it ( 'should throw if received scope does not match configured scope' , async ( ) => { checkTokenMock . mockResolvedValueOnce ( { scope : [ 'invalidScopeReceivedMockValue' ] , identity : { } , } ) ; await expect ( service . getIdentity ( tokenMock ) ) . rejects . toThrow ( ReceivedInvalidScopeException ) ; } ) ; it ( 'should return identity' , async ( ) => { const result = await service . getIdentity ( tokenMock ) ; expect ( result ) . toBe ( checkTokenResponseMock . identity ) ; } ) ; } ) ; describe ( 'checkToken' , ( ) => { const tokenMock = 'tokenMockValue' ; it ( 'should call config with lib name' , async ( ) => { await service [ 'checkToken' ] ( tokenMock ) ; expect ( configServiceMock . get ) . toHaveBeenCalledTimes ( 1 ) ; expect ( configServiceMock . get ) . toHaveBeenCalledWith ( 'DataProviderCoreAuth' ) ; } ) ; it ( 'should call http.post with endpoint and body' , async ( ) => { await service [ 'checkToken' ] ( tokenMock ) ; expect ( httpServiceMock . post ) . toHaveBeenCalledTimes ( 1 ) ; expect ( httpServiceMock . post ) . toHaveBeenCalledWith ( configValueMock . tokenEndpoint , { token : tokenMock } ) ; } ) ; it ( 'should call lastValueFrom with return from http.post' , async ( ) => { const httpServiceMockPostResponse = { } ; httpServiceMock . post . mockReturnValueOnce ( httpServiceMockPostResponse ) ; await service [ 'checkToken' ] ( tokenMock ) ; expect ( lastValueFromMock ) . toHaveBeenCalledTimes ( 1 ) ; expect ( lastValueFromMock ) . toHaveBeenCalledWith ( httpServiceMockPostResponse ) ; } ) ; it ( 'should throw if response.status is different than 200' , async ( ) => { lastValueFromMock . mockResolvedValueOnce ( { status : 500 } ) ; await expect ( service [ 'checkToken' ] ( tokenMock ) ) . rejects . toThrow ( CheckTokenFailedException ) ; } ) ; it ( 'should throw if httpService throws' , async ( ) => { httpServiceMock . post . mockImplementationOnce ( ( ) => { throw new Error ( ) ; } ) ; await expect ( service [ 'checkToken' ] ( tokenMock ) ) . rejects . toThrow ( CheckTokenFailedException ) ; } ) ; it ( 'should throw response.data is falsy' , async ( ) => { lastValueFromMock . mockResolvedValueOnce ( { status : 200 } ) ; await expect ( service [ 'checkToken' ] ( tokenMock ) ) . rejects . toThrow ( CheckTokenFailedException ) ; } ) ; it ( 'should return response.data' , async ( ) => { const result = await service [ 'checkToken' ] ( tokenMock ) ; expect ( result ) . toBe ( axiosResponseMock . data ) ; } ) ; } ) ; } ) ;