4

My use case is the following:

  • I have 2 angular5 libraries.
  • Both of the libraries are cloned from the following project: https://github.com/robisim74/angular-library-starter
  • I have a monorepo managed by lerna
  • the child library has a very simple directive which the parent library needs to use.

code for the child library

import { NgModule } from '@angular/core';
import {CommonModule} from "@angular/common";

@NgModule({
    imports: [CommonModule],
    declarations: [
        SampleDirective
    ],
    exports: [
        SampleDirective
    ]
})
export class ChildModule { }

The code for the directive in the child library

import {Directive, PLATFORM_ID, Inject} from '@angular/core';

@Directive({
    selector: '.sample'
})
export class SampleDirective {
    constructor(@Inject(PLATFORM_ID) private _element: Object) {

    }
}

In the parent I Installed the child module and I'm doing the following simple unit test

import {async, ComponentFixture, TestBed} from '@angular/core/testing';
import {Component} from '@angular/core';
import {ChildModule} from "@nz/child-lib";

@Component({
    selector: 'nz-host',
    template: `
        <div class="sample"></div>
    `
})
export class TestWrapperComponent{}


describe('injection problem', () => {
    let testFixture: ComponentFixture<TestWrapperComponent>;

    beforeEach(async(() => {
        TestBed.configureTestingModule({
            declarations: [TestWrapperComponent],
            imports: [ChildModule]                
        });
    }));

    beforeEach(async(() => {
        testFixture = TestBed.createComponent(TestWrapperComponent);
        testFixture.detectChanges();
    }));

    it('test', () => {
        expect(true).toBe(true);
    });
});

When I run the tests I'm getting the following error:

StaticInjectorError[InjectionToken Platform ID]: NullInjectorError: No provider for InjectionToken Platform ID! Error: StaticInjectorError[InjectionToken Platform ID]: at _NullInjector.get (webpack:///node_modules/@angular/core/esm5/core.js:923:0 <- spec.bundle.js:3517:19) at resolveToken (webpack:///node_modules/@angular/core/esm5/core.js:1211:0 <- spec.bundle.js:3805:24) at tryResolveToken (webpack:///node_modules/@angular/core/esm5/core.js:1153:0 <- spec.bundle.js:3747:16) at StaticInjector.get (webpack:///node_modules/@angular/core/esm5/core.js:1024:0 <- spec.bundle.js:3618:20) at resolveToken (webpack:///node_modules/@angular/core/esm5/core.js:1211:0 <- spec.bundle.js:3805:24) at tryResolveToken (webpack:///node_modules/@angular/core/esm5/core.js:1153:0 <- spec.bundle.js:3747:16) at StaticInjector.get (webpack:///node_modules/@angular/core/esm5/core.js:1024:0 <- spec.bundle.js:3618:20) at resolveNgModuleDep (webpack:///node_modules/@angular/core/esm5/core.js:10584:0 <- spec.bundle.js:13178:25) at NgModuleRef_.get (webpack:///node_modules/@angular/core/esm5/core.js:11805:0 <- spec.bundle.js:14399:16) at resolveDep (webpack:///node_modules/@angular/core/esm5/core.js:12301:0 <- spec.bundle.js:14895:45)

My package.json is this:

"dependencies": {
    "tslib": "^1.7.1"
},
"peerDependencies": {
    "@angular/common": ">= 5.0.0",
    "@angular/core": ">= 5.0.0"
},
"devDependencies": {
    "@angular/animations": "5.0.0",
    "@angular/common": "5.0.0",
    "@angular/compiler": "5.0.0",
    "@angular/compiler-cli": "5.0.0",
    "@angular/core": "5.0.0",
    "@angular/platform-browser": "5.0.0",
    "@angular/platform-browser-dynamic": "5.0.0",
    "@angular/platform-server": "5.0.0",
    "@compodoc/compodoc": "1.0.3",
    "@nz/child-lib": "^0.0.1",
    "@types/jasmine": "2.6.2",
    "@types/node": "8.0.47",
    "chalk": "2.3.0",
    "codelyzer": "4.0.2",
    "core-js": "2.5.1",
    "istanbul-instrumenter-loader": "3.0.0",
    "jasmine-core": "2.8.0",
    "karma": "1.7.1",
    "karma-chrome-launcher": "2.2.0",
    "karma-coverage-istanbul-reporter": "1.3.0",
    "karma-jasmine": "1.1.0",
    "karma-sourcemap-loader": "0.3.7",
    "karma-spec-reporter": "0.0.31",
    "karma-webpack": "2.0.5",
    "reflect-metadata": "0.1.10",
    "rollup": "0.50.0",
    "rollup-plugin-license": "0.5.0",
    "rollup-plugin-node-resolve": "3.0.0",
    "rollup-plugin-sourcemaps": "0.4.2",
    "rxjs": "5.5.2",
    "shelljs": "0.7.8",
    "source-map-loader": "0.2.3",
    "ts-loader": "3.1.1",
    "tslint": "5.8.0",
    "tslint-angular": "1.0.0",
    "typescript": "2.4.2",
    "uglify-js": "3.1.6",
    "webpack": "3.8.1",
    "zone.js": "0.8.18"
}

Even when mocking the PLATFORM_ID with the following code

{provide: PLATFORM_ID, useValue: 'browser'}

The error is still there.

packages as symlinks

I have a new theory why it happens on my end. I think since I'm using lerna to manage my packages and packages dependency. And since I added the child module to the host module through lerna, then lerna creates a symlink of the child module in the node modules of the host. So my theory is that the DI can't identify what he needs to inject when the library we are using is symlinked. Trying to figure out how to run the tests with --preserve-symlinks

Thanks a lot

Yariv Katz
  • 1,353
  • 1
  • 17
  • 24
  • You will need to mock a `PlatformId` in your test. – CozyAzure Feb 06 '18 at 09:33
  • Even when mocking platform id I'm still getting the same error. see post edit at the bottom. also a few weeks ago, this kind of code worked and i didn't have to mock platform id in order to inject it. Thanks a lot for your help – Yariv Katz Feb 06 '18 at 09:42

2 Answers2

2

So the problem was indeed symlinks. when using symlinks in your node_modules or using a package management tool like lerna (which links internal packages with symlink). Than angular won't know how to inject the items properly.

The solution for me was before running the tests to remove the symlinks install the packages with a hard copy and then run the tests.

Yariv Katz
  • 1,353
  • 1
  • 17
  • 24
  • I use `npm link` to work with my library and got into this issue. I can confirm that removing link and copying files instead works. – Martin Nuc Oct 04 '18 at 21:14
1

I encountered the same issue with Angular 6 multi-modules project and with Lerna.

First, there is an option called preserveSymLinks to set to true in Angular configuration file (angular.json in Angular 6).

After that, I was able to link the module to my project with a symbolik link but not with Lerna link. I don't know why yet but I have to do this with a mklink command on Windows environment.

adiga
  • 34,372
  • 9
  • 61
  • 83
H3lium
  • 95
  • 4