Угловой 6 модульный тест ngOnInit с setTimeOut не работает
У меня есть компонент с функцией setTimeOut внутри функции ngOnInit. Для написания модульных тестов для этого я использую tick и fakeAsync для быстрой пересылки setTimeOut. Но он не выполняется, что, в свою очередь, не вызывает другую функцию closeAlert().
Код компонента:
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 файл:
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-код:
<div class="success">
<p>{{errorData._statusMessage}}</p>
</div>
1 ответ
Решение
Пара проблем, которые я видел с кодом.
- Вы звоните обоим
component.ngOnInit()
а такжеfixture.detectChanges()
(который также будет вызывать ngOnInit) ДО того, как вы установили действительные данные вcomponent.errorData
, - Мне непонятно, почему вы ожидаете
banner
быть нулевым с HTML, который вы показали. Поэтому я изменил тест, чтобы увидетьcomponent.closeAlert()
был вызван, и еслиcomponent.errorData
был сброшен в ноль, так как кажется, что вы действительно хотите проверить. Чтобы проверить это, я следил заcomponent.closeAlert()
, - Я установил галочки, чтобы показать, когда именно
component.closeAlert()
путем тестирования послеtick(499)
а потом еще через одну галочку...
Рабочая StackBlitz.
Код:
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)
// });
}));
Надеюсь, это поможет!