To perform unit testing on a component that makes use of a service, that returns a promise, we can use fakeAsync() and spy() methods from Angular’s unit testing package.
user.component.ts
import { Component, OnInit } from '@angular/core';
import { UserService } from './user.service';
@Component({
selector: 'user-name',
templateUrl: './user.component.html',
styleUrls: ['./user.component.scss']
})
export class UserComponent implements OnInit {
userName = '';
constructor(private userService: UserService) { }
ngOnInit(): void {
this.userService.getUserName().then(response => this.userName = response);
}
}user.service.ts
import {Injectable} from '@angular/core';
import {HttpClient} from '@angular/common/http';
import 'rxjs/add/operator/toPromise';
@Injectable()
export class UserService {
constructor(private http: HttpClient) {
}
getUserName(): Promise<String> {
return this.http.get('http://localhost:3000/user/')
.toPromise();
}
}
user.component.html
<div class="user">
{{userName}}
</div>By default in the angular testing framework, changes in data aren’t reflected in the template (view) by default unless detectChanges( ) is explicitly called on the component.
user.component.spec.ts
import { async, fakeAsync, tick, ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { DebugElement } from '@angular/core';
import { UserComponent } from './user.component';
import { UserService } from './user.service';
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ UserComponent ],
providers: [ UserService ]
})
.compileComponents(); // compile external template and scss
}));
// Synchronous section
beforeEach(() => {
fixture = TestBed.createComponent(UserComponent);
comp = fixture.componentInstance;
// Inject UserService into the component
userService = fixture.debugElement.injector.get(UserService);
// Setup spy on the `getUserName` method
spy = spyOn(userService, 'getUserName')
.and.returnValue(Promise.resolve(userName));
// Get the Username element from the template DOM structure
un = fixture.debugElement.query(By.css('.user'));
elem = un.nativeElement;
});
it('should show username upon call return', fakeAsync(() => {
fixture.detectChanges(); // update view with data
tick(); // wait for all asynchronous calls to complete
fixture.detectChanges(); // update view with data
expect(elem.textContent).toBe(userName);
}));Note
tick( ) also takes milliseconds as argument, to wait for that time instead of waiting for all async calls to return.