Reputation: 141
I am struggling to write a successful test case for a following code.
In component.ts
id = 123456;
data = [];
constructor(private serv: ApiService){}
ngOnInint(){
getData(id);
}
getData(id){
this.serv.getRequest(url+id).subscribe({
(res){
this.data = res;
});
}
In spec.ts file
describe('component', () =>{
let component: DataComponent,
let fixture: ComponentFixture<OpenCasesComponent>;
let serv: ApiService;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports:[HttpClientTestingModule],
declartions:[DataComponent],
Providers: [ApiService]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.CreateComponent(DataComponent);
component = fixture.componentInstance;
apiService = TestBed.inject(ApiService);
fixture.detectChanges();
});
it('should make api call on load', fakeAsync(()=>{
component.id = '123456';
let fakeResponse = {
name: 'John';
}
component.ngOnInit();
fixture.detectChanges();
spyOn(component, 'getData').withArgs('123456').and.callThrough();
spyOn(apiService, 'getRequest')..and.returnValue(of(fakeResponse));
fixture.detectChanges();
tick();
expect(component.getData).toHaveBeenCalled();
expect(apiService.getRequest).toHaveBeenCalled();
expect(component.data).toContain(fakeResponse);
}));
}
Similar function call works with the similar code. Difference is, that func is triggered by a button click. My guess is I am not invoking the function here, if so How do I do it.
what am I doing wrong?
Upvotes: 0
Views: 387
Reputation: 18859
The main thing you should realize is that the first fixture.detectChanges()
you call is when ngOnInit
is called.
I will help you, try to follow the comments:
import { of } from 'rxjs';
.....
describe('component', () =>{
let component: DataComponent,
let fixture: ComponentFixture<OpenCasesComponent>;
// change the type of this line to be a spyObj
let serv: jasmine.SpyObj<ApiService>;
beforeEach(async () => {
// create a spy object where we will mock ApiService
// the first string argument is an identifier in case of errors
// and the 2nd array of strings are public methods that you would like to mock
serv = jasmine.createSpyObj<ApiService>('ApiService', ['getRequest']);
await TestBed.configureTestingModule({
// Pretty sure you don't need HttpClientTestingModule now
// imports:[HttpClientTestingModule],
// declarations is spelt wrong here
declarations:[DataComponent],
// lowercase p for providers here
// when the component requires ApiService, give it the value
// of this mock we just created
providers: [{ provide: ApiService, useValue: serv }],
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.CreateComponent(DataComponent);
component = fixture.componentInstance;
apiService = TestBed.inject(ApiService);
// this first fixture.detectChanges() we call is when ngOnInit is called
// so let's make sure the API call will work before it is called
// by providing fake data
serve.getRequest.and.returnValue(of({ name: 'John' }));
fixture.detectChanges();
});
it('should make api call on load', fakeAsync(()=>{
component.id = '123456';
let fakeResponse = {
name: 'John';
}
// spy before calling ngOnInit
spyOn(component, 'getData').and.callThrough();
component.ngOnInit();
fixture.detectChanges();
expect(component.getData).toHaveBeenCalled();
expect(serv.getRequest).toHaveBeenCalled();
expect(component.data).toContain(fakeResponse);
}));
}
If you don't want to make all of those changes, the following changes should suffice as well:
it('should make api call on load', fakeAsync(()=>{
component.id = '123456';
let fakeResponse = {
name: 'John';
}
// set your spies before calling ngOnInit !!
// try removing the withArgs here
spyOn(component, 'getData').and.callThrough();
spyOn(apiService, 'getRequest').and.returnValue(of(fakeResponse));
component.ngOnInit();
fixture.detectChanges();
fixture.detectChanges();
tick();
expect(component.getData).toHaveBeenCalled();
expect(apiService.getRequest).toHaveBeenCalled();
expect(component.data).toContain(fakeResponse);
}));
Upvotes: 1