Yariv Katz
Yariv Katz

Reputation: 1362

Angular 5 and lerna NullInjectorError: No provider for InjectionToken

My use case is the following:

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

Upvotes: 4

Views: 3134

Answers (2)

H3lium
H3lium

Reputation: 95

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.

Upvotes: 1

Yariv Katz
Yariv Katz

Reputation: 1362

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.

Upvotes: 2

Related Questions