fix(core): use proper configuration to compile Injectable in JIT (#35706)

Prior to this change, the logic that compiles Injectable in JIT mode used incorrect configuration that triggers a problem when `ChangeDetectorRef` is used as a dependency. This commit updates the logic to generate correct inject instruction to add the `ChangeDetectorRef` dependency in case it's requested in @Injectable class.

PR Close #35706
This commit is contained in:
Andrew Kushnir 2020-02-26 17:59:38 -08:00 committed by atscott
parent 8fed1fe792
commit 7b13977c3a
2 changed files with 22 additions and 2 deletions

View File

@ -65,7 +65,7 @@ export function compileInjectable(type: Type<any>, srcMeta?: Injectable): void {
typeArgumentCount: metadata.typeArgumentCount, typeArgumentCount: metadata.typeArgumentCount,
deps: reflectDependencies(type), deps: reflectDependencies(type),
injectFn: 'inject', injectFn: 'inject',
target: compiler.R3FactoryTarget.Pipe target: compiler.R3FactoryTarget.Injectable
}); });
} }
return ngFactoryDef; return ngFactoryDef;

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import {Compiler, Component, Directive, ErrorHandler, Inject, Injectable, InjectionToken, Injector, Input, ModuleWithProviders, NgModule, Optional, Pipe, Type, ViewChild, ɵsetClassMetadata as setClassMetadata, ɵɵdefineComponent as defineComponent, ɵɵdefineInjector as defineInjector, ɵɵdefineNgModule as defineNgModule, ɵɵsetNgModuleScope as setNgModuleScope, ɵɵtext as text} from '@angular/core'; import {ChangeDetectorRef, Compiler, Component, Directive, ErrorHandler, Inject, Injectable, InjectionToken, Injector, Input, ModuleWithProviders, NgModule, Optional, Pipe, Type, ViewChild, ɵsetClassMetadata as setClassMetadata, ɵɵdefineComponent as defineComponent, ɵɵdefineInjector as defineInjector, ɵɵdefineNgModule as defineNgModule, ɵɵsetNgModuleScope as setNgModuleScope, ɵɵtext as text} from '@angular/core';
import {TestBed, getTestBed} from '@angular/core/testing/src/test_bed'; import {TestBed, getTestBed} from '@angular/core/testing/src/test_bed';
import {By} from '@angular/platform-browser'; import {By} from '@angular/platform-browser';
import {expect} from '@angular/platform-browser/testing/src/matchers'; import {expect} from '@angular/platform-browser/testing/src/matchers';
@ -485,6 +485,26 @@ describe('TestBed', () => {
expect(service.get()).toEqual('override'); expect(service.get()).toEqual('override');
}); });
it('should handle overrides for a provider that has `ChangeDetectorRef` as a dependency', () => {
// Note: we specifically check an @Injectable with `ChangeDetectorRef` here due to the fact that
// in Ivy there is a special instruction that injects `ChangeDetectorRef` token for Pipes
// (ɵɵinjectPipeChangeDetectorRef) and using that function for other types causes problems,
// for example when we try to override an @Injectable. The test below captures a use-case that
// triggers a problem in case incompatible function is used to inject `ChangeDetectorRef` as a
// dependency.
@Injectable({providedIn: 'root'})
class MyService {
token = 'original';
constructor(public cdr: ChangeDetectorRef) {}
}
TestBed.configureTestingModule({});
TestBed.overrideProvider(MyService, {useValue: {token: 'override'}});
const service = TestBed.inject(MyService);
expect(service.token).toBe('override');
});
it('should allow overriding a provider defined via ModuleWithProviders (using TestBed.configureTestingModule)', it('should allow overriding a provider defined via ModuleWithProviders (using TestBed.configureTestingModule)',
() => { () => {
const serviceOverride = { const serviceOverride = {