Background
I was trying to test my authService.getUserProfile()
function that looks like below
private authUserSubject$ = new BehaviorSubject<IUser | null>(null);
authUser$ = this.authUserSubject$.asObservable();
getUserProfile = () => this.httpClient.get<IUser>('/user').pipe(
tap(this.authUserSubject$.next)
);
I needed to test that when getUserProfile()
is called, then authUser$
is an Observable that has the user object
To achieve this I used the below code
describe('function getUserProfile()' , () =>{
it('should return update authUser$ property', done => {
spyOn(httpClient, 'get').and.returnValue(of({name: 'John Doe'}))
service.getUserProfile().subscribe({
next: (res) => {
expect(res as any).toEqual({name: 'John Doe'});
done();
}
})
});
})
The above test fails
Uncaught TypeError: Cannot read property 'length' of undefined thrown
In the console log for my test I have
zone-evergreen.js:178 Uncaught TypeError: Cannot read property 'length' of undefined
at AuthService.next (:9876/_karma_webpack_/webpack:/node_modules/rxjs/_esm2015/internal/Subject.js:36)
at AuthService.next (:9876/_karma_webpack_/webpack:/node_modules/rxjs/_esm2015/internal/BehaviorSubject.js:30)
at TapSubscriber._next (:9876/_karma_webpack_/webpack:/node_modules/rxjs/_esm2015/internal/operators/tap.js:40)
at TapSubscriber.next (:9876/_karma_webpack_/webpack:/node_modules/rxjs/_esm2015/internal/Subscriber.js:49)
at Observable._subscribe (:9876/_karma_webpack_/webpack:/node_modules/rxjs/_esm2015/internal/util/subscribeToArray.js:3)
at Observable._trySubscribe (:9876/_karma_webpack_/webpack:/node_modules/rxjs/_esm2015/internal/Observable.js:42)
at Observable.subscribe (:9876/_karma_webpack_/webpack:/node_modules/rxjs/_esm2015/internal/Observable.js:28)
at DoOperator.call (:9876/_karma_webpack_/webpack:/node_modules/rxjs/_esm2015/internal/operators/tap.js:16)
at Observable.subscribe (:9876/_karma_webpack_/webpack:/node_modules/rxjs/_esm2015/internal/Observable.js:23)
at UserContext.<anonymous> (:9876/_karma_webpack_/webpack:/src/app/login/services/auth.service.spec.ts:38)
The above should have worked, In fact in the test coverage the code is covered in the testing. To try solve the problem I tried binding this
in my function like
getUserProfile = () => this.httpClient.get<IUser>('/user').pipe(
tap(this.authUserSubject$.next.bind(this)) // <-- This is line 38
);
Now I was so sure this will work but to my surprise same error. Finally I decided to try the expanded code i.e
getUserProfile = () => this.httpClient.get<IUser>('/user').pipe(
tap(res => this.authUserSubject$.next(res))
);
The above actually worked...
My question
What I am trying to understand is
Why would
tap(this.authUserSubject$.next.bind(this))
<-- Throws errortap(res => this.authUserSubject$.next(res))
<-- No error thrownWhere is the
length
property coming from?