问题
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>
回答1:
A couple of issues I saw with the code.
- You are calling both
component.ngOnInit()
andfixture.detectChanges()
(which will also call ngOnInit) BEFORE you have set up valid data incomponent.errorData
. - It is unclear to me why you are expecting
banner
to be null with the html you have shown. I therefore changed the test to seeingcomponent.closeAlert()
had been called, and ifcomponent.errorData
had been reset to null, since it appears that is what you are really wanting to test. To test for this I spied oncomponent.closeAlert()
. - I set up the ticks to show exactly when the call is made to
component.closeAlert()
by testing aftertick(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!
来源:https://stackoverflow.com/questions/54336414/angular-6-unit-test-ngoninit-with-a-settimeout-not-working