From 7b13977c3aeda0e3d6b09234db68906968e5b36f Mon Sep 17 00:00:00 2001 From: Andrew Kushnir Date: Wed, 26 Feb 2020 17:59:38 -0800 Subject: [PATCH] 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 --- packages/core/src/di/jit/injectable.ts | 2 +- packages/core/test/test_bed_spec.ts | 22 +++++++++++++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/packages/core/src/di/jit/injectable.ts b/packages/core/src/di/jit/injectable.ts index ee18d1a577..e8419d3a47 100644 --- a/packages/core/src/di/jit/injectable.ts +++ b/packages/core/src/di/jit/injectable.ts @@ -65,7 +65,7 @@ export function compileInjectable(type: Type, srcMeta?: Injectable): void { typeArgumentCount: metadata.typeArgumentCount, deps: reflectDependencies(type), injectFn: 'inject', - target: compiler.R3FactoryTarget.Pipe + target: compiler.R3FactoryTarget.Injectable }); } return ngFactoryDef; diff --git a/packages/core/test/test_bed_spec.ts b/packages/core/test/test_bed_spec.ts index cc3248e80d..5ec2d3f556 100644 --- a/packages/core/test/test_bed_spec.ts +++ b/packages/core/test/test_bed_spec.ts @@ -6,7 +6,7 @@ * 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 {By} from '@angular/platform-browser'; import {expect} from '@angular/platform-browser/testing/src/matchers'; @@ -485,6 +485,26 @@ describe('TestBed', () => { 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)', () => { const serviceOverride = {