Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unhandled promise rejection: Error: Injector has already been destroyed

In this issue that was recently closed: https://github.com/angular/angular/issues/44186

A contributer (@jessicajaniuk) says

We believe this is resolved by destroyAfterEach: true. If you're seeing failures that require destroyAfterEach: false, it's likely you have scope leakage in your tests. If you continue to see the original issue, please open a new issue for it.

I was wondering if anyone can elaborate on or suggest strategies on how to identify "scope creep"

I'm also running into this after upgrading to Angular 13 with destroyAfterEach: true

like image 580
skzryzg Avatar asked Nov 19 '25 10:11

skzryzg


2 Answers

The answer of @user11883568 got me in the right direction but using fakeAsync didn't help in my case. What I did instead, was to opt-out from teardown on the unit-tests affected by this problem by adding the following as described here:

For the complete suite, on the existing TestBed.configureTestingModule, just add the line:

beforeEach(async () => {
    await TestBed.configureTestingModule({
        imports: [...],
        declarations: [...],
        providers: [...],
        teardown: {destroyAfterEach: false}   // <- add this line
    }).compileComponents();
});

Or, if the problem occurs only on some of the tests, you can opt-out a describe block with:

beforeAll(() => {
    // Deactivate teardown for these tests because of a problem with
    // the primeNg dialog.
    TestBed.resetTestEnvironment();
    TestBed.initTestEnvironment(
        BrowserDynamicTestingModule,
        platformBrowserDynamicTesting(),
        {teardown: {destroyAfterEach: false}}
    );
});
like image 181
andzep Avatar answered Nov 22 '25 01:11

andzep


For my case this was a symptom of a hidden setTimeout within a service method called by the component under test. The destroyAfterEach solution may work but it ignores the root problem which is logic being executed after the test expects to be finished.

So there are 4 solutions:

  1. Try using destroyAfterEach as the other answers outline
  2. Use fakeAsync to wrap the test and likely add a flush to clear the task queue
  3. spyOn the method which contains the asynchronous logic
  4. Remove the setTimeout or rewrite the asynchronous logic (with promises or async/await or observables) and write your tests to wait for the logic to finish.

Depending on what you are trying to test only #4 truly executes the code which is causing the error from the OP.

like image 21
Nate Loftsgard Avatar answered Nov 22 '25 01:11

Nate Loftsgard



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!