Hi, I came across https://github.com/thymikee/jest-preset-angular/issues/65 and I'm currently facing the exact same issue with "zone.js": "0.8.29" and "jest": "24.1.0", "jest-preset-angular": "6.0.2". Any idea how to solve that?
My test is broken and then it ends up with
Timeout - Async callback was not invoked within the 5000ms timeout specified by jest.setTimeout.Error: Timeout - Async callback was not invoked within the 5000ms timeout specified by jest.setTimeout.
Hi, would you please provide an example when it doesn't work ?
@ahnpnl just made a really simple repro here https://github.com/maxime1992/repro-jest-bug-fake-async
git clone [email protected]:maxime1992/repro-jest-bug-fake-async.git
cd repro-jest-bug-fake-async
yarn
yarn run test:watch
If anyone has any idea, I'd be glad to hear from you :smiley_cat:!
This is really a blocker to use Jest at all
It works for me, if I create the component that uses setTimeout in the constructor from inside the fakeAsync as well.
According to Angular docs (which itself points to a passage in the setup appendix), when using fakeAsync, zone.js/dist/zone-testing has to be imported in a setup file.
zone.js/dist/zone-testing is currently not usable with jest, as it patches jasmine.QueueRunner, which is obviously not available in jest.
Either we have to dive deeper into this and create some zone-testing on our own to patch setTimeout, or you have to call setTimeout inside fakeAsync only.
Please note that the example test repo https://github.com/maxime1992/repro-jest-bug-fake-async contains some errors:
Hi @wtho
Thanks for pointing out the errors, I've fixed them.
It works for me, if I create the component that uses setTimeout in the constructor from inside the fakeAsync as well
How can that work? I've tried it and yes it works. But why?
According to what you said, it shouldn't, should it?
zone.js/dist/zone-testing is currently not usable with jest, as it patches jasmine.QueueRunner, which is obviously not available in jest.
I have been able to fix the test with the following:
describe('AppComponent', () => {
let fixture: ComponentFixture<AppComponent>;
let app: AppComponent;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [AppComponent],
}).compileComponents();
}));
const setup = () => {
fixture = TestBed.createComponent(AppComponent);
app = fixture.debugElement.componentInstance;
};
it('should create the app', () => {
setup();
expect(app).toBeTruthy();
});
// following is not working
it('should change the title after 5s', fakeAsync(() => {
setup();
tick(10000);
expect(app.title).toBe('new title!');
}));
});
A bit annoying to not use the beforeEach and call the setup function all the time but I could live with that. I just wonder if that will work in all the cases, observables using delay for exemple etc.
A bit annoying to not use the
beforeEachand call thesetupfunction all the time but I could live with that. I just wonder if that will work in all the cases, observables usingdelayfor exemple etc.
I modified a bit your app.component.ts to add this:
ngOnInit() {
this.testObservable$.pipe(
delay(3000),
).subscribe(num => {
console.log('print number', num);
});
}
and in app.component.spec.ts I added this:
it('should print number every 3s', fakeAsync(() => {
setup();
fixture.detectChanges();
tick(3000);
expect(console.log).toHaveBeenCalledWith('print number', 1);
tick(3000);
expect(console.log).toHaveBeenCalledWith('print number', 2);
tick(3000);
expect(console.log).toHaveBeenCalledWith('print number', 3);
}));
It works perfectly.
Why does calling setup within the fakeAsync block
const setup = () => {
fixture = TestBed.createComponent(TestWrapperComponent);
component = fixture.componentInstance;
};
rather than having this same code in a beforeEach() block work? I'm struggling to understand
I don't understand either to be honest... If anyone understand why please share :smile_cat:
@maxime1992 I was able to fix your test by simply defining fixture and app - ideally this would be done inside a beforeEach:
it('should change the title after 5s', fakeAsync(() => {
fixture = TestBed.createComponent(AppComponent);
app = fixture.debugElement.componentInstance;
tick(5000);
expect(app.title).toBe('new title!');
}));
Also, you made a 10 second timeout in the app component, so obviously this would have to be less than or equal than 5000 for the test to pass.
Most helpful comment
I don't understand either to be honest... If anyone understand why please share :smile_cat: