import { Test , TestingModule } from '@nestjs/testing' ; import { ConfigService } from '@fc/config' ; import { LoggerService } from '@fc/logger' ; import { CryptographyGatewayException , CryptographyInvalidPayloadFormatException , } from '../exceptions' ; import { OverrideCode } from '../helpers' ; import { CryptoOverrideService } from './crypto-override.service' ; describe ( 'CryptoOverrideService' , ( ) => { let service ; const configServiceMock = { get : jest . fn ( ) , } ; const loggerServiceMock = { setContext : jest . fn ( ) , debug : jest . fn ( ) , trace : jest . fn ( ) , } ; const messageMock = { pipe : jest . fn ( ) , } ; const brokerMock = { send : jest . fn ( ) , connect : jest . fn ( ) , close : jest . fn ( ) , } ; const pipeMock = { subscribe : jest . fn ( ) , } ; const brokerResponseMock = 'brokerResponseMock' ; const OverrideCodeSpy = jest . spyOn ( OverrideCode , 'override' ) ; beforeEach ( async ( ) => { const module = await Test . createTestingModule ( { providers : [ CryptoOverrideService , ConfigService , LoggerService , { provide : 'CryptographyBroker' , useValue : brokerMock , } , ] , } ) . overrideProvider ( LoggerService ) . useValue ( loggerServiceMock ) . overrideProvider ( ConfigService ) . useValue ( configServiceMock ) . compile ( ) ; service = module . get < CryptoOverrideService > ( CryptoOverrideService ) ; jest . resetAllMocks ( ) ; brokerMock . send . mockReturnValue ( messageMock ) ; messageMock . pipe . mockReturnValue ( pipeMock ) ; pipeMock . subscribe . mockImplementation ( ( { next } ) => next ( brokerResponseMock ) ) ; configServiceMock . get . mockReturnValue ( { payloadEncoding : 'base64' , requestTimeout : 200 , } ) ; } ) ; it ( 'should be defined' , ( ) => { expect ( service ) . toBeDefined ( ) ; } ) ; describe ( 'onModuleInit' , ( ) => { it ( 'should call OverrideCode 1 times' , ( ) => { const OVERRIDE_COUNT = 1 ; service . onModuleInit ( ) ; expect ( OverrideCodeSpy ) . toHaveBeenCalledTimes ( OVERRIDE_COUNT ) ; } ) ; it ( 'should call broker.connect' , ( ) => { service . onModuleInit ( ) ; expect ( brokerMock . connect ) . toHaveBeenCalledTimes ( 1 ) ; } ) ; } ) ; describe ( 'onModuleDestroy' , ( ) => { it ( 'should call broker.close' , ( ) => { service . onModuleDestroy ( ) ; expect ( brokerMock . close ) . toHaveBeenCalledTimes ( 1 ) ; } ) ; } ) ; describe ( 'crypto.sign' , ( ) => { it ( 'should call crypto Gateway High Service' , async ( ) => { const alg = 'alg' ; const payload = new Uint8Array ( [ 0 , 42 , 42 , 0 ] ) ; const key = Symbol ( 'key' ) ; service . sign = jest . fn ( ) ; await service [ 'crypto.sign' ] ( alg , payload , key ) ; expect ( service . sign ) . toHaveBeenCalledWith ( key , Buffer . from ( payload ) , alg ) ; } ) ; it ( 'should throw a CryptographyInvalidPayloadFormatException if the payload is not a Uint8Array' , async ( ) => { const alg = 'alg' ; const payload = '1, 2, 3, 4, 5' ; const key = Symbol ( 'key' ) ; service . sign = jest . fn ( ) ; await expect ( ( ) => service [ 'crypto.sign' ] ( alg , payload as unknown as Uint8Array , key ) ) . toThrow ( CryptographyInvalidPayloadFormatException ) ; } ) ; } ) ; describe ( 'sign' , ( ) => { const keyMock = 'key' ; const dataMock = Buffer . from ( 'data' ) ; const digestMock = 'digest' ; it ( 'should return a `Promise` in case of success' , async ( ) => { const result = service . sign ( keyMock , dataMock , digestMock ) ; expect ( result instanceof Promise ) ; expect ( loggerServiceMock . debug ) . toHaveBeenCalledTimes ( 2 ) ; await result ; } ) ; it ( 'should call reject and throw a `CryptoOverrideService` exception in case of failure' , async ( ) => { const badKeyMock = null ; const badDataMock = null ; await expect ( service . sign ( badKeyMock , badDataMock ) ) . rejects . toThrow ( CryptographyGatewayException ) ; } ) ; it ( 'should call signSuccess with error message' , async ( ) => { const resolveMock = jest . fn ( ) ; const rejectMock = jest . fn ( ) ; service [ 'signSuccess' ] ( resolveMock , rejectMock , 'ERROR' ) ; expect ( rejectMock ) . toHaveBeenCalledTimes ( 1 ) ; } ) ; it ( 'should reject if response is "ERROR"' , async ( ) => { const rejectMock = jest . fn ( ) ; const signSuccessMock = jest . spyOn < CryptoOverrideService , any > ( service , 'signSuccess' ) ; pipeMock . subscribe . mockImplementationOnce ( ( { next } ) => { const call = next . bind ( service ) ; call ( null , rejectMock , 'ERROR' ) ; } ) ; await expect ( service . sign ( keyMock , dataMock , digestMock ) ) . rejects . toThrow ( CryptographyGatewayException ) ; expect ( loggerServiceMock . debug ) . toHaveBeenCalledTimes ( 2 ) ; expect ( signSuccessMock ) . toHaveBeenCalledTimes ( 1 ) ; } ) ; it ( 'should reject if something turned bad' , async ( ) => { pipeMock . subscribe . mockImplementationOnce ( ( ) => { throw new CryptographyGatewayException ( ) ; } ) ; await expect ( service . sign ( keyMock , dataMock ) ) . rejects . toThrow ( CryptographyGatewayException ) ; } ) ; it ( 'should reject if observable throws' , async ( ) => { const error = Error ( 'not good' ) ; pipeMock . subscribe . mockImplementationOnce ( ( { next : _success , error : failure } ) => failure ( error ) ) ; await expect ( service . sign ( keyMock , dataMock ) ) . rejects . toThrow ( CryptographyGatewayException ) ; } ) ; } ) ; } ) ;