Search code examples
angularunit-testingjasmine2.0angular-test

Angular 6 - mock authState - valueChanges of undefined


I have a service with a property and a getter. The property is set in the service constructor like this:

public readonly usersMetaData: Observable<User | null>;

constructor(private afAuth: AngularFireAuth,
              private afs: AngularFirestore) {
    this.usersMetaData = this.afAuth.authState.pipe(switchMap((user: firebase.User) => {
        if (user) {
            return this.afs.doc<User>(`users/${user.uid}`).valueChanges();
        } else {
            return of(null);
        }
    }), share());
}

My getter just tests if the authstate returns a defined object basically (not null, not undefined):

public isAuthenticated(): Observable<boolean> {
    return this.usersMetaData.pipe(map(user => !!user));
}

Now for my unit test setup, I need to mock authState from firebase. It looks as follows:

  let service: AuthService;

  const authStub: any = {
    authState: {}
  };

  const storeStub = {
    doc() {
      return of(null);
    }
  };

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

    authStub.authState = of({username: 'test'});
    spyOn(storeStub, 'doc').and.stub();
    service = TestBed.get(AuthService);
  });

  it('should check for authentication - is authenticated', async(() => {
    service.isAuthenticated().subscribe(isUser => console.log(isUser)); <== should return true
  }));

The error that is returning is: Failed: Cannot read property 'valueChanges' of undefined Does anyone know how to mock authstate properly?


Solution

  • Almost right. The storeStub obj needs to be modified like this:

      const storeStub = {
        doc() {
          return {
            valueChanges() {
              return of({property: 'test'});
            }
          };
        }
      };
    

    since doc calls valueChanges you need to return valueChanges in your mocked object.