Angular - unit test for a subscribe function in a component

102,424

Solution 1

You need this for version rxjs@6 and above. For older rxjs version answer is below:

    import { of } from 'rxjs';

    it("should call getUsers and return list of users", async(() => {
      const response: User[] = [];

      spyOn(userService, 'getUsers').and.returnValue(of(response))

      homeComponent.getUsers();

      fixture.detectChanges();
    
      expect(homeComponent.listOfUsers).toEqual(response);
    }));

For old rxjs version change import from:

    import { of } from 'rxjs';

to

    import { of } from 'rxjs/observable/of';

Solution 2

I had similar issue and to make it work I used the arbitrary function (in the following code it's named done) inside of it


  it("should call getUsers and return list of users", async((done) => {
    // Arrange
    let response: User[] = [];

    // Act
    homeComponent.getUsers();

    fixture.detectChanges();
    fixture.whenStable().subscribe(() => {
        expect(homeComponent.listOfUsers).toEqual(response);
        done();
    });
  }));

Solution 3

in your case you can use fakeAsync also used tick() to detect change. you can add time to tick also to indicate how log to wait. eg tick(1000)

Code is modified from Sharikov Vladislav

import { fakeAsync, getTestBed, TestBed, tick } from '@angular/core/testing';

it("should call getUsers and return list of users", fakeAsync(() => {
  const response: User[] = [];
  spyOn(userService, 'getUsers').and.returnValue(of(response))
  homeComponent.getUsers();
  tick();
  expect(homeComponent.listOfUsers).toEqual(response);
}));
Share:
102,424

Related videos on Youtube

AngularM
Author by

AngularM

Updated on November 10, 2021

Comments

  • AngularM
    AngularM over 2 years

    Angular 4 unit test for a subscribe.

    I want to test that my subscribe returns an array of Users. I want to mock a list of users and test a function called getUsers.

    The subscribe unit test doesnt work. Something wrong with the syntax.

    This is my Users interface:

    export interface User {
      id: number;
      name: string;
      username: string;
      email: string;
      address: {
        street: string;
        suite: string;
        city: string;
        zipcode: string;
        geo: {
          lat: string;
          lng: string;
        }
      };
      phone: string;
      website: string;
      company: {
        name: string;
        catchPhrase: string;
        bs: string;
      };
    };
    

    This is my component I want to test:

    import { Component, OnInit } from "@angular/core";
    import { Observable } from "rxjs/Observable";
    
    import { UserService } from "../../services/user.service";
    import { User } from "../../models/user.model";
    
    @Component({
      selector: "home-users",
      templateUrl: "./home.component.html"
    })
    
    export class HomeComponent implements OnInit {
      private listOfUsers: User[];
    
      constructor(private userService: UserService) {
      }
    
      ngOnInit() {
        this.getUsers();
      }
    
      getUsers(): void {
        this.userService.getUsers().subscribe(users => {
          this.listOfUsers = users;
        });
      }
    }
    

    This is my unit test attempt:

    import { TestBed, async, inject } from "@angular/core/testing";
    import { HttpModule } from "@angular/http";
    
    import { HomeComponent } from "./home.component";
    import { UserService } from "../../services/user.service";
    import { User } from "../../models/user.model";
    
    describe("HomeComponent", () => {
      let userService;
      let homeComponent;
      let fixture;
      let element;
    
      beforeEach(async(() => {
        TestBed.configureTestingModule({
          declarations: [
            HomeComponent
          ],
          providers: [
            UserService
          ],
          imports: [HttpModule]
        }).compileComponents();
      }));
    
      beforeEach(inject([UserService], s => {
        userService = s;
        fixture = TestBed.createComponent(HomeComponent);
        homeComponent = fixture.componentInstance;
        element = fixture.nativeElement;
      }));
    
      it("should call getUsers and return list of users", async(() => {
        // Arrange
        let response: User[] = [];
    
        // Act
        homeComponent.getUsers();
    
        fixture.detectChanges();
        fixture.whenStable().subscribe(() => {
            expect(homeComponent.listOfUsers).toEqual(response);
        });
      }));
    });
    
    • AngularM
      AngularM over 6 years
      @Carsten the test doesnt work. Seems to be something wrong with the syntax for the subscribe part of the test
  • Sharikov Vladislav
    Sharikov Vladislav over 6 years
    Actually I can not try now :D Did this work? I added jest support and yesterday everything was working. But now I get some strange errors :)
  • AngularM
    AngularM over 6 years
    This worked! Do you think its a worthwhile test? Or should I only test my service rather than a component?
  • Sharikov Vladislav
    Sharikov Vladislav over 6 years
    I think you need test if you have some logic. For example you have some data received from server and you have server processing this data. This is critical logic and must not be broken. You have to unit test this. In your example: well why not if it is easy to test. This will defend future developers from accidently removing this subscription.
  • iBlehhz
    iBlehhz over 4 years
    Anyone has an error at of(response) in the spyOn line? mine is User[] not assignable to void.. how to resolve it since there is no return value supposedly?
  • Sharikov Vladislav
    Sharikov Vladislav over 4 years
    what is the return type of getUsers method in User interface / class?
  • Sharikov Vladislav
    Sharikov Vladislav over 4 years
    Are you sure you spy on the service? Component has the same getUsers method with void return type. Looks like you spied on the component method.
  • Shiv Gaurav
    Shiv Gaurav over 2 years
    :) thanks, for me instead of "subscribe", "then" worked fine, litle change :- fixture.whenStable().then((response) => { expect(homeComponent.listOfUsers).toEqual(response); done(); });