diff --git a/packages/core/test/acceptance/lifecycle_spec.ts b/packages/core/test/acceptance/lifecycle_spec.ts index 264f75e59d..7c94c95435 100644 --- a/packages/core/test/acceptance/lifecycle_spec.ts +++ b/packages/core/test/acceptance/lifecycle_spec.ts @@ -810,3 +810,402 @@ describe('doCheck', () => { expect(doChecks).toEqual(['app', 'dir 1', 'dir 2']); }); }); + +describe('afterContentinit', () => { + it('should be called only in creation mode', () => { + let afterContentInitCalls = 0; + + @Component({ + selector: 'comp', + template: `

test

`, + }) + class Comp { + ngAfterContentInit() { afterContentInitCalls++; } + } + @Component({template: ``}) + class App { + } + + TestBed.configureTestingModule({ + declarations: [App, Comp], + }); + const fixture = TestBed.createComponent(App); + fixture.detectChanges(); + + // two updates + fixture.detectChanges(); + fixture.detectChanges(); + + expect(afterContentInitCalls).toBe(1); + }); + + it('should be called on root component in creation mode', () => { + let afterContentInitCalls = 0; + + @Component({template: `

test

`}) + class App { + ngAfterContentInit() { afterContentInitCalls++; } + } + + TestBed.configureTestingModule({ + declarations: [App], + }); + const fixture = TestBed.createComponent(App); + fixture.detectChanges(); + + // two updates + fixture.detectChanges(); + fixture.detectChanges(); + + expect(afterContentInitCalls).toBe(1); + }); + + it('should be called on every create ngIf', () => { + const events: string[] = []; + + @Component({ + selector: 'comp', + template: `

test

`, + }) + class Comp { + ngAfterContentInit() { events.push('comp afterContentInit'); } + } + + @Component({template: ``}) + class App { + show = true; + + ngAfterContentInit() { events.push('app afterContentInit'); } + } + + TestBed.configureTestingModule({ + declarations: [App, Comp], + imports: [CommonModule], + }); + const fixture = TestBed.createComponent(App); + fixture.detectChanges(); + + expect(events).toEqual(['app afterContentInit', 'comp afterContentInit']); + + fixture.componentInstance.show = false; + fixture.detectChanges(); + + expect(events).toEqual(['app afterContentInit', 'comp afterContentInit']); + + fixture.componentInstance.show = true; + fixture.detectChanges(); + + + expect(events).toEqual( + ['app afterContentInit', 'comp afterContentInit', 'comp afterContentInit']); + }); + + it('should be called in parents before children', () => { + const events: string[] = []; + + @Component({ + selector: 'parent', + template: ``, + }) + class Parent { + @Input() + name = ''; + + ngAfterContentInit() { events.push('parent ' + this.name); } + } + + @Component({ + selector: 'child', + template: `

test

`, + }) + class Child { + @Input() + name = ''; + + ngAfterContentInit() { events.push('child of parent ' + this.name); } + } + + @Component({ + template: ` + + + ` + }) + class App { + ngAfterContentInit() { events.push('app'); } + } + + TestBed.configureTestingModule({ + declarations: [App, Parent, Child], + }); + const fixture = TestBed.createComponent(App); + fixture.detectChanges(); + + expect(events).toEqual( + ['app', 'parent 1', 'parent 2', 'child of parent 1', 'child of parent 2']); + }); + + it('should be called in projected components before their hosts', () => { + const events: string[] = []; + + @Component({ + selector: 'projected-child', + template: `

test

`, + }) + class ProjectedChild { + @Input() + name = ''; + + ngAfterContentInit() { events.push('projected child ' + this.name); } + } + + @Component({ + selector: 'comp', + template: `
`, + }) + class Comp { + @Input() + name = ''; + + ngAfterContentInit() { events.push('comp ' + this.name); } + } + + @Component({ + selector: 'projected', + template: ``, + }) + class Projected { + @Input() + name = ''; + + ngAfterContentInit() { events.push('projected ' + this.name); } + } + + @Component({ + template: ` + + + + + + + + + ` + }) + class App { + ngAfterContentInit() { events.push('app'); } + } + + TestBed.configureTestingModule({ + declarations: [App, Comp, Projected, ProjectedChild], + }); + const fixture = TestBed.createComponent(App); + fixture.detectChanges(); + + expect(events).toEqual([ + // root + 'app', + // projections of comp 1 + 'projected 1', + 'projected 2', + // comp 1 + 'comp 1', + // projections of comp 2 + 'projected 3', + 'projected 4', + // comp 2 + 'comp 2', + // children of projections + 'projected child 1', + 'projected child 2', + 'projected child 3', + 'projected child 4', + ]); + }); + + it('should be called in correct order in a for loop', () => { + const events: string[] = []; + + @Component({ + selector: 'comp', + template: `

test

`, + }) + class Comp { + @Input() + name = ''; + + ngAfterContentInit() { events.push('comp ' + this.name); } + } + + @Component({ + template: ` + + + + ` + }) + class App { + numbers = [0, 1, 2, 3]; + + ngAfterContentInit() { events.push('app'); } + } + + TestBed.configureTestingModule({ + declarations: [App, Comp], + imports: [CommonModule], + }); + const fixture = TestBed.createComponent(App); + fixture.detectChanges(); + + expect(events).toEqual(['app', 'comp 0', 'comp 1', 'comp 2', 'comp 3', 'comp 4', 'comp 5']); + }); + + it('should be called in correct order in a for loop with children', () => { + const events: string[] = []; + + @Component({ + selector: 'parent', + template: ``, + }) + class Parent { + @Input() + name = ''; + + ngAfterContentInit() { events.push('parent ' + this.name); } + } + + @Component({ + selector: 'child', + template: `

test

`, + }) + class Child { + @Input() + name = ''; + + ngAfterContentInit() { events.push('child of parent ' + this.name); } + } + + @Component({ + template: ` + + + + ` + }) + class App { + numbers = [0, 1, 2, 3]; + ngAfterContentInit() { events.push('app'); } + } + + TestBed.configureTestingModule({ + declarations: [App, Parent, Child], + }); + const fixture = TestBed.createComponent(App); + fixture.detectChanges(); + + expect(events).toEqual([ + // root + 'app', + // 4 embedded views + 'parent 0', + 'child of parent 0', + 'parent 1', + 'child of parent 1', + 'parent 2', + 'child of parent 2', + 'parent 3', + 'child of parent 3', + // root children + 'parent 4', + 'parent 5', + // children of root children + 'child of parent 4', + 'child of parent 5', + ]); + }); + + it('should be called on directives after component', () => { + const events: string[] = []; + @Directive({ + selector: '[dir]', + }) + class Dir { + @Input('dir') + name = ''; + + ngAfterContentInit() { events.push('dir ' + this.name); } + } + + @Component({ + selector: 'comp', + template: `

test

`, + }) + class Comp { + @Input() + name = ''; + + ngAfterContentInit() { events.push('comp ' + this.name); } + } + + @Component({ + template: ` + + + ` + }) + class App { + ngAfterContentInit() { events.push('app'); } + } + + TestBed.configureTestingModule({ + declarations: [App, Comp, Dir], + }); + const fixture = TestBed.createComponent(App); + fixture.detectChanges(); + + expect(events).toEqual([ + 'app', + 'comp 1', + 'dir 1', + 'comp 2', + 'dir 2', + ]); + }); +}); + +describe('afterContentChecked', () => { + it('should be called every change detection run after afterContentInit', () => { + const events: string[] = []; + + @Component({ + selector: 'comp', + template: `

test

`, + }) + class Comp { + ngAfterContentInit() { events.push('comp afterContentInit'); } + + ngAfterContentChecked() { events.push('comp afterContentChecked'); } + } + + @Component({template: ``}) + class App { + ngAfterContentInit() { events.push('app afterContentInit'); } + + ngAfterContentChecked() { events.push('app afterContentChecked'); } + } + + TestBed.configureTestingModule({ + declarations: [App, Comp], + }); + const fixture = TestBed.createComponent(App); + fixture.detectChanges(); + + expect(events).toEqual([ + 'app afterContentInit', + 'app afterContentChecked', + 'comp afterContentInit', + 'comp afterContentChecked', + ]); + }); +}); diff --git a/packages/core/test/render3/lifecycle_spec.ts b/packages/core/test/render3/lifecycle_spec.ts index 9b20c9bdf6..7cd4f67d2b 100644 --- a/packages/core/test/render3/lifecycle_spec.ts +++ b/packages/core/test/render3/lifecycle_spec.ts @@ -116,139 +116,6 @@ describe('lifecycles', () => { }); }); -<<<<<<< HEAD - describe('doCheck', () => { - let events: string[]; - let allEvents: string[]; - - beforeEach(() => { - events = []; - allEvents = []; - }); - - let Comp = createDoCheckComponent('comp', (rf: RenderFlags, ctx: any) => {}); - let Parent = createDoCheckComponent('parent', getParentTemplate('comp'), 1, 1, [Comp]); - - function createDoCheckComponent( - name: string, template: ComponentTemplate, consts: number = 0, vars: number = 0, - directives: any[] = []) { - return class Component { - ngDoCheck() { - events.push(name); - allEvents.push('check ' + name); - } - - ngOnInit() { allEvents.push('init ' + name); } - - static ngComponentDef = ΔdefineComponent({ - type: Component, - selectors: [[name]], - factory: () => new Component(), template, - consts: consts, - vars: vars, - directives: directives, - inputs: {val: 'val'} - }); - }; - } - - class Directive { - ngDoCheck() { events.push('dir'); } - - static ngDirectiveDef = ΔdefineDirective( - {type: Directive, selectors: [['', 'dir', '']], factory: () => new Directive()}); - } - - const directives = [Comp, Parent, Directive]; - - it('should call doCheck on every refresh', () => { - /** */ - const App = createComponent('app', function(rf: RenderFlags, ctx: any) { - if (rf & RenderFlags.Create) { - Δelement(0, 'comp'); - } - }, 1, 0, directives); - - const fixture = new ComponentFixture(App); - expect(events).toEqual(['comp']); - - fixture.update(); - expect(events).toEqual(['comp', 'comp']); - }); - - it('should be called on root component', () => { - const comp = renderComponent(Comp, {hostFeatures: [LifecycleHooksFeature]}); - expect(events).toEqual(['comp']); - - markDirty(comp); - requestAnimationFrame.flush(); - expect(events).toEqual(['comp', 'comp']); - }); - - it('should call parent doCheck before child doCheck', () => { - /** - * - * parent temp: - */ - const App = createComponent('app', function(rf: RenderFlags, ctx: any) { - if (rf & RenderFlags.Create) { - Δelement(0, 'parent'); - } - }, 1, 0, directives); - - const fixture = new ComponentFixture(App); - expect(events).toEqual(['parent', 'comp']); - }); - - it('should call ngOnInit before ngDoCheck if creation mode', () => { - /** */ - const App = createComponent('app', function(rf: RenderFlags, ctx: any) { - if (rf & RenderFlags.Create) { - Δelement(0, 'comp'); - } - }, 1, 0, directives); - - const fixture = new ComponentFixture(App); - expect(allEvents).toEqual(['init comp', 'check comp']); - - fixture.update(); - expect(allEvents).toEqual(['init comp', 'check comp', 'check comp']); - }); - - it('should be called on directives after component', () => { - /** */ - 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', 'dir']); - - fixture.update(); - expect(events).toEqual(['comp', 'dir', 'comp', 'dir']); - }); - - it('should be called on directives on an element', () => { - /**
*/ - 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(['dir']); - - fixture.update(); - expect(events).toEqual(['dir', 'dir']); - }); - - }); - -======= ->>>>>>> test(ivy): doCheck lifecycle acceptance tests describe('afterContentInit', () => { let events: string[]; let allEvents: string[];