I'm trying to figure out what differentiates fakeAsync's tick()
method from done()
as suggested by some answers on stack overflow.
Using tick()
we can simulate a timeout, but can we accomplish the same using done()
?
Why does angular consider it more viable method than using async
or fakeAsync
?
Take for example.
This method works for me...
it("Should display names",(done:any) => {
component.names = [
{
"firstname": "abc",
"lastname": "max"
},
{
"firstname": "def",
"lastname": "max"
},
];
done();
fixture.detectChanges();
let wrapBox = fixture.debugElement.queryAll(By.css('.wrapBox'));
console.log(wrapBox);
});
But following method returns '6 timer(s) still in queue
' error...
it("Should display names",fakeAsync(() => {
component.names = [
{
"firstname": "abc",
"lastname": "max"
},
{
"firstname": "def",
"lastname": "max"
},
];
tick();
fixture.detectChanges();
let wrapBox = fixture.debugElement.queryAll(By.css('.wrapBox'));
console.log(wrapBox);
}));
Note:
The data for array names
is asynchronous since it's retrieved from back end using 'get' operation. But here i'm mocking the data.
The data in array is iterated through and passed to another child component which displays it in the view.
ticklink. Simulates the asynchronous passage of time for the timers in the fakeAsync zone.
In almost all cases, they can be used interchangeably, but using fakeAsync()/tick() combo is preferred unless you need to make an XHR call, in which case you MUST use async()/whenStable() combo, as fakeAsync() does not support XHR calls. For the most part they can be used interchangeably.
fakeAsynclink Timers are synchronous; tick() simulates the asynchronous passage of time.
Jasmine: Using fakeAsync() and flush() flush(), on the other hand, will apply the changes to the testing components that will in turn reflect the new changes to the testing component.
Those 2 things have nothing in common.
done
is just a callback to let your test runner know when an async operation is done.
For example:
it('should wait for this promise to finish', done => {
const p = new Promise((resolve, reject) =>
setTimeout(() => resolve(`I'm the promise result`), 1000)
);
p.then(result => {
// following will display "I'm the promise result" after 1s
console.log(result);
// this let your test runner know that it can move forward
// because we're done here
// the test will take 1s due to the setTimeout at 1000ms
done();
});
});
You might also use async
for that (just to avoid calling done
manually):
it(
'should wait for this promise to finish',
async(() => {
const p = new Promise((resolve, reject) =>
setTimeout(() => resolve(`I'm the promise result`), 1000)
);
p.then(result =>
// following will display "I'm the promise result" after 1s
console.log(result)
);
// notice that we didn't call `done` here thanks to async
// which created a special zone from zone.js
// this test is now aware of pending async operation and will wait
// for it before passing to the next one
})
);
Now, fakeAsync
gives you control over time (which is really powerful) so you can write your tests in a synchronous way, and simulate that time goes by to avoid waiting for setTimeout
for example:
it(
'should wait for this promise to finish',
fakeAsync(() => {
const p = new Promise((resolve, reject) =>
setTimeout(() => resolve(`I'm the promise result`), 1000)
);
// simulates time moving forward and executing async tasks
flush();
p.then(result =>
// following will display "I'm the promise result" **instantly**
console.log(result)
);
// notice that we didn't call `done` here has there's no async task pending
})
);
So just to be clear, with fakeAsync
in the last example, if the setTimeout was set on 10s, the test would still be executed instantly.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With