I'm trying to get the results from a mock backend in Angular 2 for unit testing. Currently, we are using fakeAsync
with a timeout to simulate the passing of time.
current working unit test
it('timeout (fakeAsync/tick)', fakeAsync(() => {
counter.getTimeout();
tick(3000); //manually specify the waiting time
}));
But, this means that we are limited to a manually defined timeout. Not when the async task is completed. What I'm trying to do is getting tick()
to wait until the task is completed before continuing with the test.
This does not seem to work as intended.
Reading up on the fakeAsync
and tick
the answer here explains that:
tick() simulates the asynchronous passage of time.
I set up a plnkr example simulating this scenario.
Here, we call the getTimeout()
method which calls an internal async task that has a timeout. In the test, we try wrapping it and calling tick()
after calling the getTimeout()
method.
counter.ts
getTimeout() {
setTimeout(() => {
console.log('timeout')
},3000)
}
counter.specs.ts
it('timeout (fakeAsync/tick)', fakeAsync(() => {
counter.getTimeout();
tick();
}));
But, the unit test fails with the error "Error: 1 timer(s) still in the queue."
Does the issue here in the angular repo have anything to do with this?
Is it possible to use tick()
this way to wait for a timeout function? Or is there another approach that I can use?
Try this:
Source
Async
test.service.ts
test.service.spec.ts
Fake Async
test.service.ts
test.service.spec.ts
The purpose of
fakeAsync
is to control time within your spec.tick
will not wait for any time as it is a synchronous function used to simulate the passage of time. If you want to wait until the asynchronous function is complete, you are going to need to useasync
andwhenStable
, however, in your example, the spec will take 3 seconds to pass so I wouldn't advise this.The reason why the counter.spec.ts is failing is that you have only simulated the passage of 0 seconds (typically used to represent the next tick of the event loop). So when the spec completes, there are still mocked timers active and that fails the whole spec. It is actually working properly by informing you that a timeout has been mocked an is unhandled.
Basically, I think you are attempting to use
fakeAsync
andtick
in ways for which they were not intended to be used. If you need to test a timeout the way that you have proposed, the simplest way would be to mock thesetTimeout
function yourself so that, regardless of the time used, you can just call the method.EDITED I ran into a related issue where I wanted to clear the timers, and since it was not the part under test, I didn't care how long it took. I tried:
Which worked, but was super hacky. I ended up going with
And all of my timers were cleared.
At the end of each test add:
I normally use the flushMicrotasks method in my unit tests for use with my services. I had read that tick() is very similar to flushMicrotasks but also calls the jasmine tick() method.