Search code examples
angulartypescriptrxjsjasmineangular-test

How to test pending flag in Angular


I have fetchBooks method that retrieve data from backend and then populates books variable.

import { Component, OnInit } from "@angular/core";

@Component({
  selector: "app-root",
  templateUrl: "./app.component.html",
})
export class AppComponent implements OnInit {
  isLoading: boolean;
  books;

  constructor(private booksService: BooksService) {}

  ngOnInit() {
    this.fetchBooks();
  }

  fetchBooks(): void {
    this.isLoading = true;
    this.booksService
      .fetchBooks()
      .subscribe(
        response => {
          this.isLoading = false;
          this.books = response.data;
          // ..
        },
        error => {
          this.isLoading = false;
          // ..
        }
      );
  }
}

I need to write unit tests for isLoading flag. I wrote something like this

it('should work', async () => {
  sut.fetchBooks();

  // ...
  expect(sut.isLoading).toBe(true);
  // ...
  expect(sut.isLoading).toBe(false);
});

But I struggle with the rest. Maybe someone knows how to solve it or knows some article that explains it?


Solution

  • My solution is to make use of a Subject to control the emission of values. Pass subject.asObservable() to the spy which your SUT is subscribing to.

    import { Subject } from 'rxjs';
    
    it('should correctly work', () => {
      // replace SomeType with the type returned by booksService.fetchData()
      const subject = new Subject<SomeType>();
      spyOn(booksService, 'fetchData').and.returnValue(subject.asObservable());
      const mockData: SomeType = {}; // put some data here, same type;
    
      // bonus, you may want to check also that isLoading is initially false
      // expect(sut.isLoading).toBe(false);
    
      // check: after triggered, isLoading should be true until the subscription returns a value
      sut.ngOnOnit();
      expect(sut.isLoading).toBe(true);
    
      // check: after the subscription receives a value, isLoading should be false
      subject.next(mockData);
      expect(sut.isLoading).toBe(false);
    
      // bonus
      expect(sut.data).toEqual(mockData);
      expect(booksService.fetchData).toHaveBeenCalledTimes(1);
    });