angular icon indicating copy to clipboard operation
angular copied to clipboard

APP_INITIALIZER contract not honoured with TestBed

Open victornoel opened this issue 6 years ago • 17 comments

I'm submitting a...


[ ] Regression (a behavior that used to work and stopped working in a new release)
[x] Bug report  
[ ] Performance issue
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question
[ ] Other... Please describe:

Current behavior

When importing a Module providing a promise-based APP_INITIALIZER into a TestBed, the tests are executed before the promise is fully resolved.

There was an issue for this very problem (#16204) but the reporter closed because he found a workaround.

Expected behavior

The promise of an APP_INITIALIZER should be fully resolved, exactly as when running the application that uses this module normally.

Minimal reproduction of the problem with instructions

Hadn't had the time, but I expect that it should be simple to know if is already implemented or not to behave like expected. If yes, I will produce a repro.

What is the motivation / use case for changing the behavior?

Same contract with tests or real app.

Environment


Angular version: 6.0.7

victornoel avatar May 31 '18 12:05 victornoel

For the record, a solution until this is fixed, is to add the following beforeEach in your jasmine tests (after compileComponents() and before createComponent() for example):

  beforeEach(async () => {
    // until https://github.com/angular/angular/issues/24218 is fixed
    await TestBed.get(ApplicationInitStatus).donePromise;
  });

victornoel avatar May 31 '18 13:05 victornoel

@vicb are you expecting a repro before this is taken care of? Or is the angular team going to take a look directly at the code.

This doesn't seem to be a bug, regression or a corner case but a very clearly missing feature…

victornoel avatar Jun 06 '18 13:06 victornoel

Any update on this?

P.s: @victornoel your workaround saved my day ; )

dydFreeman avatar Jul 09 '18 13:07 dydFreeman

@vicb ping? :)

victornoel avatar Jul 24 '18 13:07 victornoel

@vicb ping

victornoel avatar Aug 30 '18 08:08 victornoel

This causes my app confusion regularly in testing. The errors are always so difficult to hunt down because they are cryptic, but I need APP_INITIALIZER to complete before the tests run.

rgant avatar Apr 22 '19 20:04 rgant

I have been successfully using the workaround for this issue, but after updating to Angular 8 (currently on 8.0.6) it seems the workaround doesn't work anymore. I now have to resort to mocking out the services which should initialize on APP_INITIALIZER in all the unit tests which depend on it, which is quite a hassle.

bjowes avatar Jun 28 '19 11:06 bjowes

@victornoel Thanks for the workaround. I wasted a day to get to this workaround. This issue still exists in Angular 8; its amazing how this looong pending issue hasn't been resolved yet!

singhvivek2503 avatar Aug 05 '19 14:08 singhvivek2503

Thumbs up to this - I would classify this as a bug rather than a feature request. Angular should use App Initializers in test the same way it does in serve/production without requiring the user to wait on the donePromise.

Just fyi - For angular 9, the workaround should use TestBed.inject() instead of TestBed.get(). And make sure it comes after TestBed.configureTestingModule(...)

s4m0r4m4 avatar Apr 01 '20 16:04 s4m0r4m4

I am using angular 6 and the suggested workaround by @victornoel isn't working for me. Any suggestions?

BTW, I am making Http calls inside the promise returned by APP_INITIALIZER's factory, and HttpClientTestingModule is injected in Testbed, i am guessing this could be the issue.

podikris avatar May 05 '20 12:05 podikris

@podikris Did you find any solution / work around for this. I too have a situation like yours.

xavier-experion avatar Jul 01 '20 10:07 xavier-experion

If you test with HttpClientTestingModule it is mandatory to flush each request manualy. To do so just inject HttpTestingController and flush the request like so:

const req = httpController.expectOne(<expected URL>);
req.flush(<request data goes here>);

also after each test make sure that you don't have outstanding requests with:

httpController.verify();

copaste avatar Oct 06 '20 09:10 copaste

If you test with HttpClientTestingModule it is mandatory to flush each request manualy. To do so just inject HttpTestingController and flush the request like so:

const req = httpController.expectOne(<expected URL>);
reqDef.flush(<request data goes here>);

also after each test make sure that you don't have outstanding requests with:

httpController.verify();

Sorry @copaste but issue is not related to HttpClientTestingModule but taton APP_INITIALIZER promise.

meriturva avatar Oct 06 '20 10:10 meriturva

@meriturva Sorry it wasn't clear for me that is not related to HttpClientTestingModule. Because If you have any http calls in the APP_INITIALIZER the promise will never resolve until you flush it.

copaste avatar Oct 06 '20 11:10 copaste

Up, spent 5 hours trying to understand why my tests were failing while the app was working.

kanidjar avatar May 21 '21 17:05 kanidjar

Note, non-initializer providers are instantiated before for the initialization functions complete with victornoels workaround. This is still inconsistent with the actual application behavior.

TrevorKarjanis avatar Aug 29 '21 18:08 TrevorKarjanis

There is no documentation on the pitfalls in testing if using APP_INITIALIZER. Even if the work around doesn't work for every user scenario, that this issue is outstanding for 5 years and there isn't even a mention outside of a ticket in GitHub is very frustrating when trying to figure out what is going wrong. For my case, the work around does get past the hurdle, so thanks to @victornoel for that!

stephen-dirtcreative avatar Aug 24 '23 20:08 stephen-dirtcreative