Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does fixture.whenStable() actually do anything in my angular tests if not within an async test execution zone?

Tags:

I have been reading a lot about angular testing lately and the pairs are always async+fixture.whenStable and fakeAsync+tick, however you can always call fixtrue.whenStable as it is not tightly coupled. If you call it when not using the async utility to track promises in a test zone will it actually do anything?

For example:

it('should be able to do this thing that needs some async setup', () => {             fixture.detectChanges();             fixture.whenStable().then() }); 

I understand the difference between FakeAsync/Tick and fixture.detectChanges. My question is regarding what fixture.whenstable will do when inside of a FakeAsync execution zone as an Async zone should keep track of async work allowing fixture.whenstable to hook into that tracking, at least as I understand it. Or indeed if used and not within an async execution zone at all.

So if fixture.whenstable is used inside a FakeAsync function, or a function that does not setup an async execution zone, will it work as intended?

like image 430
Craig Avatar asked Nov 26 '18 11:11

Craig


People also ask

What is the function of fixture detectChanges () in Angular?

fixture. detectChanges() tells Angular to run change-detection. Finally! Every time it is called, it updates data bindings like ng-if, and re-renders the component based on the updated data. Calling this function will cause ngOnInit to run only the first time it is called.

What is fixture in Angular testing?

Fixtures have access to a debugElement , which will give you access to the internals of the component fixture. Change detection isn't done automatically, so you'll call detectChanges on a fixture to tell Angular to run change detection.

Which of the following functions should be used to execute some piece of code before execution of each Jasmine test case in Angular?

You could write a setup function and call it at the beginning of each spec. But using Jasmine, you can declare code that is called before and after each spec, or before and after all specs. For this purpose, Jasmine provides four functions: beforeEach , afterEach , beforeAll and afterAll .

What is the difference between async ()' and fakeAsync?

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.


2 Answers

No the whenStable() does nothing if you test without async or fakeAsync. What whenStable() does is to wait for all tasks in the test NgZone to complete. When you don't test with async the NgZone does not get created at all and whenStable() just returns immediately.

If you want more detail check the code for ComponentFixture in GitHub.

like image 152
AlesD Avatar answered Dec 24 '22 01:12

AlesD


The accepted answer may have been correct when it was written, but as of late 2020, when using node_modules/zone.js/bundles/zone-testing.umd.js, I don't think it is anymore. I can't find a citation in the docs, but I can confirm experimentally that a test zone is always used, and that whenStable waits for its tasks to complete.

This is very simple to try for yourself. Just create an empty test, and add

//// In my.component.ts import { timer } from "rxjs"; import { map } from "rxjs/operators";  @Component({   template: `<p>{{clock|async}}</p>`,   // ... }) export class MyComponent {   /** @internal */ public readonly clock = timer(0,1000).pipe(map(() => new Date())); }   //// In `my.component.spec.ts` beforeEach(async () => {     testBed.configureTestingModule(...);     await testBed.compileComponents();     fixture = testBed.createComponent(MyComponent);     await fixture.whenStable(); }); 

Because rxjs timer uses setInterval under the hood, it's flagged as always having a pending task, so whenStable never resolves. Jasmine will fail with a timeout, waiting for the Promise returned by the setup method to resolve. (Ask me how I discovered this...)

like image 21
Coderer Avatar answered Dec 24 '22 02:12

Coderer