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', () => {
|
describe('onDestroy', () => {
|
||||||
let events: string[];
|
let events: string[];
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue