I understand that the async
and fakeAsync
methods setup some kind of listener that records all async operations so that the angular testing framework can use whenStable
and tick()
to manage waiting for all that stuff to finish. I think thats correct?
The thing I am struggling to understand is whether there is actually an execution order difference - because if not why offer both?
This has brought me to learning about JS macro tasks and Micro tasks and I am wondering if this area is where the two approaches differ?
tl;dr. 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 Wraps a function to be executed in the fakeAsync zone: Microtasks are manually executed by calling flushMicrotasks() . Timers are synchronous; tick() simulates the asynchronous passage of time.
The tick() function simulates the asynchronous passage of time for the timers in the fakeAsync zone in Angular test.
Here's an abstract from Testing Asynchronous Code - CodeCraft
async
+ whenStable
:Consider this piece of code:
it('Button label via async() and whenStable()', async(() => {
fixture.detectChanges();
expect(el.nativeElement.textContent.trim()).toBe('Login');
spyOn(authService, 'isAuthenticated').and.returnValue(Promise.resolve(true));
fixture.whenStable().then(() => {
fixture.detectChanges();
expect(el.nativeElement.textContent.trim()).toBe('Logout');
});
component.ngOnInit();
}));
async
function executes the code inside its body in a special async
test zone. This intercepts and keeps track of all promises created in its body.
Only when all of those pending promises have been resolved does it then resolves the promise returned from whenStable
.
You can use this to avoid using Jasmine's spy mechanism of detecting when a promise has been resolved.
This mechanism is slightly better than using the plain Jasmine solution but there is another version which gives us fine grained control and also allows us to lay out our test code as if it were synchronous.
fakeAsync
+ tick
:Now consider this piece of code:
it('Button label via fakeAsync() and tick()', fakeAsync(() => {
expect(el.nativeElement.textContent.trim()).toBe('');
fixture.detectChanges();
expect(el.nativeElement.textContent.trim()).toBe('Login');
spyOn(authService, 'isAuthenticated').and.returnValue(Promise.resolve(true));
component.ngOnInit();
tick();
fixture.detectChanges();
expect(el.nativeElement.textContent.trim()).toBe('Logout');
}));
Just like async
, the fakeAsync
function executes the code inside its body in a special fake async
test zone. This intercepts and keeps track of all promises created in its body.
The tick()
function blocks execution and simulates the passage of time until all pending asynchronous activities complete.
So when we call tick()
the application sits and waits for the promises to be resolved and then lets execution move to the next line.
The main advantage of using this is that it makes the code more linear as if we were executing synchronous code, there are no callbacks to confuse the mind and everything is simpler to understand.
There are three mechanisms we can use to test asynchronous code:
The jasmine's done
function and spy callbacks. This works but expects us to know about all the promises in our application and be able to hook into them.
We can use the Angular async
and whenStable
functions, we don’t need to track the promises ourselves but we still need to lay our code out via callback functions which can be hard to read.
We can use the Angular fakeAsync
and tick
functions, this additionally lets us lay out our async
test code as if it were synchronous.
These points would make you think that why use async
+ whenStable
if it's hard to read. Why not simply use fakeAsync
+ tick
instead? Well one of the reasons would be beause of this:
Important
fakeAsync
does have some drawbacks, it doesn’t track XHR requests for instance.
You can read more about this on this GitHub Thread.
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