question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Dependency injection and class inheritance doesn't work in Angular 8 library test

See original GitHub issue

🐞 bug report

Affected Package

The issue is caused by package @angular/core@^8

Is this a regression?

Yes, the previous version in which this bug was not present was: @angular/core@7

Description

The problem occurs when:

  1. The base class has a constructor with an injected service. (Injector from the example)
@Injectable()
export class BaseService {
  // "Injector" is just for the sake of example. Any injectable would have the same problem.
  constructor(public injector: Injector) {
  }
}
  1. Child class has no constructor (i.e., it relies on base class constructor) AND at least one property with the default value.
@Injectable()
export class MyLibService extends BaseService {

  public foo = 'bar';

}
  1. (dont ask me how I have found this, but:) In angular.json [lib name].test.options.codeCoverage should be true.

PROBLEM:

injector is undefined in the instance of MyLibService.


🚩 Removing property from the child class (2) AND/OR opting out codeCoverage config in angular.json (3) doesn’t brake test.

As a result, I can’t have a class inheritance and code coverage at the same time.


I could put a constructor in the child class and call super by passing all required arguments manually, but it’s the last option since the real-life scenario is much more complicated than the example provided here.

🔬 Minimal Reproduction

git repo: https://github.com/ddramone/ng-8-library-inheritance-di-test-bug

reproduce steps:

  1. Install angular 8 cli
  2. Clone git clone https://github.com/ddramone/ng-8-library-inheritance-di-test-bug.git
  3. npm i
  4. run Test ng test my-lib

Expected behavior

Test should pass = Injector service should be available in the service instance.

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Reactions:32
  • Comments:17 (4 by maintainers)

github_iconTop GitHub Comments

9reactions
JoostKcommented, Jun 28, 2020

I have looked into why DI doesn’t work when coverage reporting is enabled, and it can be traced back to how Angular detects whether a constructor was present in a class, or if a constructor is generated synthetically, e.g. to initialize class fields. Enabling coverage inserts coverage instrumentation statements into the generated constructors:

class MyLibService extends BaseService {
  constructor() {
    cov_8nt6qq5zt().f[2]++;
    cov_8nt6qq5zt().s[6]++;
    super(...arguments);
    cov_8nt6qq5zt().s[7]++;
    this.foo = 'bar';
  }
}

These prevent Angular from recognizing the constructor as synthesized, causing MyLibService to be instantiated with 0 arguments. The proper behavior would be to delegate to the parent constructor, allowing its dependencies to be injected.

I opened #37811 as a proposal to workaround this issue. It’s not done yet and I can’t give an ETA yet, unfortunately.

4reactions
petrcecommented, Oct 18, 2019

tested on angular 8.2.11 with cli 8.3.12 and it is still not fixed, now I have to add tons of workarounds 😦

Read more comments on GitHub >

github_iconTop Results From Across the Web

Dependency injection in action - Angular
Take care when writing a component that inherits from another component. If the base component has injected dependencies, you must re-provide and re-inject...
Read more >
This constructor is not compatible with Angular Dependency ...
Error: This constructor is not compatible with Angular Dependency Injection because its dependency at index 0 of the parameter list is invalid.
Read more >
How To Extend Classes with Angular Component Inheritance
Learn how to use the power of inheritance to extend your Angular components with common functionality.
Read more >
Component Inheritance in Angular - Bits and Pieces
Using inheritance in TypeScript we can use the Parent-Child design to delegate the common code to a base class and let other components...
Read more >
Understand Composition and inheritance in Angular.
It appears as a solution (and it's) and works. But the problem comes when we feel the over-dependencies in the constructor to the...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found