fix(ivy): TestBed should use annotation for the last match rather than the first (#28195)
When we look for matching annotations in TestBed, we should always take the last matching annotation. Otherwise, we will return superclass data for subclasses, which would have unintended consequences like directives matching the wrong selectors. PR Close #28195
This commit is contained in:
parent
8a08ff1571
commit
1f7d3b9a57
|
@ -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;
|
||||
|
|
|
@ -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: `
|
||||
<simple-cmp></simple-cmp> - <inherited-cmp></inherited-cmp>
|
||||
`
|
||||
})
|
||||
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})
|
||||
|
|
|
@ -37,7 +37,9 @@ abstract class OverrideResolver<T> implements Resolver<T> {
|
|||
}
|
||||
|
||||
getAnnotation(type: Type<any>): 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<any>): T|null {
|
||||
|
|
Loading…
Reference in New Issue