Reputation: 119
Consider the following code:
app.component.ts
@Component({
selector: 'app-component',
templateUrl: './app-component.html',
styleUrls: ['./app-component.scss']
})
export class AppComponent implements OnInit {
constructor(
private userService: UserService
) { }
ngOnInit() {}
}
app.component.html
<div *ngIf="userService.isUserLoggedIn$ | async">
<span class="username">{{(userService.user$ | async)?.name}}</span>
</div>
This is a simplification for one of my components. I tried to write a basic unit test:
it('should display the username', () => {
userService.isUserLoggedIn$ = cold('-a|', {a: true});
userService.user$ = cold('-a|', {a: {name: 'foo'});
fixture.detectChanges();
getTestScheduler().flush();
fixture.detectChanges();
const el = fixture.debugElement.query(By.css('.username')).nativeElement as HTMLSpanElement;
expect(el.innerText.trim()).toBe('foo);
});
I'm using the jasmine marbles library.
The problem is that the span doesn't have the correct value, it's always empty. I guess is because of the 2 nested async pipes. After the observables are flushed, the ngIf condition becomes true, the span is created and a new subscription for the user$ is created. But because the observable completed, the span will be empty.
I'm not sure if this is the correct explanation...
My question is how should I test this kind of scenario?
Thanks!
Upvotes: 1
Views: 399
Reputation: 18859
Defining userService.isUserLoggedIn$ = cold('-a|', {a: true});
and userService.user$ = cold('-a|', {a: {name: 'foo'});
after TestBed.configureTestingModule
is too late. These values have already been injected and isUserLoggedIn$
and user$
are values that are "static". Setting them at a later point in time doesn't tell the observable sequence to update this (no emissions happen).
When you mock userService
, attach the isUserLoggedIn$
and user$
before the TestBed.configureTestingModule
.
Upvotes: 1