I'm trying to test if a service method is called from ngOnInit. However, I get a strange behavior: the method is not called although ngOnInit is executed.
import { Component } from '@angular/core';
import { SampleService } from './sample.service';
@Component({
selector: 'app-sample',
templateUrl: './sample.component.html',
styleUrls: ['./sample.component.css']
})
export class SampleComponent {
todos:any;
constructor(private service: SampleService){}
ngOnInit(){
this.todos = 'A';
this.service.getAll().subscribe(
res => {
this.todos = res;
}
);
}
}
describe('SampleComponent', () => {
let component: SampleComponent;
let fixture: ComponentFixture<SampleComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [ HttpClientModule ],
declarations: [ SampleComponent ],
providers: [ SampleService ]
})
.compileComponents();
fixture = TestBed.createComponent(SampleComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should load todos from the server', () => {
let todos = [1,2,3];
let service = TestBed.inject(SampleService);
spyOn(service,'getAll').and.returnValue(of(todos));
fixture.detectChanges();
//component.ngOnInit();
expect(component.todos).toEqual(todos);
});
});
If I test this code, the test fails and it return the message "Expected 'A' to equal [ 1, 2, 3 ]". So 'ngOnInit' is executed but the method 'getAll' is not called.
However, if I uncomment 'component.ngOnInit()', so I call ngOnInit manually, the test works perfectly (it returns a SUCCESS message).
Do you understand why this happens? Why getAll is not called?
More information:
I tried to edit my test to make it easier to understand the issue. Now I use toHaveBeenCalledWith()
to test if the method is called. And, like I supposed, it is not called at all, even though ngOnInit is executed. With the following test I get the message: Expected spy getAll to have been called once. It was called 0 times. However, uncommenting component.ngOnInit()
, the method is called.
it('should load todos from the server', () => {
let todos = [1,2,3];
let service = TestBed.inject(SampleService);
let spy = spyOn(service,'getAll').and.returnValue(of(todos));
fixture.detectChanges();
//component.ngOnInit();
expect(spy).toHaveBeenCalledTimes(1);
});
I found a solution, so I decided to answer my own question.
I just copied the definition of fixture and component instance in my it()
method. So I redefine them before calling spyOn
and before executing fixture.detectChanges()
. Doing so, it works.
it('should load todos from the server', () => {
fixture = TestBed.createComponent(SampleComponent);
component = fixture.componentInstance;
let todos = [1,2,3];
let service = TestBed.inject(SampleService);
spyOn(service,'getAll').and.returnValue(of(todos));
fixture.detectChanges();
expect(component.todos).toEqual(todos);
});
I don't know whether this is a good practice or not, but for now it seems the only way to test ngOnInit
as integration test.