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
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.