test(ivy): add afterViewInit acceptance tests (#30445)
Migrates afterViewInit and afterViewChecked render3 tests to acceptance tests PR Close #30445
This commit is contained in:
parent
a5e06ba629
commit
257e9646d0
|
@ -1209,3 +1209,681 @@ describe('afterContentChecked', () => {
|
|||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('afterViewInit', () => {
|
||||
it('should be called on creation and not in update mode', () => {
|
||||
let afterViewInitCalls = 0;
|
||||
|
||||
@Component({
|
||||
selector: 'comp',
|
||||
template: `<p>test</p>`,
|
||||
})
|
||||
class Comp {
|
||||
ngAfterViewInit() { afterViewInitCalls++; }
|
||||
}
|
||||
|
||||
@Component({template: `<comp></comp>`})
|
||||
class App {
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [App, Comp],
|
||||
});
|
||||
const fixture = TestBed.createComponent(App);
|
||||
fixture.detectChanges();
|
||||
|
||||
// two updates
|
||||
fixture.detectChanges();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(afterViewInitCalls).toBe(1);
|
||||
|
||||
});
|
||||
|
||||
it('should be called on root component in creation mode', () => {
|
||||
let afterViewInitCalls = 0;
|
||||
|
||||
@Component({template: `<p>test</p>`})
|
||||
class App {
|
||||
ngAfterViewInit() { afterViewInitCalls++; }
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [App],
|
||||
});
|
||||
const fixture = TestBed.createComponent(App);
|
||||
fixture.detectChanges();
|
||||
|
||||
// two updates
|
||||
fixture.detectChanges();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(afterViewInitCalls).toBe(1);
|
||||
});
|
||||
|
||||
it('should be called every time a view is initialized with ngIf', () => {
|
||||
const events: string[] = [];
|
||||
|
||||
@Component({
|
||||
selector: 'comp',
|
||||
template: `<p>test</p>`,
|
||||
})
|
||||
class Comp {
|
||||
ngAfterViewInit() { events.push('comp'); }
|
||||
}
|
||||
|
||||
@Component({
|
||||
template: `<comp *ngIf="show"></comp>`,
|
||||
})
|
||||
class App {
|
||||
show = true;
|
||||
|
||||
ngAfterViewInit() { events.push('app'); }
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [App, Comp],
|
||||
});
|
||||
const fixture = TestBed.createComponent(App);
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(events).toEqual(['comp', 'app']);
|
||||
|
||||
fixture.componentInstance.show = false;
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(events).toEqual(['comp', 'app']);
|
||||
|
||||
fixture.componentInstance.show = true;
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(events).toEqual(['comp', 'app', 'comp']);
|
||||
});
|
||||
|
||||
it('should be called in children before parents', () => {
|
||||
const events: string[] = [];
|
||||
|
||||
@Component({
|
||||
selector: 'parent',
|
||||
template: `<child [name]=name></child>`,
|
||||
})
|
||||
class Parent {
|
||||
@Input()
|
||||
name = '';
|
||||
|
||||
ngAfterViewInit() { events.push('parent ' + this.name); }
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'child',
|
||||
template: `<p>test</p>`,
|
||||
})
|
||||
class Child {
|
||||
@Input()
|
||||
name = '';
|
||||
|
||||
ngAfterViewInit() { events.push('child of parent ' + this.name); }
|
||||
}
|
||||
|
||||
@Component({
|
||||
template: `
|
||||
<parent name="1"></parent>
|
||||
<parent name="2"></parent>
|
||||
`
|
||||
})
|
||||
class App {
|
||||
ngAfterViewInit() { events.push('app'); }
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [App, Parent, Child],
|
||||
});
|
||||
const fixture = TestBed.createComponent(App);
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(events).toEqual([
|
||||
'child of parent 1',
|
||||
'child of parent 2',
|
||||
'parent 1',
|
||||
'parent 2',
|
||||
'app',
|
||||
]);
|
||||
});
|
||||
|
||||
it('should be called in projected components before their hosts', () => {
|
||||
const events: string[] = [];
|
||||
|
||||
@Component({
|
||||
selector: 'projected',
|
||||
template: `<p>test</p>`,
|
||||
})
|
||||
class Projected {
|
||||
@Input()
|
||||
name = '';
|
||||
|
||||
ngAfterViewInit() { events.push('projected ' + this.name); }
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'comp',
|
||||
template: `<ng-content></ng-content>`,
|
||||
})
|
||||
class Comp {
|
||||
@Input()
|
||||
name = '';
|
||||
|
||||
ngAfterViewInit() { events.push('comp ' + this.name); }
|
||||
}
|
||||
|
||||
@Component({
|
||||
template: `
|
||||
<comp name="1"><projected name="1"></projected></comp>
|
||||
<comp name="2"><projected name="2"></projected></comp>
|
||||
`
|
||||
})
|
||||
class App {
|
||||
ngAfterViewInit() { events.push('app'); }
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [App, Comp, Projected],
|
||||
});
|
||||
const fixture = TestBed.createComponent(App);
|
||||
fixture.detectChanges();
|
||||
|
||||
|
||||
expect(events).toEqual([
|
||||
'projected 1',
|
||||
'comp 1',
|
||||
'projected 2',
|
||||
'comp 2',
|
||||
'app',
|
||||
]);
|
||||
});
|
||||
|
||||
it('should call afterViewInit in content children and host before next host', () => {
|
||||
const events: string[] = [];
|
||||
|
||||
@Component({
|
||||
selector: 'projected-child',
|
||||
template: `<p>test</p>`,
|
||||
})
|
||||
class ProjectedChild {
|
||||
@Input()
|
||||
name = '';
|
||||
|
||||
ngAfterViewInit() { events.push('child of projected ' + this.name); }
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'projected',
|
||||
template: `<projected-child [name]="name"></projected-child>`,
|
||||
})
|
||||
class Projected {
|
||||
@Input()
|
||||
name = '';
|
||||
|
||||
ngAfterViewInit() { events.push('projected ' + this.name); }
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'comp',
|
||||
template: `<div><ng-content></ng-content></div>`,
|
||||
})
|
||||
class Comp {
|
||||
@Input()
|
||||
name = '';
|
||||
|
||||
ngAfterViewInit() { events.push('comp ' + this.name); }
|
||||
}
|
||||
|
||||
@Component({
|
||||
template: `
|
||||
<comp name="1"><projected name="1"></projected></comp>
|
||||
<comp name="2"><projected name="2"></projected></comp>
|
||||
`
|
||||
})
|
||||
class App {
|
||||
ngAfterViewInit() { events.push('app'); }
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [App, Comp, Projected, ProjectedChild],
|
||||
});
|
||||
const fixture = TestBed.createComponent(App);
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(events).toEqual([
|
||||
'child of projected 1',
|
||||
'child of projected 2',
|
||||
'projected 1',
|
||||
'comp 1',
|
||||
'projected 2',
|
||||
'comp 2',
|
||||
'app',
|
||||
]);
|
||||
});
|
||||
|
||||
it('should be called in correct order with ngFor', () => {
|
||||
const events: string[] = [];
|
||||
|
||||
@Component({
|
||||
selector: 'comp',
|
||||
template: `<p>test</p>`,
|
||||
})
|
||||
class Comp {
|
||||
@Input()
|
||||
name = '';
|
||||
|
||||
ngAfterViewInit() { events.push('comp ' + this.name); }
|
||||
}
|
||||
|
||||
@Component({
|
||||
template: `
|
||||
<comp name="4"></comp>
|
||||
<comp *ngFor="let number of numbers" [name]="number"></comp>
|
||||
<comp name="5"></comp>
|
||||
`
|
||||
})
|
||||
class App {
|
||||
numbers = [0, 1, 2, 3];
|
||||
|
||||
ngAfterViewInit() { events.push('app'); }
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [App, Comp],
|
||||
imports: [CommonModule],
|
||||
});
|
||||
const fixture = TestBed.createComponent(App);
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(events).toEqual([
|
||||
'comp 0',
|
||||
'comp 1',
|
||||
'comp 2',
|
||||
'comp 3',
|
||||
'comp 4',
|
||||
'comp 5',
|
||||
'app',
|
||||
]);
|
||||
});
|
||||
|
||||
it('should be called in correct order with for loops with children', () => {
|
||||
const events: string[] = [];
|
||||
|
||||
@Component({
|
||||
selector: 'child',
|
||||
template: `<p>test</p>`,
|
||||
})
|
||||
class Child {
|
||||
@Input()
|
||||
name = '';
|
||||
|
||||
ngAfterViewInit() { events.push('child of parent ' + this.name); }
|
||||
}
|
||||
@Component({
|
||||
selector: 'parent',
|
||||
template: `<child [name]="name"></child>`,
|
||||
})
|
||||
class Parent {
|
||||
@Input()
|
||||
name = '';
|
||||
|
||||
ngAfterViewInit() { events.push('parent ' + this.name); }
|
||||
}
|
||||
|
||||
@Component({
|
||||
template: `
|
||||
<parent name="4"></parent>
|
||||
<parent *ngFor="let number of numbers" [name]="number"></parent>
|
||||
<parent name="5"></parent>
|
||||
`
|
||||
})
|
||||
class App {
|
||||
numbers = [0, 1, 2, 3];
|
||||
|
||||
ngAfterViewInit() { events.push('app'); }
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [App, Parent, Child],
|
||||
imports: [CommonModule],
|
||||
});
|
||||
const fixture = TestBed.createComponent(App);
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(events).toEqual([
|
||||
'child of parent 0',
|
||||
'parent 0',
|
||||
'child of parent 1',
|
||||
'parent 1',
|
||||
'child of parent 2',
|
||||
'parent 2',
|
||||
'child of parent 3',
|
||||
'parent 3',
|
||||
'child of parent 4',
|
||||
'child of parent 5',
|
||||
'parent 4',
|
||||
'parent 5',
|
||||
'app',
|
||||
]);
|
||||
});
|
||||
|
||||
it('should be called on directives after component', () => {
|
||||
const events: string[] = [];
|
||||
|
||||
@Directive({
|
||||
selector: '[dir]',
|
||||
})
|
||||
class Dir {
|
||||
@Input('dir')
|
||||
name = '';
|
||||
|
||||
ngAfterViewInit() { events.push('dir ' + this.name); }
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'comp',
|
||||
template: `<p>test</p>`,
|
||||
})
|
||||
class Comp {
|
||||
@Input()
|
||||
name = '';
|
||||
|
||||
ngAfterViewInit() { events.push('comp ' + this.name); }
|
||||
}
|
||||
|
||||
@Component({
|
||||
template: `
|
||||
<comp name="1" dir="1"></comp>
|
||||
<comp name="2" dir="2"></comp>
|
||||
`
|
||||
})
|
||||
class App {
|
||||
ngAfterViewInit() { events.push('app'); }
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [App, Comp, Dir],
|
||||
});
|
||||
const fixture = TestBed.createComponent(App);
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(events).toEqual([
|
||||
'comp 1',
|
||||
'dir 1',
|
||||
'comp 2',
|
||||
'dir 2',
|
||||
'app',
|
||||
]);
|
||||
});
|
||||
|
||||
it('should be called on directives on an element', () => {
|
||||
const events: string[] = [];
|
||||
|
||||
@Directive({
|
||||
selector: '[dir]',
|
||||
})
|
||||
class Dir {
|
||||
@Input('dir')
|
||||
name = '';
|
||||
|
||||
ngAfterViewInit() { events.push('dir ' + this.name); }
|
||||
}
|
||||
|
||||
@Component({
|
||||
template: `
|
||||
<div dir="1"></div>
|
||||
<div dir="2"></div>
|
||||
`
|
||||
})
|
||||
class App {
|
||||
ngAfterViewInit() { events.push('app'); }
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [App, Dir],
|
||||
});
|
||||
const fixture = TestBed.createComponent(App);
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(events).toEqual([
|
||||
'dir 1',
|
||||
'dir 2',
|
||||
'app',
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('ngAfterViewChecked', () => {
|
||||
it('should call ngAfterViewChecked every update', () => {
|
||||
let afterViewCheckedCalls = 0;
|
||||
|
||||
@Component({
|
||||
selector: 'comp',
|
||||
template: `<p>test</p>`,
|
||||
})
|
||||
class Comp {
|
||||
ngAfterViewChecked() { afterViewCheckedCalls++; }
|
||||
}
|
||||
|
||||
@Component({template: `<comp></comp>`})
|
||||
class App {
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [App, Comp],
|
||||
});
|
||||
const fixture = TestBed.createComponent(App);
|
||||
|
||||
fixture.detectChanges();
|
||||
expect(afterViewCheckedCalls).toBe(1);
|
||||
|
||||
fixture.detectChanges();
|
||||
expect(afterViewCheckedCalls).toBe(2);
|
||||
|
||||
fixture.detectChanges();
|
||||
expect(afterViewCheckedCalls).toBe(3);
|
||||
});
|
||||
|
||||
it('should be called on root component', () => {
|
||||
let afterViewCheckedCalls = 0;
|
||||
|
||||
@Component({template: `<p>test</p>`})
|
||||
class App {
|
||||
ngAfterViewChecked() { afterViewCheckedCalls++; }
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [App],
|
||||
});
|
||||
const fixture = TestBed.createComponent(App);
|
||||
|
||||
fixture.detectChanges();
|
||||
expect(afterViewCheckedCalls).toBe(1);
|
||||
|
||||
fixture.detectChanges();
|
||||
expect(afterViewCheckedCalls).toBe(2);
|
||||
|
||||
fixture.detectChanges();
|
||||
expect(afterViewCheckedCalls).toBe(3);
|
||||
});
|
||||
|
||||
it('should call ngAfterViewChecked with bindings', () => {
|
||||
let afterViewCheckedCalls = 0;
|
||||
|
||||
@Component({
|
||||
selector: 'comp',
|
||||
template: `<p>{{value}}</p>`,
|
||||
})
|
||||
class Comp {
|
||||
@Input()
|
||||
value = '';
|
||||
ngAfterViewChecked() { afterViewCheckedCalls++; }
|
||||
}
|
||||
|
||||
@Component({template: `<comp [value]="value"></comp>`})
|
||||
class App {
|
||||
value = 1;
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [App, Comp],
|
||||
});
|
||||
const fixture = TestBed.createComponent(App);
|
||||
fixture.detectChanges();
|
||||
expect(afterViewCheckedCalls).toBe(1);
|
||||
|
||||
fixture.componentInstance.value = 1337;
|
||||
fixture.detectChanges();
|
||||
expect(afterViewCheckedCalls).toBe(2);
|
||||
});
|
||||
|
||||
it('should be called in correct order with for loops with children', () => {
|
||||
const events: string[] = [];
|
||||
|
||||
@Component({
|
||||
selector: 'child',
|
||||
template: `<p>test</p>`,
|
||||
})
|
||||
class Child {
|
||||
@Input()
|
||||
name = '';
|
||||
|
||||
ngAfterViewChecked() { events.push('child of parent ' + this.name); }
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'parent',
|
||||
template: `<child [name]="name"></child>`,
|
||||
})
|
||||
class Parent {
|
||||
@Input()
|
||||
name = '';
|
||||
|
||||
ngAfterViewChecked() { events.push('parent ' + this.name); }
|
||||
}
|
||||
|
||||
@Component({
|
||||
template: `
|
||||
<parent name="4"></parent>
|
||||
<parent *ngFor="let number of numbers" [name]="number"></parent>
|
||||
<parent name="5"></parent>
|
||||
`
|
||||
})
|
||||
class App {
|
||||
numbers = [0, 1, 2, 3];
|
||||
|
||||
ngAfterViewChecked() { events.push('app'); }
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [App, Parent, Child],
|
||||
});
|
||||
const fixture = TestBed.createComponent(App);
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(events).toEqual([
|
||||
'child of parent 0',
|
||||
'parent 0',
|
||||
'child of parent 1',
|
||||
'parent 1',
|
||||
'child of parent 2',
|
||||
'parent 2',
|
||||
'child of parent 3',
|
||||
'parent 3',
|
||||
'child of parent 4',
|
||||
'child of parent 5',
|
||||
'parent 4',
|
||||
'parent 5',
|
||||
'app',
|
||||
]);
|
||||
});
|
||||
|
||||
it('should be called on directives after component', () => {
|
||||
const events: string[] = [];
|
||||
|
||||
@Directive({
|
||||
selector: '[dir]',
|
||||
})
|
||||
class Dir {
|
||||
@Input('dir')
|
||||
name = '';
|
||||
|
||||
ngAfterViewChecked() { events.push('dir ' + this.name); }
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'comp',
|
||||
template: `<p>test</p>`,
|
||||
})
|
||||
class Comp {
|
||||
@Input()
|
||||
name = '';
|
||||
|
||||
ngAfterViewChecked() { events.push('comp ' + this.name); }
|
||||
}
|
||||
|
||||
@Component({
|
||||
template: `
|
||||
<comp name="1" dir="1"></comp>
|
||||
<comp name="2" dir="2"></comp>
|
||||
`
|
||||
})
|
||||
class App {
|
||||
ngAfterViewChecked() { events.push('app'); }
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [App, Comp, Dir],
|
||||
});
|
||||
const fixture = TestBed.createComponent(App);
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(events).toEqual([
|
||||
'comp 1',
|
||||
'dir 1',
|
||||
'comp 2',
|
||||
'dir 2',
|
||||
'app',
|
||||
]);
|
||||
});
|
||||
|
||||
it('should be called on directives on an element', () => {
|
||||
const events: string[] = [];
|
||||
|
||||
@Directive({
|
||||
selector: '[dir]',
|
||||
})
|
||||
class Dir {
|
||||
@Input('dir')
|
||||
name = '';
|
||||
|
||||
ngAfterViewChecked() { events.push('dir ' + this.name); }
|
||||
}
|
||||
|
||||
@Component({
|
||||
template: `
|
||||
<div dir="1"></div>
|
||||
<div dir="2"></div>
|
||||
`
|
||||
})
|
||||
class App {
|
||||
ngAfterViewChecked() { events.push('app'); }
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [App, Dir],
|
||||
});
|
||||
const fixture = TestBed.createComponent(App);
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(events).toEqual([
|
||||
'dir 1',
|
||||
'dir 2',
|
||||
'app',
|
||||
]);
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
@ -116,858 +116,6 @@ describe('lifecycles', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('afterContentInit', () => {
|
||||
let events: string[];
|
||||
let allEvents: string[];
|
||||
|
||||
beforeEach(() => {
|
||||
events = [];
|
||||
allEvents = [];
|
||||
});
|
||||
|
||||
let Comp = createAfterContentInitComp('comp', function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
ΔprojectionDef();
|
||||
Δprojection(0);
|
||||
}
|
||||
}, 1);
|
||||
|
||||
let Parent = createAfterContentInitComp('parent', function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
ΔprojectionDef();
|
||||
ΔelementStart(0, 'comp');
|
||||
{ Δprojection(1); }
|
||||
ΔelementEnd();
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
ΔelementProperty(0, 'val', Δbind(ctx.val));
|
||||
}
|
||||
}, 2, 1, [Comp]);
|
||||
|
||||
let ProjectedComp = createAfterContentInitComp('projected', (rf: RenderFlags, ctx: any) => {
|
||||
if (rf & RenderFlags.Create) {
|
||||
ΔprojectionDef();
|
||||
Δprojection(0);
|
||||
}
|
||||
}, 1);
|
||||
|
||||
function createAfterContentInitComp(
|
||||
name: string, template: ComponentTemplate<any>, consts: number = 0, vars: number = 0,
|
||||
directives: any[] = []) {
|
||||
return class Component {
|
||||
val: string = '';
|
||||
ngAfterContentInit() {
|
||||
events.push(`${name}${this.val}`);
|
||||
allEvents.push(`${name}${this.val} init`);
|
||||
}
|
||||
ngAfterContentChecked() { allEvents.push(`${name}${this.val} check`); }
|
||||
|
||||
static ngComponentDef = ΔdefineComponent({
|
||||
type: Component,
|
||||
selectors: [[name]],
|
||||
factory: () => new Component(),
|
||||
consts: consts,
|
||||
vars: vars,
|
||||
inputs: {val: 'val'},
|
||||
template: template,
|
||||
directives: directives
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
class Directive {
|
||||
ngAfterContentInit() { events.push('init'); }
|
||||
ngAfterContentChecked() { events.push('check'); }
|
||||
|
||||
static ngDirectiveDef = ΔdefineDirective(
|
||||
{type: Directive, selectors: [['', 'dir', '']], factory: () => new Directive()});
|
||||
}
|
||||
|
||||
function ForLoopWithChildrenTemplate(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
ΔelementStart(0, 'parent');
|
||||
{ Δtext(1, 'content'); }
|
||||
ΔelementEnd();
|
||||
Δcontainer(2);
|
||||
ΔelementStart(3, 'parent');
|
||||
{ Δtext(4, 'content'); }
|
||||
ΔelementEnd();
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
ΔelementProperty(0, 'val', 1);
|
||||
Δselect(3);
|
||||
ΔelementProperty(3, 'val', 4);
|
||||
ΔcontainerRefreshStart(2);
|
||||
{
|
||||
for (let i = 2; i < 4; i++) {
|
||||
let rf1 = ΔembeddedViewStart(0, 2, 0);
|
||||
if (rf1 & RenderFlags.Create) {
|
||||
ΔelementStart(0, 'parent');
|
||||
{ Δtext(1, 'content'); }
|
||||
ΔelementEnd();
|
||||
}
|
||||
if (rf1 & RenderFlags.Update) {
|
||||
ΔelementProperty(0, 'val', i);
|
||||
}
|
||||
ΔembeddedViewEnd();
|
||||
}
|
||||
}
|
||||
ΔcontainerRefreshEnd();
|
||||
}
|
||||
}
|
||||
|
||||
const directives = [Comp, Parent, ProjectedComp, Directive];
|
||||
|
||||
it('should be called only in creation mode', () => {
|
||||
/** <comp>content</comp> */
|
||||
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
ΔelementStart(0, 'comp');
|
||||
{ Δtext(1, 'content'); }
|
||||
ΔelementEnd();
|
||||
}
|
||||
}, 2, 0, directives);
|
||||
|
||||
const fixture = new ComponentFixture(App);
|
||||
expect(events).toEqual(['comp']);
|
||||
|
||||
fixture.update();
|
||||
expect(events).toEqual(['comp']);
|
||||
});
|
||||
|
||||
it('should be called on root component in creation mode', () => {
|
||||
const comp = renderComponent(Comp, {hostFeatures: [LifecycleHooksFeature]});
|
||||
expect(events).toEqual(['comp']);
|
||||
|
||||
markDirty(comp);
|
||||
requestAnimationFrame.flush();
|
||||
expect(events).toEqual(['comp']);
|
||||
});
|
||||
|
||||
it('should be called on every init (if blocks)', () => {
|
||||
/**
|
||||
* % if (!skip) {
|
||||
* <comp>content</comp>
|
||||
* % }
|
||||
*/
|
||||
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
Δcontainer(0);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
ΔcontainerRefreshStart(0);
|
||||
{
|
||||
if (!ctx.skip) {
|
||||
let rf1 = ΔembeddedViewStart(0, 2, 0);
|
||||
if (rf1 & RenderFlags.Create) {
|
||||
ΔelementStart(0, 'comp');
|
||||
{ Δtext(1, 'content'); }
|
||||
ΔelementEnd();
|
||||
}
|
||||
ΔembeddedViewEnd();
|
||||
}
|
||||
}
|
||||
ΔcontainerRefreshEnd();
|
||||
}
|
||||
}, 1, 0, directives);
|
||||
|
||||
const fixture = new ComponentFixture(App);
|
||||
expect(events).toEqual(['comp']);
|
||||
|
||||
fixture.component.skip = true;
|
||||
fixture.update();
|
||||
expect(events).toEqual(['comp']);
|
||||
|
||||
fixture.component.skip = false;
|
||||
fixture.update();
|
||||
expect(events).toEqual(['comp', 'comp']);
|
||||
});
|
||||
|
||||
it('should be called in parents before children', () => {
|
||||
/**
|
||||
* <parent>content</parent>
|
||||
*
|
||||
* parent template: <comp><ng-content></ng-content></comp>
|
||||
*/
|
||||
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
ΔelementStart(0, 'parent');
|
||||
{ Δtext(1, 'content'); }
|
||||
ΔelementEnd();
|
||||
}
|
||||
}, 2, 0, directives);
|
||||
|
||||
const fixture = new ComponentFixture(App);
|
||||
expect(events).toEqual(['parent', 'comp']);
|
||||
});
|
||||
|
||||
it('should be called breadth-first in entire parent subtree before any children', () => {
|
||||
/**
|
||||
* <parent [val]="1">content</parent>
|
||||
* <parent [val]="2">content</parent>
|
||||
*
|
||||
* parent template: <comp [val]="val"><ng-content></ng-content></comp>
|
||||
*/
|
||||
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
ΔelementStart(0, 'parent');
|
||||
{ Δtext(1, 'content'); }
|
||||
ΔelementEnd();
|
||||
ΔelementStart(2, 'parent');
|
||||
{ Δtext(3, 'content'); }
|
||||
ΔelementEnd();
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
ΔelementProperty(0, 'val', 1);
|
||||
Δselect(2);
|
||||
ΔelementProperty(2, 'val', 2);
|
||||
}
|
||||
}, 4, 0, directives);
|
||||
|
||||
const fixture = new ComponentFixture(App);
|
||||
expect(events).toEqual(['parent1', 'parent2', 'comp1', 'comp2']);
|
||||
});
|
||||
|
||||
it('should be called in projected components before their hosts', () => {
|
||||
/**
|
||||
* <parent>
|
||||
* <projected>content</projected>
|
||||
* </parent>
|
||||
*
|
||||
* parent template:
|
||||
* <comp><ng-content></ng-content></comp>
|
||||
*
|
||||
* projected comp: <ng-content></ng-content>
|
||||
*/
|
||||
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
ΔelementStart(0, 'parent');
|
||||
{
|
||||
ΔelementStart(1, 'projected');
|
||||
{ Δtext(2, 'content'); }
|
||||
ΔelementEnd();
|
||||
}
|
||||
ΔelementEnd();
|
||||
}
|
||||
}, 3, 0, directives);
|
||||
|
||||
const fixture = new ComponentFixture(App);
|
||||
expect(events).toEqual(['projected', 'parent', 'comp']);
|
||||
});
|
||||
|
||||
it('should be called in projected components and hosts before children', () => {
|
||||
/**
|
||||
* <parent [val]="1">
|
||||
* <projected [val]="1">content</projected>
|
||||
* </parent>
|
||||
* * <parent [val]="2">
|
||||
* <projected [val]="2">content</projected>
|
||||
* </parent>
|
||||
*
|
||||
* parent template:
|
||||
* <comp [val]="val"><ng-content></ng-content></comp>
|
||||
*
|
||||
* projected comp: <ng-content></ng-content>
|
||||
*/
|
||||
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
ΔelementStart(0, 'parent');
|
||||
{
|
||||
ΔelementStart(1, 'projected');
|
||||
{ Δtext(2, 'content'); }
|
||||
ΔelementEnd();
|
||||
}
|
||||
ΔelementEnd();
|
||||
ΔelementStart(3, 'parent');
|
||||
{
|
||||
ΔelementStart(4, 'projected');
|
||||
{ Δtext(5, 'content'); }
|
||||
ΔelementEnd();
|
||||
}
|
||||
ΔelementEnd();
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
ΔelementProperty(0, 'val', 1);
|
||||
Δselect(1);
|
||||
ΔelementProperty(1, 'val', 1);
|
||||
Δselect(3);
|
||||
ΔelementProperty(3, 'val', 2);
|
||||
Δselect(4);
|
||||
ΔelementProperty(4, 'val', 2);
|
||||
}
|
||||
}, 6, 0, directives);
|
||||
|
||||
const fixture = new ComponentFixture(App);
|
||||
expect(events).toEqual(['projected1', 'parent1', 'projected2', 'parent2', 'comp1', 'comp2']);
|
||||
});
|
||||
|
||||
it('should be called in correct order in a for loop', () => {
|
||||
/**
|
||||
* <comp [val]="1">content</comp>
|
||||
* % for(let i = 2; i < 4; i++) {
|
||||
* <comp [val]="i">content</comp>
|
||||
* % }
|
||||
* <comp [val]="4">content</comp>
|
||||
*/
|
||||
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
ΔelementStart(0, 'comp');
|
||||
{ Δtext(1, 'content'); }
|
||||
ΔelementEnd();
|
||||
Δcontainer(2);
|
||||
ΔelementStart(3, 'comp');
|
||||
{ Δtext(4, 'content'); }
|
||||
ΔelementEnd();
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
ΔelementProperty(0, 'val', 1);
|
||||
Δselect(3);
|
||||
ΔelementProperty(3, 'val', 4);
|
||||
ΔcontainerRefreshStart(2);
|
||||
{
|
||||
for (let i = 2; i < 4; i++) {
|
||||
let rf1 = ΔembeddedViewStart(0, 2, 0);
|
||||
if (rf1 & RenderFlags.Create) {
|
||||
ΔelementStart(0, 'comp');
|
||||
{ Δtext(1, 'content'); }
|
||||
ΔelementEnd();
|
||||
}
|
||||
if (rf1 & RenderFlags.Update) {
|
||||
ΔelementProperty(0, 'val', i);
|
||||
}
|
||||
ΔembeddedViewEnd();
|
||||
}
|
||||
}
|
||||
ΔcontainerRefreshEnd();
|
||||
}
|
||||
}, 5, 0, directives);
|
||||
|
||||
const fixture = new ComponentFixture(App);
|
||||
expect(events).toEqual(['comp2', 'comp3', 'comp1', 'comp4']);
|
||||
});
|
||||
|
||||
it('should be called in correct order in a for loop with children', () => {
|
||||
/**
|
||||
* <parent [val]="1">content</parent>
|
||||
* % for(let i = 2; i < 4; i++) {
|
||||
* <parent [val]="i">content</parent>
|
||||
* % }
|
||||
* <parent [val]="4">content</parent>
|
||||
*/
|
||||
|
||||
renderToHtml(ForLoopWithChildrenTemplate, {}, 5, 0, directives);
|
||||
expect(events).toEqual(
|
||||
['parent2', 'comp2', 'parent3', 'comp3', 'parent1', 'parent4', 'comp1', 'comp4']);
|
||||
});
|
||||
|
||||
describe('ngAfterContentChecked', () => {
|
||||
|
||||
it('should be called every change detection run after afterContentInit', () => {
|
||||
/** <comp>content</comp> */
|
||||
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
ΔelementStart(0, 'comp');
|
||||
{ Δtext(1, 'content'); }
|
||||
ΔelementEnd();
|
||||
}
|
||||
}, 2, 0, directives);
|
||||
|
||||
const fixture = new ComponentFixture(App);
|
||||
expect(allEvents).toEqual(['comp init', 'comp check']);
|
||||
|
||||
fixture.update();
|
||||
expect(allEvents).toEqual(['comp init', 'comp check', 'comp check']);
|
||||
});
|
||||
|
||||
it('should be called on root component', () => {
|
||||
const comp = renderComponent(Comp, {hostFeatures: [LifecycleHooksFeature]});
|
||||
expect(allEvents).toEqual(['comp init', 'comp check']);
|
||||
|
||||
markDirty(comp);
|
||||
requestAnimationFrame.flush();
|
||||
expect(allEvents).toEqual(['comp init', 'comp check', 'comp check']);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('directives', () => {
|
||||
it('should be called on directives after component', () => {
|
||||
/** <comp directive></comp> */
|
||||
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
Δelement(0, 'comp', ['dir', '']);
|
||||
}
|
||||
}, 1, 0, directives);
|
||||
|
||||
const fixture = new ComponentFixture(App);
|
||||
expect(events).toEqual(['comp', 'init', 'check']);
|
||||
});
|
||||
|
||||
it('should be called on directives on an element', () => {
|
||||
/** <div directive></div> */
|
||||
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
Δelement(0, 'div', ['dir', '']);
|
||||
}
|
||||
}, 1, 0, directives);
|
||||
|
||||
const fixture = new ComponentFixture(App);
|
||||
expect(events).toEqual(['init', 'check']);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('afterViewInit', () => {
|
||||
let events: string[];
|
||||
let allEvents: string[];
|
||||
|
||||
beforeEach(() => {
|
||||
events = [];
|
||||
allEvents = [];
|
||||
});
|
||||
|
||||
let Comp = createAfterViewInitComponent('comp', (rf: RenderFlags, ctx: any) => {
|
||||
if (rf & RenderFlags.Create) {
|
||||
ΔprojectionDef();
|
||||
ΔelementStart(0, 'div');
|
||||
{ Δprojection(1); }
|
||||
ΔelementEnd();
|
||||
}
|
||||
}, 2);
|
||||
let Parent = createAfterViewInitComponent('parent', getParentTemplate('comp'), 1, 1, [Comp]);
|
||||
|
||||
let ProjectedComp = createAfterViewInitComponent('projected', (rf: RenderFlags, ctx: any) => {
|
||||
if (rf & RenderFlags.Create) {
|
||||
Δtext(0, 'content');
|
||||
}
|
||||
}, 1);
|
||||
|
||||
function createAfterViewInitComponent(
|
||||
name: string, template: ComponentTemplate<any>, consts: number, vars: number = 0,
|
||||
directives: any[] = []) {
|
||||
return class Component {
|
||||
val: string = '';
|
||||
ngAfterViewInit() {
|
||||
if (!this.val) this.val = '';
|
||||
events.push(`${name}${this.val}`);
|
||||
allEvents.push(`${name}${this.val} init`);
|
||||
}
|
||||
ngAfterViewChecked() { allEvents.push(`${name}${this.val} check`); }
|
||||
|
||||
static ngComponentDef = ΔdefineComponent({
|
||||
type: Component,
|
||||
selectors: [[name]],
|
||||
consts: consts,
|
||||
vars: vars,
|
||||
factory: () => new Component(),
|
||||
inputs: {val: 'val'},
|
||||
template: template,
|
||||
directives: directives
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
class Directive {
|
||||
ngAfterViewInit() { events.push('init'); }
|
||||
ngAfterViewChecked() { events.push('check'); }
|
||||
|
||||
static ngDirectiveDef = ΔdefineDirective(
|
||||
{type: Directive, selectors: [['', 'dir', '']], factory: () => new Directive()});
|
||||
}
|
||||
|
||||
const defs = [Comp, Parent, ProjectedComp, Directive];
|
||||
|
||||
it('should be called on init and not in update mode', () => {
|
||||
/** <comp></comp> */
|
||||
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
Δelement(0, 'comp');
|
||||
}
|
||||
}, 1, 0, defs);
|
||||
|
||||
const fixture = new ComponentFixture(App);
|
||||
expect(events).toEqual(['comp']);
|
||||
|
||||
fixture.update();
|
||||
expect(events).toEqual(['comp']);
|
||||
});
|
||||
|
||||
it('should be called on root component in creation mode', () => {
|
||||
const comp = renderComponent(Comp, {hostFeatures: [LifecycleHooksFeature]});
|
||||
expect(events).toEqual(['comp']);
|
||||
|
||||
markDirty(comp);
|
||||
requestAnimationFrame.flush();
|
||||
expect(events).toEqual(['comp']);
|
||||
});
|
||||
|
||||
it('should be called every time a view is initialized (if block)', () => {
|
||||
/*
|
||||
* % if (!skip) {
|
||||
* <comp></comp>
|
||||
* % }
|
||||
*/
|
||||
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
Δcontainer(0);
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
ΔcontainerRefreshStart(0);
|
||||
{
|
||||
if (!ctx.skip) {
|
||||
let rf1 = ΔembeddedViewStart(0, 1, 0);
|
||||
if (rf1 & RenderFlags.Create) {
|
||||
Δelement(0, 'comp');
|
||||
}
|
||||
ΔembeddedViewEnd();
|
||||
}
|
||||
}
|
||||
ΔcontainerRefreshEnd();
|
||||
}
|
||||
}, 1, 0, defs);
|
||||
|
||||
const fixture = new ComponentFixture(App);
|
||||
expect(events).toEqual(['comp']);
|
||||
|
||||
fixture.component.skip = true;
|
||||
fixture.update();
|
||||
expect(events).toEqual(['comp']);
|
||||
|
||||
fixture.component.skip = false;
|
||||
fixture.update();
|
||||
expect(events).toEqual(['comp', 'comp']);
|
||||
|
||||
});
|
||||
|
||||
it('should be called in children before parents', () => {
|
||||
/**
|
||||
* <parent></parent>
|
||||
*
|
||||
* parent temp: <comp></comp>
|
||||
*/
|
||||
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
Δelement(0, 'parent');
|
||||
}
|
||||
}, 1, 0, defs);
|
||||
|
||||
const fixture = new ComponentFixture(App);
|
||||
expect(events).toEqual(['comp', 'parent']);
|
||||
});
|
||||
|
||||
it('should be called for entire subtree before being called in any parent view comps', () => {
|
||||
/**
|
||||
* <parent [val]="1"></parent>
|
||||
* <parent [val]="2"></parent>
|
||||
*
|
||||
* parent temp: <comp [val]="val"></comp>
|
||||
*/
|
||||
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, defs);
|
||||
|
||||
const fixture = new ComponentFixture(App);
|
||||
expect(events).toEqual(['comp1', 'comp2', 'parent1', 'parent2']);
|
||||
|
||||
});
|
||||
|
||||
it('should be called in projected components before their hosts', () => {
|
||||
/**
|
||||
* <comp>
|
||||
* <projected></projected>
|
||||
* </comp>
|
||||
*/
|
||||
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
ΔelementStart(0, 'comp');
|
||||
{ Δelement(1, 'projected'); }
|
||||
ΔelementEnd();
|
||||
}
|
||||
}, 2, 0, defs);
|
||||
|
||||
const fixture = new ComponentFixture(App);
|
||||
expect(events).toEqual(['projected', 'comp']);
|
||||
});
|
||||
|
||||
it('should call afterViewInit in content children and host before next host', () => {
|
||||
/**
|
||||
* <comp [val]="1">
|
||||
* <projected [val]="1"></projected>
|
||||
* </comp>
|
||||
* <comp [val]="2">
|
||||
* <projected [val]="2"></projected>
|
||||
* </comp>
|
||||
*/
|
||||
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
ΔelementStart(0, 'comp');
|
||||
{ Δelement(1, 'projected'); }
|
||||
ΔelementEnd();
|
||||
ΔelementStart(2, 'comp');
|
||||
{ Δelement(3, 'projected'); }
|
||||
ΔelementEnd();
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
ΔelementProperty(0, 'val', 1);
|
||||
Δselect(1);
|
||||
ΔelementProperty(1, 'val', 1);
|
||||
Δselect(2);
|
||||
ΔelementProperty(2, 'val', 2);
|
||||
Δselect(3);
|
||||
ΔelementProperty(3, 'val', 2);
|
||||
}
|
||||
}, 4, 0, defs);
|
||||
|
||||
const fixture = new ComponentFixture(App);
|
||||
expect(events).toEqual(['projected1', 'comp1', 'projected2', 'comp2']);
|
||||
});
|
||||
|
||||
it('should call afterViewInit in content children and hosts before parents', () => {
|
||||
/*
|
||||
* <comp [val]="val">
|
||||
* <projected [val]="val"></projected>
|
||||
* </comp>
|
||||
*/
|
||||
const ParentComp = createAfterViewInitComponent('parent', (rf: RenderFlags, ctx: any) => {
|
||||
if (rf & RenderFlags.Create) {
|
||||
ΔelementStart(0, 'comp');
|
||||
{ Δelement(1, 'projected'); }
|
||||
ΔelementEnd();
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
ΔelementProperty(0, 'val', Δbind(ctx.val));
|
||||
Δselect(1);
|
||||
ΔelementProperty(1, 'val', Δbind(ctx.val));
|
||||
}
|
||||
}, 2, 2, [Comp, ProjectedComp]);
|
||||
|
||||
/**
|
||||
* <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, [ParentComp]);
|
||||
|
||||
const fixture = new ComponentFixture(App);
|
||||
expect(events).toEqual(['projected1', 'comp1', 'projected2', 'comp2', 'parent1', 'parent2']);
|
||||
});
|
||||
|
||||
it('should be called in correct order with for loops', () => {
|
||||
/**
|
||||
* <comp [val]="1"></comp>
|
||||
* % for (let i = 0; i < 4; i++) {
|
||||
* <comp [val]="i"></comp>
|
||||
* % }
|
||||
* <comp [val]="4"></comp>
|
||||
*/
|
||||
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
Δelement(0, 'comp');
|
||||
Δcontainer(1);
|
||||
Δelement(2, 'comp');
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
ΔelementProperty(0, 'val', 1);
|
||||
Δselect(2);
|
||||
ΔelementProperty(2, 'val', 4);
|
||||
ΔcontainerRefreshStart(1);
|
||||
{
|
||||
for (let i = 2; i < 4; i++) {
|
||||
let rf1 = ΔembeddedViewStart(0, 1, 0);
|
||||
if (rf1 & RenderFlags.Create) {
|
||||
Δelement(0, 'comp');
|
||||
}
|
||||
if (rf1 & RenderFlags.Update) {
|
||||
ΔelementProperty(0, 'val', i);
|
||||
}
|
||||
ΔembeddedViewEnd();
|
||||
}
|
||||
}
|
||||
ΔcontainerRefreshEnd();
|
||||
}
|
||||
}, 3, 0, defs);
|
||||
|
||||
const fixture = new ComponentFixture(App);
|
||||
expect(events).toEqual(['comp2', 'comp3', 'comp1', 'comp4']);
|
||||
|
||||
});
|
||||
|
||||
it('should be called in correct order with for loops with children', () => {
|
||||
/**
|
||||
* <parent [val]="1"></parent>
|
||||
* % for(let i = 0; i < 4; i++) {
|
||||
* <parent [val]="i"></parent>
|
||||
* % }
|
||||
* <parent [val]="4"></parent>
|
||||
*/
|
||||
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
Δelement(0, 'parent');
|
||||
Δcontainer(1);
|
||||
Δelement(2, 'parent');
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
ΔelementProperty(0, 'val', 1);
|
||||
Δselect(2);
|
||||
ΔelementProperty(2, 'val', 4);
|
||||
ΔcontainerRefreshStart(1);
|
||||
{
|
||||
for (let i = 2; i < 4; i++) {
|
||||
let rf1 = ΔembeddedViewStart(0, 1, 0);
|
||||
if (rf1 & RenderFlags.Create) {
|
||||
Δelement(0, 'parent');
|
||||
}
|
||||
if (rf1 & RenderFlags.Update) {
|
||||
ΔelementProperty(0, 'val', i);
|
||||
}
|
||||
ΔembeddedViewEnd();
|
||||
}
|
||||
}
|
||||
ΔcontainerRefreshEnd();
|
||||
}
|
||||
}, 3, 0, defs);
|
||||
|
||||
const fixture = new ComponentFixture(App);
|
||||
expect(events).toEqual(
|
||||
['comp2', 'parent2', 'comp3', 'parent3', 'comp1', 'comp4', 'parent1', 'parent4']);
|
||||
|
||||
});
|
||||
|
||||
describe('ngAfterViewChecked', () => {
|
||||
|
||||
it('should call ngAfterViewChecked every update', () => {
|
||||
/** <comp></comp> */
|
||||
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
Δelement(0, 'comp');
|
||||
}
|
||||
}, 1, 0, defs);
|
||||
|
||||
const fixture = new ComponentFixture(App);
|
||||
expect(allEvents).toEqual(['comp init', 'comp check']);
|
||||
|
||||
fixture.update();
|
||||
expect(allEvents).toEqual(['comp init', 'comp check', 'comp check']);
|
||||
});
|
||||
|
||||
it('should be called on root component', () => {
|
||||
const comp = renderComponent(Comp, {hostFeatures: [LifecycleHooksFeature]});
|
||||
expect(allEvents).toEqual(['comp init', 'comp check']);
|
||||
|
||||
markDirty(comp);
|
||||
requestAnimationFrame.flush();
|
||||
expect(allEvents).toEqual(['comp init', 'comp check', 'comp check']);
|
||||
});
|
||||
|
||||
it('should call ngAfterViewChecked with bindings', () => {
|
||||
/** <comp [val]="myVal"></comp> */
|
||||
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
Δelement(0, 'comp');
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
ΔelementProperty(0, 'val', Δbind(ctx.myVal));
|
||||
}
|
||||
}, 1, 1, defs);
|
||||
|
||||
const fixture = new ComponentFixture(App);
|
||||
expect(allEvents).toEqual(['comp init', 'comp check']);
|
||||
|
||||
fixture.component.myVal = 2;
|
||||
fixture.update();
|
||||
expect(allEvents).toEqual(['comp init', 'comp check', 'comp2 check']);
|
||||
});
|
||||
|
||||
it('should be called in correct order with for loops with children', () => {
|
||||
/**
|
||||
* <parent [val]="1"></parent>
|
||||
* % for(let i = 0; i < 4; i++) {
|
||||
* <parent [val]="i"></parent>
|
||||
* % }
|
||||
* <parent [val]="4"></parent>
|
||||
*/
|
||||
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
Δelement(0, 'parent');
|
||||
Δcontainer(1);
|
||||
Δelement(2, 'parent');
|
||||
}
|
||||
if (rf & RenderFlags.Update) {
|
||||
ΔelementProperty(0, 'val', 1);
|
||||
Δselect(2);
|
||||
ΔelementProperty(2, 'val', 4);
|
||||
ΔcontainerRefreshStart(1);
|
||||
{
|
||||
for (let i = 2; i < 4; i++) {
|
||||
let rf1 = ΔembeddedViewStart(0, 1, 0);
|
||||
if (rf1 & RenderFlags.Create) {
|
||||
Δelement(0, 'parent');
|
||||
}
|
||||
if (rf1 & RenderFlags.Update) {
|
||||
ΔelementProperty(0, 'val', i);
|
||||
}
|
||||
ΔembeddedViewEnd();
|
||||
}
|
||||
}
|
||||
ΔcontainerRefreshEnd();
|
||||
}
|
||||
}, 3, 0, defs);
|
||||
|
||||
const fixture = new ComponentFixture(App);
|
||||
expect(allEvents).toEqual([
|
||||
'comp2 init', 'comp2 check', 'parent2 init', 'parent2 check', 'comp3 init', 'comp3 check',
|
||||
'parent3 init', 'parent3 check', 'comp1 init', 'comp1 check', 'comp4 init', 'comp4 check',
|
||||
'parent1 init', 'parent1 check', 'parent4 init', 'parent4 check'
|
||||
]);
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('directives', () => {
|
||||
it('should be called on directives after component', () => {
|
||||
/** <comp directive></comp> */
|
||||
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
Δelement(0, 'comp', ['dir', '']);
|
||||
}
|
||||
}, 1, 0, defs);
|
||||
|
||||
const fixture = new ComponentFixture(App);
|
||||
expect(events).toEqual(['comp', 'init', 'check']);
|
||||
});
|
||||
|
||||
it('should be called on directives on an element', () => {
|
||||
/** <div directive></div> */
|
||||
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
|
||||
if (rf & RenderFlags.Create) {
|
||||
Δelement(0, 'div', ['dir', '']);
|
||||
}
|
||||
}, 1, 0, defs);
|
||||
|
||||
const fixture = new ComponentFixture(App);
|
||||
expect(events).toEqual(['init', 'check']);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('onDestroy', () => {
|
||||
let events: string[];
|
||||
|
||||
|
|
Loading…
Reference in New Issue