I'm trying to test a component. In another post I asked about testing the direct function call. Here I'm focusing, using same example component, on the error handling of my component.
I want to test, when my service returns an observable error, that my component properly calls console.error(error).
How to "create" this error trigger and test my component handles it properly. I heard about spies could do that but I don't know where to setup this spy.
I want to simulate the case where the http request on the service could fail. For any reason or any error code.
Here is the code for component, stub service and my spec files.
import { Component, OnInit, ViewContainerRef } from '@angular/core';
import { UserManagementService } from '../../shared/services/global.api';
import { UserListItemComponent } from './user-list-item.component';
@Component({
selector: 'app-user-list',
templateUrl: './user-list.component.html'
})
export class UserListComponent implements OnInit {
public userList = [];
constructor(
private _userManagementService: UserManagementService,
) { }
ngOnInit() {
this.getUserList();
}
onRefreshUserList() {
this.getUserList();
}
getUserList(notifyWhenComplete = false) {
this._userManagementService.getListUsers().subscribe(
result => {
this.userList = result.objects;
},
error => {
console.error(error); // That's the part of my component I want to test
},
() => {
if (notifyWhenComplete) {
console.info('Notification');
}
}
);
}
}
import { NO_ERRORS_SCHEMA } from '@angular/core';
import {
async,
fakeAsync,
ComponentFixture,
TestBed,
tick,
inject
} from '@angular/core/testing';
import { Observable } from 'rxjs/Observable';
// Components
import { UserListComponent } from './user-list.component';
// Services
import { UserManagementService } from '../../shared/services/global.api';
import { UserManagementServiceStub } from '../../testing/services/global.api.stub';
let comp: UserListComponent;
let fixture: ComponentFixture<UserListComponent>;
let service: UserManagementService;
describe('UserListComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [UserListComponent],
imports: [],
providers: [
{
provide: UserManagementService,
useClass: UserManagementServiceStub
}
],
schemas: [ NO_ERRORS_SCHEMA ]
})
.compileComponents();
}));
tests();
});
function tests() {
beforeEach(() => {
fixture = TestBed.createComponent(UserListComponent);
comp = fixture.componentInstance;
service = TestBed.get(UserManagementService);
});
it(`should be initialized`, () => {
expect(fixture).toBeDefined();
expect(comp).toBeDefined();
});
it(`should get the user List after ngOnInit`, async(() => {
fixture.detectChanges();
expect(comp.userList.length).toBe(3, 'user list exists after init');
}));
}
import { Observable } from 'rxjs/Observable';
export class UserManagementServiceStub {
getListUsers() {
return Observable.from([
{
count: 3,
objects:
[
{
id: "7f5a6610-f59b-4cd7-b649-1ea3cf72347f",
name: "user 1",
group: "any"
},
{
id: "d6f54c29-810e-43d8-8083-0712d1c412a3",
name: "user 2",
group: "any"
},
{
id: "2874f506-009a-4af8-8ca5-f6e6ba1824cb",
name: "user 3",
group: "any"
}
]
}
]);
}
}
If I'm correct in understanding that you just need a way to return an error from a stubbed service, you can just create a separate stub which returns an Observable error, and then use that in the test that checks for error handling:
export class UserManagementServiceErrorStub {
getListUsers() {
return Observable.throw(new Error('Test error'));
}
}
There is a really nice article on testing Angular services using Observables here: https://web.archive.org/web/20191214083526/http://www.zackarychapple.guru/angular2/2016/11/25/angular2-testing-services.html
Update - 01/06/2019 for RxJS 6
import { throwError } from 'rxjs';
class UserManagementServiceErrorStub {
getListUsers() {
return throwError(new Error('Test error'));
}
}