I have a component with a setTimeOut function inside a ngOnInit function. To write unit test cases for that I'm using tick and fakeAsync to fast forward the setTimeOut. But, it's not getting executed which in turn is not calling other function closeAlert().
Component code:
export class BannerComponent implements OnInit {
@Input()errorData: any;
@Input()callback: any;
@Input()autoHide: boolean;
constructor() { }
ngOnInit() {
if (this.autoHide) {
setTimeout
(() => {
this.closeAlert();
}, 500);
}
}
closeAlert() {
this.errorData = null;
if (this.callback) {
this.callback();
}
};
}
Spec file:
describe('BannerComponent', () => {
let component: BannerComponent;
let fixture: ComponentFixture<BannerComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ BannerComponent ]
})
.compileComponents();
}));
beforeEach(async() => {
fixture = TestBed.createComponent(BannerComponent);
component = fixture.componentInstance;
component.ngOnInit();
fixture.detectChanges();
});
it("banner should hide after 500ms", fakeAsync(() => {
component.errorData = {
_statusMessage: "New alert banner",
_statusCode: '200',
};
component.callback = null;;
component.autoHide = true;
tick(600);
fixture.detectChanges()
fixture.whenStable().then(() => {
let banner = fixture.debugElement.query(By.css('.success'));
expect(banner).toBe(null)
})
}));
});
Html code:
<div class="success">
<p>{{errorData._statusMessage}}</p>
</div>
A couple of issues I saw with the code.
component.ngOnInit()
and fixture.detectChanges()
(which will also call ngOnInit) BEFORE you have set up valid data in component.errorData
.banner
to be null with the html you have shown. I therefore changed the test to seeing component.closeAlert()
had been called, and if component.errorData
had been reset to null, since it appears that is what you are really wanting to test. To test for this I spied on component.closeAlert()
.component.closeAlert()
by testing after tick(499)
, and then after one more tick ...Working StackBlitz.
Code:
beforeEach(async(() => { // slight correction of incorrect async wrapper ...
fixture = TestBed.createComponent(BannerComponent);
component = fixture.componentInstance;
// component.ngOnInit(); // <-- don't call this here, the data isn't set up yet ...
// fixture.detectChanges(); // ditto
}));
it("banner should hide after 500ms", fakeAsync(() => {
spyOn(component, 'closeAlert').and.callThrough(); // set up a spy so we can test later
component.errorData = {
_statusMessage: "New alert banner",
_statusCode: '200',
};
component.callback = null;;
component.autoHide = true;
fixture.detectChanges(); // <-- this will execute ngOnInit()
expect(component.errorData).not.toBeNull(); // <-- after ngOnInit, still NOT null
expect(component.closeAlert).not.toHaveBeenCalled();
tick(499); // <-- now let 499ms pass ...
expect(component.errorData).not.toBeNull(); // <-- after all that "fake" time, still NOT null
expect(component.closeAlert).not.toHaveBeenCalled();
tick(1); // <-- now tick for just 1 more millisecond ...
expect(component.errorData).toBeNull(); // <-- now this has become NULL
expect(component.closeAlert).toHaveBeenCalled(); // <-- and the method was called
// fixture.whenStable().then(() => {
// let banner = fixture.debugElement.query(By.css('.success'));
// expect(banner).toBe(null)
// });
}));
I hope this helps!