Angular - unit test for a subscribe function in a component
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);
}));
Related videos on Youtube
AngularM
Updated on November 10, 2021Comments
-
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 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 over 6 yearsActually 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 over 6 yearsThis worked! Do you think its a worthwhile test? Or should I only test my service rather than a component?
-
Sharikov Vladislav over 6 yearsI 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 over 4 yearsAnyone 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 over 4 yearswhat is the return type of getUsers method in User interface / class?
-
Sharikov Vladislav over 4 yearsAre 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 over 2 years:) thanks, for me instead of "subscribe", "then" worked fine, litle change :- fixture.whenStable().then((response) => { expect(homeComponent.listOfUsers).toEqual(response); done(); });