Search code examples
angularjestjsngrxrxjs5ngrx-component-store

How can I unit test a component that uses NgrxLet LetDirective?


This is my stackblitz example where you can see in the terminal the test running and its result (or you can stop the execution and run jest).

I use the NgrxLet directive to consume the resulting observables in my components, like this:

myComponent.component.html

<ng-container *ngrxLet="myObs$ as myObs">
  <p> {{ myObs }} </p>
</ng-container>

myComponent.component.ts

@Component({
  selector: 'my-component',
  standalone: true,
  imports: [CommonModule, LetDirective],
  templateUrl: './my-component.component.html',
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class MyComponent implements OnInit {
  myObs$: Observable<string> = of('');
  myObsService = inject(MyObsService);
  ngOnInit() {
    this.myObs$ = this.myObsService.myObs$;
  }
}

However this creates an odd situation where the content of the ng-container *ngrxLet="myObs$ as myObs" never renders in my jest unit tests, even though this works perfectly during the execution.

I've tried a few solutions I could think of after going through Angular's component testing documentation :

const myObscontent = 'myObs content';
describe('myComponent tests', () => {
 beforeEach(async () => {
  await TestBed.configureTestingModule({
   imports: [LetDirective, MyComponent],
    providers: [
     { provide: MyObsService, useValue: {myObs$: of(myObsContent)}},
    ],
  }).compileComponents();

  fixture = TestBed.createComponent(MyComponent);
  component = fixture.componentInstance;
  fixture.detectChanges();
 })

 it('should show myObs content', async () => {
  await fixture.whenStable();
  expect(fixture.debugElement.nativeElement.textContent.includes(myObsContent))
   .toBeTruthy();
 })
})

👆 the rendered version never contains myObs content.

I've also tried using fakeAsync instead of async, and creating a behaviorSubject then pushing my observable value, to replace the cold observable created by of in my example above by a hot one.

The result in all the scenarios is that whatever lives inside of the ng-container *ngrxLet="myObs$ as myObs" and consumes myObs never renders.

is there any documentation about testing with Ngrx's LetDirective?

what are the alternatives?


Solution

  • Try fixture.whenStable, which strangely does not work with await but works great with .then(() => { ... }); syntax:

    it('should show the fact', (done) => {
      const staticText = 'outside of ngrxlet ng containerCat Fact: ';
      fixture.whenStable().then(() => {
        const compiled = fixture.nativeElement as HTMLElement;
        expect(compiled.textContent).toContain(`${staticText}${catFact}`);
        done();
      });
    });
    

    Stackblitz Demo