Search code examples
angularunit-testingjasminemockingangularfire2

Angular firebase - Unit testing a service using angularFireAuth


I have a core service that gets an instance of the firebase.auth obj and returns it with a getter. It is simple and looks as follows:

export class AuthService {

  ...
  constructor(private afAuth: AngularFireAuth,
              private afs: AngularFirestore) {
  ...
}

  public getAuthInstance(): FirebaseAuth {
    return this.afAuth.auth;
  }
}

Now I have a LoginService that needs the AuthService for logging into my app.

export class LoginService {

  constructor(private authService: AuthService) {
  }

  public login(email, password): Promise<UserCredential | string> {
    return this.authService.getAuthInstance().signInWithEmailAndPassword(email, password)
      .catch(() => Promise.reject('Login failed.'));
  }

Also not too complex. But now I want to test my login comp. - specifically the login method. I am not able to mock signInWithEmailAndPassword. I tried basically everything:

  • jasmine.spies
  • self created fake obj.

The test class looks as follows:

  ...
  const authStub: AuthService = jasmine.createSpyObj('AuthService', ['getAuthInstance']);
  const fireStub = {
    auth: {
      signInWithEmailAndPassword() {
        return Promise.resolve();
      }
    }
  };

  beforeEach(() => {
    TestBed.configureTestingModule({
      providers: [
        {provide: AuthService, useValue: authStub},
        {provide: AngularFireAuth, useValue: fireStub},
        LoginService
      ]
    });
  });

  const spy = it('should call signInWithPasswordAndEmail', inject([LoginService], (service: LoginService) => {
    (<jasmine.Spy>authStub.getAuthInstance).and.returnValue({username: 'test'});
    spyOn(fireStub.auth, 'signInWithEmailAndPassword').and.callThrough();


    service.login(email, password).then(() => expect(spy).toHaveBeenCalledTimes(1));
  }));

Can anyone help me to get this damn test green? xD^^ The Error msg. That ist thrown is: this.getAuthInstance().signInWithEmail.... Is Not a function


Solution

  • After some Trial and Error I mocked the AuthService indirectly with AngularFireAuth and AngularFireStore the test configuration looks as follows:

    describe('LoginService', () => {
    
      const email: string = 'email';
      const password: string = 'password';
    
      const authStub: any = {
        authState: {},
        auth: {
          signInWithEmailAndPassword() {
            return Promise.resolve();
          }
        }
      };
    
      beforeEach(() => {
        TestBed.configureTestingModule({
          providers: [
            {provide: AngularFireAuth, useValue: authStub},
            {provide: AngularFirestore},
            LoginService
          ]
        });
        authStub.authState = of(null);
      });
    
      it('should call signInWithPasswordAndEmail', inject([LoginService], (service: LoginService) => {
        const mock = TestBed.get(AngularFireAuth);
        const spy = spyOn(authStub.auth, 'signInWithEmailAndPassword').and.callThrough();
        mock.auth = authStub.auth;
    
        service.login(email, password);
    
        expect(spy).toHaveBeenCalledWith(email, password);
      }));
    });
    

    It gets the job done. If someone has a better solution, I would be pleased to know.