test(ivy): add exhaustive inheritance tests (#30442)
- Adds inheritance tests for many combinations of directive, component and bare class inheritance - Adds tests that are failing in ivy, but should work, marks them with `xit` and a TODO. - Removes render3 unit tests that cover the same things. PR Close #30442
This commit is contained in:
parent
e9ead2bc09
commit
3f7e823b80
File diff suppressed because it is too large
Load Diff
|
@ -1,639 +0,0 @@
|
||||||
/**
|
|
||||||
* @license
|
|
||||||
* Copyright Google Inc. All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Use of this source code is governed by an MIT-style license that can be
|
|
||||||
* found in the LICENSE file at https://angular.io/license
|
|
||||||
*/
|
|
||||||
|
|
||||||
import {ElementRef, Inject, InjectionToken, QueryList, ɵAttributeMarker as AttributeMarker} from '../../src/core';
|
|
||||||
import {ΔallocHostVars, Δbind, ComponentDef, ΔcontentQuery, ΔdefineBase, ΔdefineComponent, ΔdefineDirective, DirectiveDef, ΔdirectiveInject, Δelement, ΔelementEnd, ΔelementProperty, ΔelementStart, ΔInheritDefinitionFeature, Δload, ΔloadContentQuery, ΔloadViewQuery, ΔNgOnChangesFeature, ΔProvidersFeature, ΔqueryRefresh, RenderFlags, ΔviewQuery,} from '../../src/render3/index';
|
|
||||||
|
|
||||||
import {ComponentFixture, createComponent, getDirectiveOnNode} from './render_util';
|
|
||||||
|
|
||||||
describe('InheritDefinitionFeature', () => {
|
|
||||||
it('should inherit lifecycle hooks', () => {
|
|
||||||
class SuperDirective {
|
|
||||||
ngOnInit() {}
|
|
||||||
ngOnDestroy() {}
|
|
||||||
ngAfterContentInit() {}
|
|
||||||
ngAfterContentChecked() {}
|
|
||||||
ngAfterViewInit() {}
|
|
||||||
ngAfterViewChecked() {}
|
|
||||||
ngDoCheck() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
class SubDirective extends SuperDirective {
|
|
||||||
ngAfterViewInit() {}
|
|
||||||
ngAfterViewChecked() {}
|
|
||||||
ngDoCheck() {}
|
|
||||||
|
|
||||||
static ngDirectiveDef = ΔdefineDirective({
|
|
||||||
type: SubDirective,
|
|
||||||
selectors: [['', 'subDir', '']],
|
|
||||||
factory: () => new SubDirective(),
|
|
||||||
features: [ΔInheritDefinitionFeature]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const finalDef = SubDirective.ngDirectiveDef as DirectiveDef<any>;
|
|
||||||
|
|
||||||
|
|
||||||
expect(finalDef.onInit).toBe(SuperDirective.prototype.ngOnInit);
|
|
||||||
expect(finalDef.onDestroy).toBe(SuperDirective.prototype.ngOnDestroy);
|
|
||||||
expect(finalDef.afterContentChecked).toBe(SuperDirective.prototype.ngAfterContentChecked);
|
|
||||||
expect(finalDef.afterContentInit).toBe(SuperDirective.prototype.ngAfterContentInit);
|
|
||||||
expect(finalDef.afterViewChecked).toBe(SubDirective.prototype.ngAfterViewChecked);
|
|
||||||
expect(finalDef.afterViewInit).toBe(SubDirective.prototype.ngAfterViewInit);
|
|
||||||
expect(finalDef.doCheck).toBe(SubDirective.prototype.ngDoCheck);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should inherit inputs', () => {
|
|
||||||
class SuperDirective {
|
|
||||||
static ngDirectiveDef = ΔdefineDirective({
|
|
||||||
inputs: {
|
|
||||||
superFoo: ['foo', 'declaredFoo'],
|
|
||||||
superBar: 'bar',
|
|
||||||
superBaz: 'baz',
|
|
||||||
},
|
|
||||||
type: SuperDirective,
|
|
||||||
selectors: [['', 'superDir', '']],
|
|
||||||
factory: () => new SuperDirective(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
class SubDirective extends SuperDirective {
|
|
||||||
static ngDirectiveDef = ΔdefineDirective({
|
|
||||||
type: SubDirective,
|
|
||||||
inputs: {
|
|
||||||
subBaz: 'baz',
|
|
||||||
subQux: 'qux',
|
|
||||||
},
|
|
||||||
selectors: [['', 'subDir', '']],
|
|
||||||
factory: () => new SubDirective(),
|
|
||||||
features: [ΔInheritDefinitionFeature]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const subDef = SubDirective.ngDirectiveDef as DirectiveDef<any>;
|
|
||||||
|
|
||||||
expect(subDef.inputs).toEqual({
|
|
||||||
foo: 'superFoo',
|
|
||||||
bar: 'superBar',
|
|
||||||
baz: 'subBaz',
|
|
||||||
qux: 'subQux',
|
|
||||||
});
|
|
||||||
expect(subDef.declaredInputs).toEqual({
|
|
||||||
foo: 'declaredFoo',
|
|
||||||
bar: 'bar',
|
|
||||||
baz: 'baz',
|
|
||||||
qux: 'qux',
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should inherit outputs', () => {
|
|
||||||
class SuperDirective {
|
|
||||||
static ngDirectiveDef = ΔdefineDirective({
|
|
||||||
outputs: {
|
|
||||||
superFoo: 'foo',
|
|
||||||
superBar: 'bar',
|
|
||||||
superBaz: 'baz',
|
|
||||||
},
|
|
||||||
type: SuperDirective,
|
|
||||||
selectors: [['', 'superDir', '']],
|
|
||||||
factory: () => new SuperDirective(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
class SubDirective extends SuperDirective {
|
|
||||||
static ngDirectiveDef = ΔdefineDirective({
|
|
||||||
type: SubDirective,
|
|
||||||
outputs: {
|
|
||||||
subBaz: 'baz',
|
|
||||||
subQux: 'qux',
|
|
||||||
},
|
|
||||||
selectors: [['', 'subDir', '']],
|
|
||||||
factory: () => new SubDirective(),
|
|
||||||
features: [ΔInheritDefinitionFeature]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const subDef = SubDirective.ngDirectiveDef as DirectiveDef<any>;
|
|
||||||
|
|
||||||
expect(subDef.outputs).toEqual({
|
|
||||||
foo: 'superFoo',
|
|
||||||
bar: 'superBar',
|
|
||||||
baz: 'subBaz',
|
|
||||||
qux: 'subQux',
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should detect EMPTY inputs and outputs', () => {
|
|
||||||
class SuperDirective {
|
|
||||||
static ngDirectiveDef = ΔdefineDirective({
|
|
||||||
inputs: {
|
|
||||||
testIn: 'testIn',
|
|
||||||
},
|
|
||||||
outputs: {
|
|
||||||
testOut: 'testOut',
|
|
||||||
},
|
|
||||||
type: SuperDirective,
|
|
||||||
selectors: [['', 'superDir', '']],
|
|
||||||
factory: () => new SuperDirective(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
class SubDirective extends SuperDirective {
|
|
||||||
static ngDirectiveDef = ΔdefineDirective({
|
|
||||||
type: SubDirective,
|
|
||||||
selectors: [['', 'subDir', '']],
|
|
||||||
factory: () => new SubDirective(),
|
|
||||||
features: [ΔInheritDefinitionFeature]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const subDef = SubDirective.ngDirectiveDef as DirectiveDef<any>;
|
|
||||||
|
|
||||||
expect(subDef.inputs).toEqual({
|
|
||||||
testIn: 'testIn',
|
|
||||||
});
|
|
||||||
expect(subDef.outputs).toEqual({
|
|
||||||
testOut: 'testOut',
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should inherit inputs from ngBaseDefs along the way', () => {
|
|
||||||
|
|
||||||
class Class5 {
|
|
||||||
input5 = 'data, so data';
|
|
||||||
|
|
||||||
static ngBaseDef = ΔdefineBase({
|
|
||||||
inputs: {
|
|
||||||
input5: 'input5',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
class Class4 extends Class5 {
|
|
||||||
input4 = 'hehe';
|
|
||||||
|
|
||||||
static ngDirectiveDef = ΔdefineDirective({
|
|
||||||
inputs: {
|
|
||||||
input4: 'input4',
|
|
||||||
},
|
|
||||||
type: Class4,
|
|
||||||
selectors: [['', 'superDir', '']],
|
|
||||||
factory: () => new Class4(),
|
|
||||||
features: [ΔInheritDefinitionFeature],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
class Class3 extends Class4 {}
|
|
||||||
|
|
||||||
class Class2 extends Class3 {
|
|
||||||
input3 = 'wee';
|
|
||||||
|
|
||||||
static ngBaseDef = ΔdefineBase({
|
|
||||||
inputs: {
|
|
||||||
input3: ['alias3', 'input3'],
|
|
||||||
}
|
|
||||||
}) as any;
|
|
||||||
}
|
|
||||||
|
|
||||||
class Class1 extends Class2 {
|
|
||||||
input1 = 'test';
|
|
||||||
input2 = 'whatever';
|
|
||||||
|
|
||||||
static ngDirectiveDef = ΔdefineDirective({
|
|
||||||
type: Class1,
|
|
||||||
inputs: {
|
|
||||||
input1: 'input1',
|
|
||||||
input2: 'input2',
|
|
||||||
},
|
|
||||||
selectors: [['', 'subDir', '']],
|
|
||||||
factory: () => new Class1(),
|
|
||||||
features: [ΔInheritDefinitionFeature],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const subDef = Class1.ngDirectiveDef as DirectiveDef<any>;
|
|
||||||
|
|
||||||
expect(subDef.inputs).toEqual({
|
|
||||||
input1: 'input1',
|
|
||||||
input2: 'input2',
|
|
||||||
alias3: 'input3',
|
|
||||||
input4: 'input4',
|
|
||||||
input5: 'input5',
|
|
||||||
});
|
|
||||||
expect(subDef.declaredInputs).toEqual({
|
|
||||||
input1: 'input1',
|
|
||||||
input2: 'input2',
|
|
||||||
alias3: 'input3',
|
|
||||||
input4: 'input4',
|
|
||||||
input5: 'input5',
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should inherit outputs from ngBaseDefs along the way', () => {
|
|
||||||
|
|
||||||
class Class5 {
|
|
||||||
output5 = 'data, so data';
|
|
||||||
|
|
||||||
static ngBaseDef = ΔdefineBase({
|
|
||||||
outputs: {
|
|
||||||
output5: 'alias5',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
class Class4 extends Class5 {
|
|
||||||
output4 = 'hehe';
|
|
||||||
|
|
||||||
static ngDirectiveDef = ΔdefineDirective({
|
|
||||||
outputs: {
|
|
||||||
output4: 'alias4',
|
|
||||||
},
|
|
||||||
type: Class4,
|
|
||||||
selectors: [['', 'superDir', '']],
|
|
||||||
factory: () => new Class4(),
|
|
||||||
features: [ΔInheritDefinitionFeature],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
class Class3 extends Class4 {}
|
|
||||||
|
|
||||||
class Class2 extends Class3 {
|
|
||||||
output3 = 'wee';
|
|
||||||
|
|
||||||
static ngBaseDef = ΔdefineBase({
|
|
||||||
outputs: {
|
|
||||||
output3: 'alias3',
|
|
||||||
}
|
|
||||||
}) as any;
|
|
||||||
}
|
|
||||||
|
|
||||||
class Class1 extends Class2 {
|
|
||||||
output1 = 'test';
|
|
||||||
output2 = 'whatever';
|
|
||||||
|
|
||||||
static ngDirectiveDef = ΔdefineDirective({
|
|
||||||
type: Class1,
|
|
||||||
outputs: {
|
|
||||||
output1: 'alias1',
|
|
||||||
output2: 'alias2',
|
|
||||||
},
|
|
||||||
selectors: [['', 'subDir', '']],
|
|
||||||
factory: () => new Class1(),
|
|
||||||
features: [ΔInheritDefinitionFeature],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const subDef = Class1.ngDirectiveDef as DirectiveDef<any>;
|
|
||||||
|
|
||||||
expect(subDef.outputs).toEqual({
|
|
||||||
alias1: 'output1',
|
|
||||||
alias2: 'output2',
|
|
||||||
alias3: 'output3',
|
|
||||||
alias4: 'output4',
|
|
||||||
alias5: 'output5',
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should compose hostBindings', () => {
|
|
||||||
let subDir !: SubDirective;
|
|
||||||
|
|
||||||
class SuperDirective {
|
|
||||||
id = 'my-id';
|
|
||||||
|
|
||||||
static ngDirectiveDef = ΔdefineDirective({
|
|
||||||
type: SuperDirective,
|
|
||||||
selectors: [['', 'superDir', '']],
|
|
||||||
hostBindings: (rf: RenderFlags, ctx: SuperDirective, elementIndex: number) => {
|
|
||||||
if (rf & RenderFlags.Create) {
|
|
||||||
ΔallocHostVars(1);
|
|
||||||
}
|
|
||||||
if (rf & RenderFlags.Update) {
|
|
||||||
ΔelementProperty(elementIndex, 'id', Δbind(ctx.id));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
factory: () => new SuperDirective(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
class SubDirective extends SuperDirective {
|
|
||||||
title = 'my-title';
|
|
||||||
|
|
||||||
static ngDirectiveDef = ΔdefineDirective({
|
|
||||||
type: SubDirective,
|
|
||||||
selectors: [['', 'subDir', '']],
|
|
||||||
hostBindings: (rf: RenderFlags, ctx: SubDirective, elementIndex: number) => {
|
|
||||||
if (rf & RenderFlags.Create) {
|
|
||||||
ΔallocHostVars(1);
|
|
||||||
}
|
|
||||||
if (rf & RenderFlags.Update) {
|
|
||||||
ΔelementProperty(elementIndex, 'title', Δbind(ctx.title));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
factory: () => subDir = new SubDirective(),
|
|
||||||
features: [ΔInheritDefinitionFeature]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const App = createComponent('app', (rf: RenderFlags, ctx: any) => {
|
|
||||||
if (rf & RenderFlags.Create) {
|
|
||||||
Δelement(0, 'div', ['subDir', '']);
|
|
||||||
}
|
|
||||||
}, 1, 0, [SubDirective]);
|
|
||||||
|
|
||||||
const fixture = new ComponentFixture(App);
|
|
||||||
const divEl = fixture.hostElement.querySelector('div') as HTMLElement;
|
|
||||||
|
|
||||||
expect(divEl.id).toEqual('my-id');
|
|
||||||
expect(divEl.title).toEqual('my-title');
|
|
||||||
|
|
||||||
subDir.title = 'new-title';
|
|
||||||
fixture.update();
|
|
||||||
expect(divEl.id).toEqual('my-id');
|
|
||||||
expect(divEl.title).toEqual('new-title');
|
|
||||||
|
|
||||||
subDir.id = 'new-id';
|
|
||||||
fixture.update();
|
|
||||||
expect(divEl.id).toEqual('new-id');
|
|
||||||
expect(divEl.title).toEqual('new-title');
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('view query', () => {
|
|
||||||
|
|
||||||
const SomeComp = createComponent('some-comp', (rf: RenderFlags, ctx: any) => {});
|
|
||||||
|
|
||||||
/*
|
|
||||||
* class SuperComponent {
|
|
||||||
* @ViewChildren('super') superQuery;
|
|
||||||
* }
|
|
||||||
*/
|
|
||||||
class SuperComponent {
|
|
||||||
superQuery?: QueryList<any>;
|
|
||||||
static ngComponentDef = ΔdefineComponent({
|
|
||||||
type: SuperComponent,
|
|
||||||
template: () => {},
|
|
||||||
consts: 0,
|
|
||||||
vars: 0,
|
|
||||||
selectors: [['super-comp']],
|
|
||||||
viewQuery: <T>(rf: RenderFlags, ctx: any) => {
|
|
||||||
if (rf & RenderFlags.Create) {
|
|
||||||
ΔviewQuery(['super'], false, null);
|
|
||||||
}
|
|
||||||
if (rf & RenderFlags.Update) {
|
|
||||||
let tmp: any;
|
|
||||||
ΔqueryRefresh(tmp = ΔloadViewQuery<QueryList<any>>()) &&
|
|
||||||
(ctx.superQuery = tmp as QueryList<any>);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
factory: () => new SuperComponent(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <div id="sub" #sub></div>
|
|
||||||
* <div id="super" #super></div>
|
|
||||||
* <some-comp></some-comp>
|
|
||||||
* class SubComponent extends SuperComponent {
|
|
||||||
* @ViewChildren('sub') subQuery;
|
|
||||||
* }
|
|
||||||
*/
|
|
||||||
class SubComponent extends SuperComponent {
|
|
||||||
subQuery?: QueryList<any>;
|
|
||||||
static ngComponentDef = ΔdefineComponent({
|
|
||||||
type: SubComponent,
|
|
||||||
template: (rf: RenderFlags, ctx: any) => {
|
|
||||||
if (rf & RenderFlags.Create) {
|
|
||||||
Δelement(0, 'div', ['id', 'sub'], ['sub', '']);
|
|
||||||
Δelement(2, 'div', ['id', 'super'], ['super', '']);
|
|
||||||
Δelement(4, 'some-comp');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
consts: 5,
|
|
||||||
vars: 0,
|
|
||||||
selectors: [['sub-comp']],
|
|
||||||
viewQuery: (rf: RenderFlags, ctx: any) => {
|
|
||||||
if (rf & RenderFlags.Create) {
|
|
||||||
ΔviewQuery(['sub'], false, null);
|
|
||||||
}
|
|
||||||
if (rf & RenderFlags.Update) {
|
|
||||||
let tmp: any;
|
|
||||||
ΔqueryRefresh(tmp = ΔloadViewQuery<QueryList<any>>()) &&
|
|
||||||
(ctx.subQuery = tmp as QueryList<any>);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
factory: () => new SubComponent(),
|
|
||||||
features: [ΔInheritDefinitionFeature],
|
|
||||||
directives: [SomeComp]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
it('should compose viewQuery (basic mechanics check)', () => {
|
|
||||||
const log: Array<[string, RenderFlags, any]> = [];
|
|
||||||
|
|
||||||
class SuperComponent {
|
|
||||||
static ngComponentDef = ΔdefineComponent({
|
|
||||||
type: SuperComponent,
|
|
||||||
template: () => {},
|
|
||||||
consts: 0,
|
|
||||||
vars: 0,
|
|
||||||
selectors: [['', 'superDir', '']],
|
|
||||||
viewQuery: <T>(rf: RenderFlags, ctx: T) => {
|
|
||||||
log.push(['super', rf, ctx]);
|
|
||||||
},
|
|
||||||
factory: () => new SuperComponent(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
class SubComponent extends SuperComponent {
|
|
||||||
static ngComponentDef = ΔdefineComponent({
|
|
||||||
type: SubComponent,
|
|
||||||
template: () => {},
|
|
||||||
consts: 0,
|
|
||||||
vars: 0,
|
|
||||||
selectors: [['', 'subDir', '']],
|
|
||||||
viewQuery: (rf: RenderFlags, ctx: SubComponent) => {
|
|
||||||
log.push(['sub', rf, ctx]);
|
|
||||||
},
|
|
||||||
factory: () => new SubComponent(),
|
|
||||||
features: [ΔInheritDefinitionFeature]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const subDef = SubComponent.ngComponentDef as ComponentDef<any>;
|
|
||||||
|
|
||||||
const context = {foo: 'bar'};
|
|
||||||
|
|
||||||
subDef.viewQuery !(RenderFlags.Create, context);
|
|
||||||
|
|
||||||
expect(log).toEqual(
|
|
||||||
[['super', RenderFlags.Create, context], ['sub', RenderFlags.Create, context]]);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
it('should compose viewQuery (query logic check)', () => {
|
|
||||||
const fixture = new ComponentFixture(SubComponent);
|
|
||||||
|
|
||||||
const check = (key: string): void => {
|
|
||||||
const qList = (fixture.component as any)[`${key}Query`] as QueryList<any>;
|
|
||||||
expect(qList.length).toBe(1);
|
|
||||||
expect(qList.first.nativeElement).toEqual(fixture.hostElement.querySelector(`#${key}`));
|
|
||||||
expect(qList.first.nativeElement.id).toEqual(key);
|
|
||||||
};
|
|
||||||
|
|
||||||
check('sub');
|
|
||||||
check('super');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should work with multiple viewQuery comps', () => {
|
|
||||||
let subCompOne !: SubComponent;
|
|
||||||
let subCompTwo !: SubComponent;
|
|
||||||
|
|
||||||
const App = createComponent('app', (rf: RenderFlags, ctx: any) => {
|
|
||||||
if (rf & RenderFlags.Create) {
|
|
||||||
Δelement(0, 'sub-comp');
|
|
||||||
Δelement(1, 'sub-comp');
|
|
||||||
}
|
|
||||||
subCompOne = getDirectiveOnNode(0);
|
|
||||||
subCompTwo = getDirectiveOnNode(1);
|
|
||||||
}, 2, 0, [SubComponent, SuperComponent]);
|
|
||||||
|
|
||||||
const fixture = new ComponentFixture(App);
|
|
||||||
|
|
||||||
const check = (comp: SubComponent): void => {
|
|
||||||
const qList = comp.subQuery as QueryList<any>;
|
|
||||||
expect(qList.length).toBe(1);
|
|
||||||
expect(qList.first.nativeElement).toEqual(fixture.hostElement.querySelector('#sub'));
|
|
||||||
expect(qList.first.nativeElement.id).toEqual('sub');
|
|
||||||
};
|
|
||||||
|
|
||||||
check(subCompOne);
|
|
||||||
check(subCompTwo);
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
it('should compose contentQueries (basic mechanics check)', () => {
|
|
||||||
const log: string[] = [];
|
|
||||||
|
|
||||||
class SuperDirective {
|
|
||||||
static ngDirectiveDef = ΔdefineDirective({
|
|
||||||
type: SuperDirective,
|
|
||||||
selectors: [['', 'superDir', '']],
|
|
||||||
contentQueries: () => { log.push('super'); },
|
|
||||||
factory: () => new SuperDirective(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
class SubDirective extends SuperDirective {
|
|
||||||
static ngDirectiveDef = ΔdefineDirective({
|
|
||||||
type: SubDirective,
|
|
||||||
selectors: [['', 'subDir', '']],
|
|
||||||
contentQueries: () => { log.push('sub'); },
|
|
||||||
factory: () => new SubDirective(),
|
|
||||||
features: [ΔInheritDefinitionFeature]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const subDef = SubDirective.ngDirectiveDef as DirectiveDef<any>;
|
|
||||||
|
|
||||||
subDef.contentQueries !(RenderFlags.Create, {}, 0);
|
|
||||||
|
|
||||||
expect(log).toEqual(['super', 'sub']);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should compose contentQueries (verify query sets)', () => {
|
|
||||||
let dirInstance: SubDirective;
|
|
||||||
class SuperDirective {
|
|
||||||
// @ContentChildren('foo')
|
|
||||||
foos !: QueryList<ElementRef>;
|
|
||||||
|
|
||||||
static ngDirectiveDef = ΔdefineDirective({
|
|
||||||
type: SuperDirective,
|
|
||||||
selectors: [['', 'super-dir', '']],
|
|
||||||
factory: () => new SuperDirective(),
|
|
||||||
contentQueries: (rf: RenderFlags, ctx: any, dirIndex: number) => {
|
|
||||||
if (rf & RenderFlags.Create) {
|
|
||||||
ΔcontentQuery(dirIndex, ['foo'], true, null);
|
|
||||||
}
|
|
||||||
if (rf & RenderFlags.Update) {
|
|
||||||
let tmp: any;
|
|
||||||
ΔqueryRefresh(tmp = ΔloadContentQuery<ElementRef>()) && (ctx.foos = tmp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
class SubDirective extends SuperDirective {
|
|
||||||
// @ContentChildren('bar')
|
|
||||||
bars !: QueryList<ElementRef>;
|
|
||||||
|
|
||||||
static ngDirectiveDef = ΔdefineDirective({
|
|
||||||
type: SubDirective,
|
|
||||||
selectors: [['', 'sub-dir', '']],
|
|
||||||
factory: () => dirInstance = new SubDirective(),
|
|
||||||
contentQueries: (rf: RenderFlags, ctx: any, dirIndex: number) => {
|
|
||||||
if (rf & RenderFlags.Create) {
|
|
||||||
ΔcontentQuery(dirIndex, ['bar'], true, null);
|
|
||||||
}
|
|
||||||
if (rf & RenderFlags.Update) {
|
|
||||||
let tmp: any;
|
|
||||||
ΔqueryRefresh(tmp = ΔloadContentQuery<ElementRef>()) && (ctx.bars = tmp);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
features: [ΔInheritDefinitionFeature]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <div sub-dir>
|
|
||||||
* <span #foo></span>
|
|
||||||
* <span #bar></span>
|
|
||||||
* </div>
|
|
||||||
*/
|
|
||||||
const AppComponent = createComponent('app-component', function(rf: RenderFlags, ctx: any) {
|
|
||||||
if (rf & RenderFlags.Create) {
|
|
||||||
ΔelementStart(0, 'div', [AttributeMarker.Bindings, 'sub-dir']);
|
|
||||||
{
|
|
||||||
Δelement(1, 'span', null, ['foo', '']);
|
|
||||||
Δelement(3, 'span', null, ['bar', '']);
|
|
||||||
}
|
|
||||||
ΔelementEnd();
|
|
||||||
}
|
|
||||||
}, 5, 0, [SubDirective]);
|
|
||||||
|
|
||||||
const fixture = new ComponentFixture(AppComponent);
|
|
||||||
expect(dirInstance !.foos.length).toBe(1);
|
|
||||||
expect(dirInstance !.bars.length).toBe(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should throw if inheriting a component from a directive', () => {
|
|
||||||
class SuperComponent {
|
|
||||||
static ngComponentDef = ΔdefineComponent({
|
|
||||||
type: SuperComponent,
|
|
||||||
template: () => {},
|
|
||||||
selectors: [['', 'superDir', '']],
|
|
||||||
consts: 0,
|
|
||||||
vars: 0,
|
|
||||||
factory: () => new SuperComponent()
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(() => {
|
|
||||||
class SubDirective extends SuperComponent{static ngDirectiveDef = ΔdefineDirective({
|
|
||||||
type: SubDirective,
|
|
||||||
selectors: [['', 'subDir', '']],
|
|
||||||
factory: () => new SubDirective(),
|
|
||||||
features: [ΔInheritDefinitionFeature]
|
|
||||||
});}
|
|
||||||
}).toThrowError('Directives cannot inherit Components');
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
Loading…
Reference in New Issue