Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the difference between angular testing async+whenStable and fakeAsync+tick?

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?

like image 747
Craig Avatar asked Nov 23 '18 09:11

Craig


People also ask

What is the difference between the async and fakeAsync utilities in Angular?

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.

What is fakeAsync in Angular testing?

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.

What is tick () in Angular?

The tick() function simulates the asynchronous passage of time for the timers in the fakeAsync zone in Angular test.


1 Answers

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.

Conclusion:

There are three mechanisms we can use to test asynchronous code:

  1. 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.

  2. 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.

  3. 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.

like image 112
SiddAjmera Avatar answered Nov 01 '22 23:11

SiddAjmera