Reputation: 45
I have a component that uses a service to retrieve information. But that service also gets configs from Configuration Service from a static variable conf. When running karma tests the const variable is undefined.
I am aware that I can create mock service, however shall I create 2 services to test this component? And if yes, I have other services that also use Configuration Service, so I have to create mock service for each of them? Seems like lots of work, but I haven't found a better solution :( I provided both ConfigurationService and the Service I am using if that that makes any difference.
TypeError: Cannot read property 'apiUrl' of undefined
apiUrl is a property of conf that is a static variable in ConfigurationService.
ConfigService.ts
import {Injectable} from '@angular/core';
import {HttpClient} from '@angular/common/http';
import * as YAML from 'js-yaml';
import {Config} from './models/Config';
@Injectable()
export class ConfigService {
public static conf: Config;
constructor(private http: HttpClient) {}
async load() {
const res = await this.http.get<Config>('assets/config.yml', {responseType: 'text' as 'json'}).toPromise();
ConfigService.conf = YAML.load(res).environment;
}
}
InfoService.ts
export class InfoService {
private InfoUrl = ConfigService.conf.apiUrl + '/info';
constructor(private http: HttpClient) {}
getInfo(){
return http.get(InfoUrl);
}
}
InfoComponent.ts
export class InfoComponent implements OnInit {
private info;
constructor(private infoService: InfoService) {}
ngOnInit() {}
loadInfo() {
this.info = this.infoService.getInfo();
}
InfoComponent.spec.ts
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { InfoComponent } from './info.component';
import {HttpClientModule} from '@angular/common/http';
import {InfoService} from './info.service';
import {ConfigService} from '../shared/config.service';
describe('InfoComponent', () => {
let component: InfoComponent;
let fixture: ComponentFixture<InfoComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [HttpClientModule],
declarations: [InfoComponent],
providers: [
ConfigService
InfoService,
],
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(InfoComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
Upvotes: 1
Views: 810
Reputation: 17494
Basically your component needs InfoService
. The core concept of Unit testing revolves around isolating the target code and test it. So, in your case, you dont need to create dependency on ConfigService
. There should be a separate Unit test to test the behavior of ConfigService
class InfoServiceStub {
getInfo(){
return of({
/// your mock data
});
}
}
describe('InfoComponent', () => {
let component: InfoComponent;
let fixture: ComponentFixture<InfoComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [HttpClientModule],
declarations: [InfoComponent],
providers: [
{provide: InfoService, useClass: InfoServiceStub },
],
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(InfoComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
Upvotes: 1