From 357a0733c74634615917f6fd89fa13f6609c1062 Mon Sep 17 00:00:00 2001 From: Andrew Scott Date: Mon, 16 Dec 2019 10:03:09 -0800 Subject: [PATCH] fix(ivy): reorder provider type checks to align with VE (#34433) The ordering matters because we don't currently throw if multiple configurations are provided (i.e. provider has *both* useExisting and useFactory). We should actually throw an error in this case, but to avoid another breaking change in v9, this PR simply aligns the Ivy behavior with ViewEngine. PR Close #34433 --- packages/core/src/di/r3_injector.ts | 4 +-- packages/core/test/acceptance/di_spec.ts | 32 ++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/packages/core/src/di/r3_injector.ts b/packages/core/src/di/r3_injector.ts index f6af39c0c8..2776e85bb2 100644 --- a/packages/core/src/di/r3_injector.ts +++ b/packages/core/src/di/r3_injector.ts @@ -482,10 +482,10 @@ export function providerToFactory( } else { if (isValueProvider(provider)) { factory = () => resolveForwardRef(provider.useValue); - } else if (isExistingProvider(provider)) { - factory = () => ɵɵinject(resolveForwardRef(provider.useExisting)); } else if (isFactoryProvider(provider)) { factory = () => provider.useFactory(...injectArgs(provider.deps || [])); + } else if (isExistingProvider(provider)) { + factory = () => ɵɵinject(resolveForwardRef(provider.useExisting)); } else { const classRef = resolveForwardRef( provider && diff --git a/packages/core/test/acceptance/di_spec.ts b/packages/core/test/acceptance/di_spec.ts index 863c3e3fcd..9a2df0297c 100644 --- a/packages/core/test/acceptance/di_spec.ts +++ b/packages/core/test/acceptance/di_spec.ts @@ -1901,4 +1901,36 @@ describe('di', () => { expect(fixture.nativeElement.textContent.trim()).toBe('2 (transformed) items'); }); + + // TODO: https://angular-team.atlassian.net/browse/FW-1779 + it('should prioritize useFactory over useExisting', () => { + abstract class Base {} + @Directive({selector: '[dirA]'}) + class DirA implements Base { + } + @Directive({selector: '[dirB]'}) + class DirB implements Base { + } + + const PROVIDER = {provide: Base, useExisting: DirA, useFactory: () => new DirB()}; + + @Component({selector: 'child', template: '', providers: [PROVIDER]}) + class Child { + constructor(readonly base: Base) {} + } + + @Component({template: `
`}) + class App { + @ViewChild(DirA) dirA !: DirA; + @ViewChild(Child) child !: Child; + } + + const fixture = TestBed.configureTestingModule({declarations: [DirA, DirB, App, Child]}) + .createComponent(App); + fixture.detectChanges(); + expect(fixture.componentInstance.dirA) + .not.toEqual( + fixture.componentInstance.child.base, + 'should not get dirA from parent, but create new dirB from the useFactory provider'); + }); });