diff --git a/packages/core/src/render3/metadata.ts b/packages/core/src/render3/metadata.ts index bfa8e65a64..053d742845 100644 --- a/packages/core/src/render3/metadata.ts +++ b/packages/core/src/render3/metadata.ts @@ -28,7 +28,7 @@ export function setClassMetadata( propDecorators: {[field: string]: any} | null): void { const clazz = type as TypeWithMetadata; if (decorators !== null) { - if (clazz.decorators !== undefined) { + if (clazz.hasOwnProperty('decorators') && clazz.decorators !== undefined) { clazz.decorators.push(...decorators); } else { clazz.decorators = decorators; diff --git a/packages/core/test/test_bed_spec.ts b/packages/core/test/test_bed_spec.ts index 0492ecd2c0..2b055bc58d 100644 --- a/packages/core/test/test_bed_spec.ts +++ b/packages/core/test/test_bed_spec.ts @@ -48,8 +48,21 @@ export class SimpleCmp { export class WithRefsCmp { } +@Component({selector: 'inherited-cmp', template: 'inherited'}) +export class InheritedCmp extends SimpleCmp { +} + +@Component({ + selector: 'simple-app', + template: ` + - + ` +}) +export class SimpleApp { +} + @NgModule({ - declarations: [HelloWorld, SimpleCmp, WithRefsCmp], + declarations: [HelloWorld, SimpleCmp, WithRefsCmp, InheritedCmp, SimpleApp], imports: [GreetingModule], providers: [ {provide: NAME, useValue: 'World!'}, @@ -174,6 +187,13 @@ describe('TestBed', () => { expect(hello.nativeElement).toHaveText('Hello injected World !'); }); + it('should resolve components that are extended by other components', () => { + // SimpleApp uses SimpleCmp in its template, which is extended by InheritedCmp + const simpleApp = TestBed.createComponent(SimpleApp); + simpleApp.detectChanges(); + expect(simpleApp.nativeElement).toHaveText('simple - inherited'); + }); + onlyInIvy('patched ng defs should be removed after resetting TestingModule') .it('make sure we restore ng defs to their initial states', () => { @Pipe({name: 'somePipe', pure: true}) diff --git a/packages/core/testing/src/resolvers.ts b/packages/core/testing/src/resolvers.ts index 2a15dd7bc5..bacbe78273 100644 --- a/packages/core/testing/src/resolvers.ts +++ b/packages/core/testing/src/resolvers.ts @@ -37,7 +37,9 @@ abstract class OverrideResolver implements Resolver { } getAnnotation(type: Type): T|null { - return reflection.annotations(type).find(a => a instanceof this.type) || null; + // We should always return the last match from filter(), or we may return superclass data by + // mistake. + return reflection.annotations(type).filter(a => a instanceof this.type).pop() || null; } resolve(type: Type): T|null {