import { createMock } from '@golevelup/nestjs-testing' ; import { Test , TestingModule } from '@nestjs/testing' ; import * as bcrypt from 'bcrypt' ; import { of } from 'rxjs' ; import { GoogleUserService } from '../google-user/google-user.service' ; import { GoogleUser } from './user/models/google-user.model' ; import { UserService } from './user/user.service' ; import { AuthService } from './auth.service' ; import { GoogleSub } from './models/google.payload' ; const passVal = 'Pa$$w0rd' ; const badPassVal = 'Passw0rd' ; const email = 'test@test.com' ; const mockGoogleUser = { id : 'USR-id' , email , roles : [ 'player' ] , googleId : 'Google Id' , firstName : 'test' , lastName : 'test' , } ; const userObserver = ( done ) => ( { next ( token ) { expect ( token ) . toEqual ( { id : 'USR-TEST' } ) ; } , error ( error ) { throw error ; } , complete ( ) { done ( ) ; } , } ) ; const errorObserver = ( done , errorValue ) => ( { next ( value ) { throw new Error ( 'Expected null got value: ' + value ) ; } , error ( error ) { expect ( error . message ) . toEqual ( errorValue ) ; done ( ) ; } , complete ( ) { done ( ) ; } , } ) ; const googleSubscriber = ( done , spy , callTimes ) => ( { next : ( val ) => { expect ( val ) . toEqual ( mockGoogleUser ) ; } , error : ( err ) => { throw err ; } , complete : ( ) => { expect ( spy ) . toBeCalledTimes ( callTimes ) ; done ( ) ; } , } ) ; describe ( 'AuthService' , ( ) => { let service ; let module ; beforeEach ( async ( ) => { module = await Test . createTestingModule ( { providers : [ AuthService , { provide : UserService , useValue : { getByEmail : jest . fn ( ) . mockReturnValue ( of ( { id : 'USR-TEST' , email , role : [ 'player' ] , password : passVal , } ) ) , insertUser : jest . fn ( ) . mockReturnValue ( of ( { id : 'USR-TEST' , } ) ) , } , } , { provide : GoogleUserService , useValue : { getByGoogleId : jest . fn ( ) . mockReturnValue ( of ( { } ) ) , createNewGoogleUser : jest . fn ( ) . mockReturnValue ( of ( { } ) ) , } , } , ] , } ) . compile ( ) ; service = module . get < AuthService > ( AuthService ) ; } ) ; it ( 'should be defined' , ( ) => { expect ( service ) . toBeDefined ( ) ; } ) ; describe ( 'Local Strategy' , ( ) => { describe ( 'login' , ( ) => { let compareSpy ; beforeEach ( ( ) => { compareSpy = jest . spyOn ( bcrypt , 'compare' ) ; } ) ; afterEach ( ( ) => { jest . clearAllMocks ( ) ; } ) ; it ( 'should return a token' , ( done ) => { compareSpy . mockResolvedValueOnce ( true ) ; service . login ( { email , password : passVal } ) . subscribe ( userObserver ( done ) ) ; } ) ; it ( 'should throw an error' , ( done ) => { compareSpy . mockResolvedValueOnce ( false ) ; service . login ( { email , password : badPassVal } ) . subscribe ( errorObserver ( done , { statusCode : 401 , error : 'Unauthorized' , message : 'Invalid email or password.' , } ) ) ; } ) ; } ) ; describe ( 'signup' , ( ) => { const signupTest = { email , password : passVal , confirmationPassword : passVal , consentToEmail : true , role : [ 'player' ] , firstName : 'Tester' , lastName : 'McTesting' , } ; it ( 'should allow a user to signup' , ( done ) => { const userService = module . get < UserService > ( UserService ) ; jest . spyOn ( userService , 'getByEmail' ) . mockReturnValueOnce ( of ( undefined ) ) ; service . signup ( signupTest ) . subscribe ( userObserver ( done ) ) . unsubscribe ( ) ; } ) ; it ( 'should throw an error for same email address' , ( done ) => { service . signup ( signupTest ) . subscribe ( errorObserver ( done , { statusCode : 400 , error : 'Bad Request' , message : 'Email already in use' , } ) ) . unsubscribe ( ) ; } ) ; } ) ; } ) ; describe ( 'Google Strategy' , ( ) => { describe ( 'findOrCreateGoogleUser' , ( ) => { let googleService ; beforeEach ( ( ) => { googleService = module . get < GoogleUserService > ( GoogleUserService ) ; } ) ; afterEach ( ( ) => { jest . clearAllMocks ( ) ; } ) ; it ( 'should find and return a Google User' , ( done ) => { const getGoogleSpy = jest . spyOn ( googleService , 'getByGoogleId' ) . mockReturnValueOnce ( of ( mockGoogleUser ) ) ; service . findOrCreateGoogleUser ( createMock < GoogleSub > ( ) ) . subscribe ( googleSubscriber ( done , getGoogleSpy , 1 ) ) ; } ) ; it ( 'should not find, but still create ad return a Google User' , ( done ) => { jest . spyOn ( googleService , 'getByGoogleId' ) . mockReturnValueOnce ( of ( undefined ) ) ; const createSpy = jest . spyOn ( googleService , 'createNewGoogleUser' ) . mockReturnValueOnce ( of ( mockGoogleUser ) ) ; service . findOrCreateGoogleUser ( createMock < GoogleSub > ( ) ) . subscribe ( googleSubscriber ( done , createSpy , 1 ) ) ; } ) ; } ) ; } ) ; } ) ;