Reputation: 195
I keep running into this error when I try unit testing any of my functions that use a service in my component class. Here is a part of my function.
loadUser() {
this.httpService.getData(AppConfig.URL_UserById + "?UserID=" + this.userId)
.catch((error: Response | any) => {
this.showAlertWindow(this.exceptionMessage);
console.error(error.message || error);
return Observable.throw(error.message || error);
})
This part retrieves the data from a url and throws an error if there is a problem. getData is a service that makes a get request .I am just trying to test if the method showAlertWindow is being called. Now I am pretty sure my test code is correct but I have to be missing something to be receiving this error. I am guessing that jasmine does not know what to do with the line this.httpService.getData(...)
Thank you.
Test:
fit('should have getUsers() call showAlertWindow', () => {
let window = spyOn(userComponent, 'showAlertWindow');
userComponent.loadUser(); //Fails here
expect(window).toHaveBeenCalled();
})
Full Error:
Error: Cannot call Promise.then from within a sync test.
Error: Cannot call Promise.then from within a sync test.
at SyncTestZoneSpec.webpackJsonp../node_modules/zone.js/dist/zone-testing.js.SyncTestZoneSpec.onScheduleTask (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone-testing.js:365:1)
at ZoneDelegate.webpackJsonp../node_modules/zone.js/dist/zone.js.ZoneDelegate.scheduleTask (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone.js:401:1)
at Zone.webpackJsonp../node_modules/zone.js/dist/zone.js.Zone.scheduleTask (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone.js:232:1)
at Zone.webpackJsonp../node_modules/zone.js/dist/zone.js.Zone.scheduleMicroTask (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone.js:252:1)
at scheduleResolveOrReject (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone.js:862:1)
at ZoneAwarePromise.then (http://localhost:9876/_karma_webpack_/webpack:/node_modules/zone.js/dist/zone.js:962:1)
at ApplicationInitStatus.webpackJsonp../node_modules/@angular/core/esm5/core.js.ApplicationInitStatus.runInitializers (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/esm5/core.js:3580:1)
at TestBed.webpackJsonp../node_modules/@angular/core/esm5/testing.js.TestBed._initIfNeeded (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/esm5/testing.js:1011:1)
at TestBed.webpackJsonp../node_modules/@angular/core/esm5/testing.js.TestBed.get (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/esm5/testing.js:1050:1)
at Function.webpackJsonp../node_modules/@angular/core/esm5/testing.js.TestBed.get (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/esm5/testing.js:834:1)
If somebody can give me some insight on the meaning behind this error, that would be great. Thanks.
Test config:
import { HttpService } from '../../services/http.service';
import { TestBed, async, inject, fakeAsync, ComponentFixture } from "@angular/core/testing";
import { UserComponent } from './user.component';
import { Observable } from 'rxjs';
fdescribe('User Component', () => {
let httpService: HttpService;
let userComponent: UserComponent
beforeEach(async() => {
TestBed.configureTestingModule({
declarations: [
UserComponent,
],
providers: [
HttpService,
],
}).compileComponents();
});
beforeEach(() => {
userComponent = fixture.componentInstance;
httpService = TestBed.get(HttpService);
fit('should have getUsers() call showAlertWindow', () => {
let window = spyOn(userComponent, 'showAlertWindow');
userComponent.loadUser();
expect(window).toHaveBeenCalled();
})
Edit: There are two possible solutions. I solved the error by spying on my service and returning an observable. spyOn(httpService, 'getData).and.returnValue(Observable.of('test'));
Or JanRecker's solution, which is more practical.
Upvotes: 3
Views: 5167
Reputation: 1847
Did you mock your HttpService ?
If you instantiated your service in the UnitTests, than it will try to process this method. I assume, that in your HttpService you use the Angular HTTPClient Service (i think so because of the error "this.http.get")
Now, you instantiated your Service, but not its dependancies. And, in the UnitTests, you have to instantiate everything by hand. Therefore in your tests, there is no Angular "http" service up and running.
I have the habit to mock EVERYTHING away, that´s not my component/service under test. So in your case i would do something like
TestBed.configureTestingModule({
declarations: [YourComponentUnderTest],
providers: [
{provide: YourHttpService, useClass: MockYourHttpService}
]
});
let httpService = TestBed.get(YourHttpService);
MockYourHttpService would be a skeleton that looks like the original service, but without fancy implementations. Now you can mock that service as you like
spyOn(httpService, 'getData').and.returnValue(yourMockedData)
Alternatively you could import the HttpClientTestingModule, and mock the "this.http.get" call, but then your component Unit Test will implicitly test parts of your httpService.
warm regards
Upvotes: 6