Search code examples
angularangular-testjasmine-marbles

Jasmine marble testing observable with ngIf async pipe


I want to test an Observable with jasmine-marble testing, but unfortunately I can't figure out how to trigger change detection for ngIf, which should render the component.

This is a simplified version of my class:

export class MyComponent implements OnInit {
  data$: Observable<{data: any[]}>;

  constructor(private baseService: BaseService) { }

  ngOnInit(): void {
    this.data$ = this.baseService.get(endpoint);
  }
}

And my html file:

<custom-component *ngIf="data$ | async as value" [data]="value.data">
    ...
</custom-component>

This is my current test, which fails:

it ('should display custom component', fakeAsync(() => {
    const expected = cold('a|',  {a: {data: [{id: 1}]}});
    baseServiceStub.get.and.returnValue(expected);
    component.ngOnInit();
    fixture.detectChanges();
    tick();
    expect(component.data$).toBeObservable(expected); // this passes and the observable also holds the correct value
    expect(baseService.get).toHaveBeenCalledWith(endpoint); // this passes aswell
    component.data$.subscribe(val => {
      console.log(val); // here I can log the correct value of the observable ( {data: [{id:1}]})
    });
    expect(fixture.debugElement.query(By.css('custom-component'))).not.toBeNull(); // this fails
}));

Unfortunately everything I got is this

Error: Expected null not to be null.

There's no issue with the service or the observable itself, but it seems to me that for some reason the DOM doesn't trigger change detection with the async pipe which would render the component.

PS: When I am using getTestScheduler().flush() I get the error Can't subscribe to undefined instead.


Solution

  • I solved it by creating another test suite, where I defined a value for the observable manually. I'm not entirely happy with this approach but it is a workaround for my problem.