test(ivy): add additional lifecycle hook acceptance tests (#30445)
Moves additional lifecycle hook tests from render3 to acceptance PR Close #30445
This commit is contained in:
parent
d18c58816f
commit
60235b5aef
|
@ -3376,3 +3376,335 @@ describe('onDestroy', () => {
|
|||
expect(events).toEqual(['dir']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('hook order', () => {
|
||||
let events: string[] = [];
|
||||
|
||||
beforeEach(() => events = []);
|
||||
|
||||
@Component({
|
||||
selector: 'comp',
|
||||
template: `{{value}}<div><ng-content></ng-content></div>`,
|
||||
})
|
||||
class Comp {
|
||||
@Input()
|
||||
value = '';
|
||||
|
||||
@Input()
|
||||
name = '';
|
||||
|
||||
ngOnInit() { events.push(`${this.name} onInit`); }
|
||||
|
||||
ngDoCheck() { events.push(`${this.name} doCheck`); }
|
||||
|
||||
ngOnChanges() { events.push(`${this.name} onChanges`); }
|
||||
|
||||
ngAfterContentInit() { events.push(`${this.name} afterContentInit`); }
|
||||
|
||||
ngAfterContentChecked() { events.push(`${this.name} afterContentChecked`); }
|
||||
|
||||
ngAfterViewInit() { events.push(`${this.name} afterViewInit`); }
|
||||
|
||||
ngAfterViewChecked() { events.push(`${this.name} afterViewChecked`); }
|
||||
|
||||
ngOnDestroy() { events.push(`${this.name} onDestroy`); }
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'parent',
|
||||
template:
|
||||
`<comp [name]="'child of ' + this.name" [value]="value"><ng-content></ng-content></comp>`,
|
||||
})
|
||||
class Parent extends Comp {
|
||||
}
|
||||
|
||||
it('should call all hooks in correct order', () => {
|
||||
@Component({template: `<comp *ngIf="show" name="comp" [value]="value"></comp>`})
|
||||
class App {
|
||||
value = 'a';
|
||||
|
||||
show = true;
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [App, Comp],
|
||||
imports: [CommonModule],
|
||||
});
|
||||
const fixture = TestBed.createComponent(App);
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(events).toEqual([
|
||||
'comp onChanges',
|
||||
'comp onInit',
|
||||
'comp doCheck',
|
||||
'comp afterContentInit',
|
||||
'comp afterContentChecked',
|
||||
'comp afterViewInit',
|
||||
'comp afterViewChecked',
|
||||
]);
|
||||
|
||||
events.length = 0;
|
||||
fixture.detectChanges();
|
||||
expect(events).toEqual([
|
||||
'comp doCheck',
|
||||
'comp afterContentChecked',
|
||||
'comp afterViewChecked',
|
||||
]);
|
||||
|
||||
events.length = 0;
|
||||
fixture.componentInstance.value = 'b';
|
||||
fixture.detectChanges();
|
||||
expect(events).toEqual([
|
||||
'comp onChanges',
|
||||
'comp doCheck',
|
||||
'comp afterContentChecked',
|
||||
'comp afterViewChecked',
|
||||
]);
|
||||
|
||||
events.length = 0;
|
||||
fixture.componentInstance.show = false;
|
||||
fixture.detectChanges();
|
||||
expect(events).toEqual([
|
||||
'comp onDestroy',
|
||||
]);
|
||||
});
|
||||
|
||||
it('should call all hooks in correct order with children', () => {
|
||||
@Component({
|
||||
template: `
|
||||
<div *ngIf="show">
|
||||
<parent name="parent1" [value]="value"></parent>
|
||||
<parent name="parent2" [value]="value"></parent>
|
||||
</div>
|
||||
`
|
||||
})
|
||||
class App {
|
||||
value = 'a';
|
||||
|
||||
show = true;
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [App, Parent, Comp],
|
||||
imports: [CommonModule],
|
||||
});
|
||||
const fixture = TestBed.createComponent(App);
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(events).toEqual([
|
||||
'parent1 onChanges',
|
||||
'parent1 onInit',
|
||||
'parent1 doCheck',
|
||||
'parent2 onChanges',
|
||||
'parent2 onInit',
|
||||
'parent2 doCheck',
|
||||
'parent1 afterContentInit',
|
||||
'parent1 afterContentChecked',
|
||||
'parent2 afterContentInit',
|
||||
'parent2 afterContentChecked',
|
||||
'child of parent1 onChanges',
|
||||
'child of parent1 onInit',
|
||||
'child of parent1 doCheck',
|
||||
'child of parent1 afterContentInit',
|
||||
'child of parent1 afterContentChecked',
|
||||
'child of parent1 afterViewInit',
|
||||
'child of parent1 afterViewChecked',
|
||||
'child of parent2 onChanges',
|
||||
'child of parent2 onInit',
|
||||
'child of parent2 doCheck',
|
||||
'child of parent2 afterContentInit',
|
||||
'child of parent2 afterContentChecked',
|
||||
'child of parent2 afterViewInit',
|
||||
'child of parent2 afterViewChecked',
|
||||
'parent1 afterViewInit',
|
||||
'parent1 afterViewChecked',
|
||||
'parent2 afterViewInit',
|
||||
'parent2 afterViewChecked',
|
||||
]);
|
||||
|
||||
events.length = 0;
|
||||
fixture.componentInstance.value = 'b';
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(events).toEqual([
|
||||
'parent1 onChanges',
|
||||
'parent1 doCheck',
|
||||
'parent2 onChanges',
|
||||
'parent2 doCheck',
|
||||
'parent1 afterContentChecked',
|
||||
'parent2 afterContentChecked',
|
||||
'child of parent1 onChanges',
|
||||
'child of parent1 doCheck',
|
||||
'child of parent1 afterContentChecked',
|
||||
'child of parent1 afterViewChecked',
|
||||
'child of parent2 onChanges',
|
||||
'child of parent2 doCheck',
|
||||
'child of parent2 afterContentChecked',
|
||||
'child of parent2 afterViewChecked',
|
||||
'parent1 afterViewChecked',
|
||||
'parent2 afterViewChecked',
|
||||
]);
|
||||
|
||||
events.length = 0;
|
||||
fixture.componentInstance.show = false;
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(events).toEqual([
|
||||
'child of parent1 onDestroy',
|
||||
'child of parent2 onDestroy',
|
||||
'parent1 onDestroy',
|
||||
'parent2 onDestroy',
|
||||
]);
|
||||
});
|
||||
|
||||
// Angular 5 reference: https://stackblitz.com/edit/lifecycle-hooks-ng
|
||||
it('should call all hooks in correct order with view and content', () => {
|
||||
@Component({
|
||||
template: `
|
||||
<div *ngIf="show">
|
||||
<parent name="parent1" [value]="value">
|
||||
<comp name="projected1" [value]="value"></comp>
|
||||
</parent>
|
||||
<parent name="parent2" [value]="value">
|
||||
<comp name="projected2" [value]="value"></comp>
|
||||
</parent>
|
||||
</div>
|
||||
`
|
||||
})
|
||||
class App {
|
||||
value = 'a';
|
||||
show = true;
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [App, Parent, Comp],
|
||||
imports: [CommonModule],
|
||||
});
|
||||
const fixture = TestBed.createComponent(App);
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(events).toEqual([
|
||||
'parent1 onChanges',
|
||||
'parent1 onInit',
|
||||
'parent1 doCheck',
|
||||
'projected1 onChanges',
|
||||
'projected1 onInit',
|
||||
'projected1 doCheck',
|
||||
'parent2 onChanges',
|
||||
'parent2 onInit',
|
||||
'parent2 doCheck',
|
||||
'projected2 onChanges',
|
||||
'projected2 onInit',
|
||||
'projected2 doCheck',
|
||||
'projected1 afterContentInit',
|
||||
'projected1 afterContentChecked',
|
||||
'parent1 afterContentInit',
|
||||
'parent1 afterContentChecked',
|
||||
'projected2 afterContentInit',
|
||||
'projected2 afterContentChecked',
|
||||
'parent2 afterContentInit',
|
||||
'parent2 afterContentChecked',
|
||||
'child of parent1 onChanges',
|
||||
'child of parent1 onInit',
|
||||
'child of parent1 doCheck',
|
||||
'child of parent1 afterContentInit',
|
||||
'child of parent1 afterContentChecked',
|
||||
'child of parent1 afterViewInit',
|
||||
'child of parent1 afterViewChecked',
|
||||
'child of parent2 onChanges',
|
||||
'child of parent2 onInit',
|
||||
'child of parent2 doCheck',
|
||||
'child of parent2 afterContentInit',
|
||||
'child of parent2 afterContentChecked',
|
||||
'child of parent2 afterViewInit',
|
||||
'child of parent2 afterViewChecked',
|
||||
'projected1 afterViewInit',
|
||||
'projected1 afterViewChecked',
|
||||
'parent1 afterViewInit',
|
||||
'parent1 afterViewChecked',
|
||||
'projected2 afterViewInit',
|
||||
'projected2 afterViewChecked',
|
||||
'parent2 afterViewInit',
|
||||
'parent2 afterViewChecked',
|
||||
]);
|
||||
|
||||
events.length = 0;
|
||||
fixture.componentInstance.value = 'b';
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(events).toEqual([
|
||||
'parent1 onChanges',
|
||||
'parent1 doCheck',
|
||||
'projected1 onChanges',
|
||||
'projected1 doCheck',
|
||||
'parent2 onChanges',
|
||||
'parent2 doCheck',
|
||||
'projected2 onChanges',
|
||||
'projected2 doCheck',
|
||||
'projected1 afterContentChecked',
|
||||
'parent1 afterContentChecked',
|
||||
'projected2 afterContentChecked',
|
||||
'parent2 afterContentChecked',
|
||||
'child of parent1 onChanges',
|
||||
'child of parent1 doCheck',
|
||||
'child of parent1 afterContentChecked',
|
||||
'child of parent1 afterViewChecked',
|
||||
'child of parent2 onChanges',
|
||||
'child of parent2 doCheck',
|
||||
'child of parent2 afterContentChecked',
|
||||
'child of parent2 afterViewChecked',
|
||||
'projected1 afterViewChecked',
|
||||
'parent1 afterViewChecked',
|
||||
'projected2 afterViewChecked',
|
||||
'parent2 afterViewChecked',
|
||||
]);
|
||||
|
||||
events.length = 0;
|
||||
fixture.componentInstance.show = false;
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(events).toEqual([
|
||||
'child of parent1 onDestroy',
|
||||
'child of parent2 onDestroy',
|
||||
'projected1 onDestroy',
|
||||
'parent1 onDestroy',
|
||||
'projected2 onDestroy',
|
||||
'parent2 onDestroy',
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('non-regression', () => {
|
||||
it('should call lifecycle hooks for directives active on <ng-template>', () => {
|
||||
let destroyed = false;
|
||||
|
||||
@Directive({
|
||||
selector: '[onDestroyDir]',
|
||||
})
|
||||
class OnDestroyDir {
|
||||
ngOnDestroy() { destroyed = true; }
|
||||
}
|
||||
|
||||
@Component({
|
||||
template: `<ng-template [ngIf]="show">
|
||||
<ng-template onDestroyDir>content</ng-template>
|
||||
</ng-template>`
|
||||
})
|
||||
class App {
|
||||
show = true;
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [App, OnDestroyDir],
|
||||
});
|
||||
const fixture = TestBed.createComponent(App);
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(destroyed).toBeFalsy();
|
||||
|
||||
fixture.componentInstance.show = false;
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(destroyed).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -6,13 +6,13 @@
|
|||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {ComponentFactoryResolver, OnDestroy, SimpleChange, SimpleChanges, ViewContainerRef} from '../../src/core';
|
||||
import {AttributeMarker, ComponentTemplate, LifecycleHooksFeature, injectComponentFactoryResolver, ΔNgOnChangesFeature, ΔdefineComponent, ΔdefineDirective} from '../../src/render3/index';
|
||||
import {markDirty, Δbind, Δcontainer, ΔcontainerRefreshEnd, ΔcontainerRefreshStart, ΔdirectiveInject, Δelement, ΔelementEnd, ΔelementProperty, ΔelementStart, ΔembeddedViewEnd, ΔembeddedViewStart, Δlistener, Δprojection, ΔprojectionDef, Δselect, Δtemplate, Δtext} from '../../src/render3/instructions/all';
|
||||
import {OnDestroy} from '../../src/core';
|
||||
import {AttributeMarker, ComponentTemplate, ΔNgOnChangesFeature, ΔdefineComponent, ΔdefineDirective} from '../../src/render3/index';
|
||||
import {Δbind, Δcontainer, ΔcontainerRefreshEnd, ΔcontainerRefreshStart, Δelement, ΔelementEnd, ΔelementProperty, ΔelementStart, ΔembeddedViewEnd, ΔembeddedViewStart, Δprojection, ΔprojectionDef, Δselect, Δtemplate, Δtext} from '../../src/render3/instructions/all';
|
||||
import {RenderFlags} from '../../src/render3/interfaces/definition';
|
||||
|
||||
import {NgIf} from './common_with_def';
|
||||
import {ComponentFixture, containerEl, createComponent, renderComponent, renderToHtml, requestAnimationFrame} from './render_util';
|
||||
import {ComponentFixture, createComponent} from './render_util';
|
||||
|
||||
describe('lifecycles', () => {
|
||||
|
||||
|
@ -32,7 +32,7 @@ describe('lifecycles', () => {
|
|||
|
||||
beforeEach(() => { events = []; });
|
||||
|
||||
let Comp = createOnInitComponent('comp', (rf: RenderFlags, ctx: any) => {
|
||||
let Comp = createOnInitComponent('comp', (rf: RenderFlags) => {
|
||||
if (rf & RenderFlags.Create) {
|
||||
ΔprojectionDef();
|
||||
ΔelementStart(0, 'div');
|
||||
|
@ -41,7 +41,7 @@ describe('lifecycles', () => {
|
|||
}
|
||||
}, 2);
|
||||
let Parent = createOnInitComponent('parent', getParentTemplate('comp'), 1, 1, [Comp]);
|
||||
let ProjectedComp = createOnInitComponent('projected', (rf: RenderFlags, ctx: any) => {
|
||||
let ProjectedComp = createOnInitComponent('projected', (rf: RenderFlags) => {
|
||||
if (rf & RenderFlags.Create) {
|
||||
Δtext(0, 'content');
|
||||
}
|
||||
|
@ -115,277 +115,4 @@ describe('lifecycles', () => {
|
|||
expect(events).toEqual(['comp', 'comp']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('hook order', () => {
|
||||
let events: string[];
|
||||
|
||||
beforeEach(() => { events = []; });
|
||||
|
||||
function createAllHooksComponent(
|
||||
name: string, template: ComponentTemplate<any>, consts: number = 0, vars: number = 0,
|
||||
directives: any[] = []) {
|
||||
return class Component {
|
||||
val: string = '';
|
||||
|
||||
ngOnChanges() { events.push(`changes ${name}${this.val}`); }
|
||||
|
||||
ngOnInit() { events.push(`init ${name}${this.val}`); }
|
||||
ngDoCheck() { events.push(`check ${name}${this.val}`); }
|
||||
|
||||
ngAfterContentInit() { events.push(`contentInit ${name}${this.val}`); }
|
||||
ngAfterContentChecked() { events.push(`contentCheck ${name}${this.val}`); }
|
||||
|
||||
ngAfterViewInit() { events.push(`viewInit ${name}${this.val}`); }
|
||||
ngAfterViewChecked() { events.push(`viewCheck ${name}${this.val}`); }
|
||||
|
||||
static ngComponentDef = ΔdefineComponent({
|
||||
type: Component,
|
||||
selectors: [[name]],
|
||||
factory: () => new Component(),
|
||||
consts: consts,
|
||||
vars: vars,
|
||||
inputs: {val: 'val'}, template,
|
||||
directives: directives,
|
||||
features: [ΔNgOnChangesFeature()],
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
it('should call all hooks in correct order', () => {
|
||||
const Comp = createAllHooksComponent('comp', (rf: RenderFlags, ctx: any) => {});
|
||||
|
||||
/**
|
||||
* <comp [val]="1"></comp>
|
||||
* <comp [val]="2"></comp>
|
||||
*/
|
||||
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
Δelement(0, 'comp');
|
||||
Δelement(1, 'comp');
|
||||
}
|
||||
// This template function is a little weird in that the `elementProperty` calls
|
||||
// below are directly setting values `1` and `2`, where normally there would be
|
||||
// a call to `bind()` that would do the work of seeing if something changed.
|
||||
// This means when `fixture.update()` is called below, ngOnChanges should fire,
|
||||
// even though the *value* itself never changed.
|
||||
if (rf & RenderFlags.Update) {
|
||||
ΔelementProperty(0, 'val', 1);
|
||||
Δselect(1);
|
||||
ΔelementProperty(1, 'val', 2);
|
||||
}
|
||||
}, 2, 0, [Comp]);
|
||||
|
||||
const fixture = new ComponentFixture(App);
|
||||
expect(events).toEqual([
|
||||
'changes comp1', 'init comp1', 'check comp1', 'changes comp2', 'init comp2', 'check comp2',
|
||||
'contentInit comp1', 'contentCheck comp1', 'contentInit comp2', 'contentCheck comp2',
|
||||
'viewInit comp1', 'viewCheck comp1', 'viewInit comp2', 'viewCheck comp2'
|
||||
]);
|
||||
|
||||
events = [];
|
||||
fixture.update(); // Changes are made due to lack of `bind()` call in template fn.
|
||||
expect(events).toEqual([
|
||||
'changes comp1', 'check comp1', 'changes comp2', 'check comp2', 'contentCheck comp1',
|
||||
'contentCheck comp2', 'viewCheck comp1', 'viewCheck comp2'
|
||||
]);
|
||||
});
|
||||
|
||||
it('should call all hooks in correct order with children', () => {
|
||||
const Comp = createAllHooksComponent('comp', (rf: RenderFlags, ctx: any) => {});
|
||||
|
||||
/** <comp [val]="val"></comp> */
|
||||
const Parent = createAllHooksComponent('parent', (rf: RenderFlags, ctx: any) => {
|
||||
if (rf & RenderFlags.Create) {
|
||||
Δelement(0, 'comp');
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
ΔelementProperty(0, 'val', Δbind(ctx.val));
|
||||
}
|
||||
}, 1, 1, [Comp]);
|
||||
|
||||
/**
|
||||
* <parent [val]="1"></parent>
|
||||
* <parent [val]="2"></parent>
|
||||
*/
|
||||
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
Δelement(0, 'parent');
|
||||
Δelement(1, 'parent');
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
ΔelementProperty(0, 'val', 1);
|
||||
Δselect(1);
|
||||
ΔelementProperty(1, 'val', 2);
|
||||
}
|
||||
}, 2, 0, [Parent]);
|
||||
|
||||
const fixture = new ComponentFixture(App);
|
||||
expect(events).toEqual([
|
||||
'changes parent1', 'init parent1', 'check parent1',
|
||||
'changes parent2', 'init parent2', 'check parent2',
|
||||
'contentInit parent1', 'contentCheck parent1', 'contentInit parent2',
|
||||
'contentCheck parent2', 'changes comp1', 'init comp1',
|
||||
'check comp1', 'contentInit comp1', 'contentCheck comp1',
|
||||
'viewInit comp1', 'viewCheck comp1', 'changes comp2',
|
||||
'init comp2', 'check comp2', 'contentInit comp2',
|
||||
'contentCheck comp2', 'viewInit comp2', 'viewCheck comp2',
|
||||
'viewInit parent1', 'viewCheck parent1', 'viewInit parent2',
|
||||
'viewCheck parent2'
|
||||
]);
|
||||
|
||||
events = [];
|
||||
fixture.update();
|
||||
expect(events).toEqual([
|
||||
'changes parent1', 'check parent1', 'changes parent2', 'check parent2',
|
||||
'contentCheck parent1', 'contentCheck parent2', 'check comp1', 'contentCheck comp1',
|
||||
'viewCheck comp1', 'check comp2', 'contentCheck comp2', 'viewCheck comp2',
|
||||
'viewCheck parent1', 'viewCheck parent2'
|
||||
]);
|
||||
|
||||
});
|
||||
|
||||
// Angular 5 reference: https://stackblitz.com/edit/lifecycle-hooks-ng
|
||||
it('should call all hooks in correct order with view and content', () => {
|
||||
const Content = createAllHooksComponent('content', (rf: RenderFlags, ctx: any) => {});
|
||||
|
||||
const View = createAllHooksComponent('view', (rf: RenderFlags, ctx: any) => {});
|
||||
|
||||
/** <ng-content></ng-content><view [val]="val"></view> */
|
||||
const Parent = createAllHooksComponent('parent', (rf: RenderFlags, ctx: any) => {
|
||||
if (rf & RenderFlags.Create) {
|
||||
ΔprojectionDef();
|
||||
Δprojection(0);
|
||||
Δelement(1, 'view');
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
Δselect(1);
|
||||
ΔelementProperty(1, 'val', Δbind(ctx.val));
|
||||
}
|
||||
}, 2, 1, [View]);
|
||||
|
||||
/**
|
||||
* <parent [val]="1">
|
||||
* <content [val]="1"></content>
|
||||
* </parent>
|
||||
* <parent [val]="2">
|
||||
* <content [val]="2"></content>
|
||||
* </parent>
|
||||
*/
|
||||
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
ΔelementStart(0, 'parent');
|
||||
{ Δelement(1, 'content'); }
|
||||
ΔelementEnd();
|
||||
ΔelementStart(2, 'parent');
|
||||
{ Δelement(3, 'content'); }
|
||||
ΔelementEnd();
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
ΔelementProperty(0, 'val', Δbind(1));
|
||||
Δselect(1);
|
||||
ΔelementProperty(1, 'val', Δbind(1));
|
||||
Δselect(2);
|
||||
ΔelementProperty(2, 'val', Δbind(2));
|
||||
Δselect(3);
|
||||
ΔelementProperty(3, 'val', Δbind(2));
|
||||
}
|
||||
}, 4, 4, [Parent, Content]);
|
||||
|
||||
const fixture = new ComponentFixture(App);
|
||||
expect(events).toEqual([
|
||||
'changes parent1', 'init parent1',
|
||||
'check parent1', 'changes content1',
|
||||
'init content1', 'check content1',
|
||||
'changes parent2', 'init parent2',
|
||||
'check parent2', 'changes content2',
|
||||
'init content2', 'check content2',
|
||||
'contentInit content1', 'contentCheck content1',
|
||||
'contentInit parent1', 'contentCheck parent1',
|
||||
'contentInit content2', 'contentCheck content2',
|
||||
'contentInit parent2', 'contentCheck parent2',
|
||||
'changes view1', 'init view1',
|
||||
'check view1', 'contentInit view1',
|
||||
'contentCheck view1', 'viewInit view1',
|
||||
'viewCheck view1', 'changes view2',
|
||||
'init view2', 'check view2',
|
||||
'contentInit view2', 'contentCheck view2',
|
||||
'viewInit view2', 'viewCheck view2',
|
||||
'viewInit content1', 'viewCheck content1',
|
||||
'viewInit parent1', 'viewCheck parent1',
|
||||
'viewInit content2', 'viewCheck content2',
|
||||
'viewInit parent2', 'viewCheck parent2'
|
||||
]);
|
||||
|
||||
events = [];
|
||||
fixture.update();
|
||||
expect(events).toEqual([
|
||||
'check parent1', 'check content1', 'check parent2', 'check content2',
|
||||
'contentCheck content1', 'contentCheck parent1', 'contentCheck content2',
|
||||
'contentCheck parent2', 'check view1', 'contentCheck view1', 'viewCheck view1',
|
||||
'check view2', 'contentCheck view2', 'viewCheck view2', 'viewCheck content1',
|
||||
'viewCheck parent1', 'viewCheck content2', 'viewCheck parent2'
|
||||
]);
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('non-regression', () => {
|
||||
|
||||
it('should call lifecycle hooks for directives active on <ng-template>', () => {
|
||||
let destroyed = false;
|
||||
|
||||
class OnDestroyDirective implements OnDestroy {
|
||||
ngOnDestroy() { destroyed = true; }
|
||||
|
||||
static ngDirectiveDef = ΔdefineDirective({
|
||||
type: OnDestroyDirective,
|
||||
selectors: [['', 'onDestroyDirective', '']],
|
||||
factory: () => new OnDestroyDirective()
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function conditionTpl(rf: RenderFlags, ctx: Cmpt) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
Δtemplate(0, null, 0, 1, 'ng-template', [AttributeMarker.Bindings, 'onDestroyDirective']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <ng-template [ngIf]="condition">
|
||||
* <ng-template onDestroyDirective></ng-template>
|
||||
* </ng-template>
|
||||
*/
|
||||
function cmptTpl(rf: RenderFlags, cmpt: Cmpt) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
Δtemplate(0, conditionTpl, 1, 1, 'ng-template', [AttributeMarker.Bindings, 'ngIf']);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
ΔelementProperty(0, 'ngIf', Δbind(cmpt.showing));
|
||||
}
|
||||
}
|
||||
|
||||
class Cmpt {
|
||||
showing = true;
|
||||
static ngComponentDef = ΔdefineComponent({
|
||||
type: Cmpt,
|
||||
factory: () => new Cmpt(),
|
||||
selectors: [['cmpt']],
|
||||
consts: 1,
|
||||
vars: 1,
|
||||
template: cmptTpl,
|
||||
directives: [NgIf, OnDestroyDirective]
|
||||
});
|
||||
}
|
||||
|
||||
const fixture = new ComponentFixture(Cmpt);
|
||||
expect(destroyed).toBeFalsy();
|
||||
|
||||
fixture.component.showing = false;
|
||||
fixture.update();
|
||||
expect(destroyed).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue