test(ivy): resolve root cause for core animation tests (#28062)

PR Close #28062
This commit is contained in:
Matias Niemelä 2019-01-10 14:16:29 -08:00 committed by Andrew Kushnir
parent 26a8c095d0
commit b0f3c20a4c
2 changed files with 205 additions and 199 deletions

View File

@ -853,56 +853,57 @@ const DEFAULT_COMPONENT_ID = '1';
})); }));
// nonAnimationRenderer => animationRenderer // nonAnimationRenderer => animationRenderer
fixmeIvy('unknown').it( fixmeIvy(
'should trigger a leave animation when the inner components host binding updates', 'FW-943 - elements are removed in the wrong renderer so far as host animation @triggers are concerned')
fakeAsync(() => { .it('should trigger a leave animation when the inner components host binding updates',
@Component({ fakeAsync(() => {
selector: 'parent-cmp', @Component({
template: ` selector: 'parent-cmp',
template: `
<child-cmp *ngIf="exp"></child-cmp> <child-cmp *ngIf="exp"></child-cmp>
` `
}) })
class ParentCmp { class ParentCmp {
public exp = true; public exp = true;
} }
@Component({ @Component({
selector: 'child-cmp', selector: 'child-cmp',
template: '...', template: '...',
animations: [trigger( animations: [trigger(
'host', 'host', [transition(
[transition( ':leave',
':leave', [style({opacity: 1}), animate(1000, style({opacity: 0}))])])] [style({opacity: 1}), animate(1000, style({opacity: 0}))])])]
}) })
class ChildCmp { class ChildCmp {
@HostBinding('@host') public hostAnimation = true; @HostBinding('@host') public hostAnimation = true;
} }
TestBed.configureTestingModule({declarations: [ParentCmp, ChildCmp]}); TestBed.configureTestingModule({declarations: [ParentCmp, ChildCmp]});
const engine = TestBed.get(ɵAnimationEngine); const engine = TestBed.get(ɵAnimationEngine);
const fixture = TestBed.createComponent(ParentCmp); const fixture = TestBed.createComponent(ParentCmp);
const cmp = fixture.componentInstance; const cmp = fixture.componentInstance;
fixture.detectChanges(); fixture.detectChanges();
engine.flush(); engine.flush();
expect(getLog().length).toEqual(0); expect(getLog().length).toEqual(0);
cmp.exp = false; cmp.exp = false;
fixture.detectChanges(); fixture.detectChanges();
expect(fixture.debugElement.nativeElement.children.length).toBe(1); expect(fixture.debugElement.nativeElement.children.length).toBe(1);
engine.flush(); engine.flush();
expect(getLog().length).toEqual(1); expect(getLog().length).toEqual(1);
const [player] = getLog(); const [player] = getLog();
expect(player.keyframes).toEqual([ expect(player.keyframes).toEqual([
{opacity: '1', offset: 0}, {opacity: '1', offset: 0},
{opacity: '0', offset: 1}, {opacity: '0', offset: 1},
]); ]);
player.finish(); player.finish();
expect(fixture.debugElement.nativeElement.children.length).toBe(0); expect(fixture.debugElement.nativeElement.children.length).toBe(0);
})); }));
// animationRenderer => nonAnimationRenderer // animationRenderer => nonAnimationRenderer
it('should trigger a leave animation when the outer components element binding updates on the host component element', it('should trigger a leave animation when the outer components element binding updates on the host component element',
@ -956,69 +957,70 @@ const DEFAULT_COMPONENT_ID = '1';
})); }));
// animationRenderer => animationRenderer // animationRenderer => animationRenderer
fixmeIvy('unknown').it( fixmeIvy(
'should trigger a leave animation when both the inner and outer components trigger on the same element', 'FW-943 - elements are removed in the wrong renderer so far as host animation @triggers are concerned')
fakeAsync(() => { .it('should trigger a leave animation when both the inner and outer components trigger on the same element',
@Component({ fakeAsync(() => {
selector: 'parent-cmp', @Component({
animations: [trigger( selector: 'parent-cmp',
'host', animations: [trigger(
[transition( 'host',
':leave', [transition(
[style({height: '100px'}), animate(1000, style({height: '0px'}))])])], ':leave',
template: ` [style({height: '100px'}), animate(1000, style({height: '0px'}))])])],
template: `
<child-cmp *ngIf="exp" @host></child-cmp> <child-cmp *ngIf="exp" @host></child-cmp>
` `
}) })
class ParentCmp { class ParentCmp {
public exp = true; public exp = true;
} }
@Component({ @Component({
selector: 'child-cmp', selector: 'child-cmp',
template: '...', template: '...',
animations: [trigger( animations: [trigger(
'host', 'host',
[transition( [transition(
':leave', ':leave',
[style({width: '100px'}), animate(1000, style({width: '0px'}))])])] [style({width: '100px'}), animate(1000, style({width: '0px'}))])])]
}) })
class ChildCmp { class ChildCmp {
@HostBinding('@host') public hostAnimation = true; @HostBinding('@host') public hostAnimation = true;
} }
TestBed.configureTestingModule({declarations: [ParentCmp, ChildCmp]}); TestBed.configureTestingModule({declarations: [ParentCmp, ChildCmp]});
const engine = TestBed.get(ɵAnimationEngine); const engine = TestBed.get(ɵAnimationEngine);
const fixture = TestBed.createComponent(ParentCmp); const fixture = TestBed.createComponent(ParentCmp);
const cmp = fixture.componentInstance; const cmp = fixture.componentInstance;
fixture.detectChanges(); fixture.detectChanges();
engine.flush(); engine.flush();
expect(getLog().length).toEqual(0); expect(getLog().length).toEqual(0);
cmp.exp = false; cmp.exp = false;
fixture.detectChanges(); fixture.detectChanges();
expect(fixture.debugElement.nativeElement.children.length).toBe(1); expect(fixture.debugElement.nativeElement.children.length).toBe(1);
engine.flush(); engine.flush();
expect(getLog().length).toEqual(2); expect(getLog().length).toEqual(2);
const [p1, p2] = getLog(); const [p1, p2] = getLog();
expect(p1.keyframes).toEqual([ expect(p1.keyframes).toEqual([
{width: '100px', offset: 0}, {width: '100px', offset: 0},
{width: '0px', offset: 1}, {width: '0px', offset: 1},
]); ]);
expect(p2.keyframes).toEqual([ expect(p2.keyframes).toEqual([
{height: '100px', offset: 0}, {height: '100px', offset: 0},
{height: '0px', offset: 1}, {height: '0px', offset: 1},
]); ]);
p1.finish(); p1.finish();
p2.finish(); p2.finish();
flushMicrotasks(); flushMicrotasks();
expect(fixture.debugElement.nativeElement.children.length).toBe(0); expect(fixture.debugElement.nativeElement.children.length).toBe(0);
})); }));
it('should not throw when the host element is removed and no animation triggers', it('should not throw when the host element is removed and no animation triggers',
fakeAsync(() => { fakeAsync(() => {
@ -2915,10 +2917,10 @@ const DEFAULT_COMPONENT_ID = '1';
expect(cmp.log).toEqual(['parent-done', 'child-done']); expect(cmp.log).toEqual(['parent-done', 'child-done']);
})); }));
fixmeIvy('unknown').it( fixmeIvy(
'should fire callbacks and collect the correct the totalTime and element details for any queried sub animations', 'FW-944 - style/class bindings lose track of consts/vars when interpolation is present')
fakeAsync( .it('should fire callbacks and collect the correct the totalTime and element details for any queried sub animations',
() => { fakeAsync(() => {
@Component({ @Component({
selector: 'my-cmp', selector: 'my-cmp',
template: ` template: `

View File

@ -295,8 +295,9 @@ import {HostListener} from '../../src/metadata/directives';
expect(p6.element.classList.contains('b3')).toBeTruthy(); expect(p6.element.classList.contains('b3')).toBeTruthy();
}); });
fixmeIvy('unknown').it( fixmeIvy(
'should be able to query all active animations using :animating in a query', () => { 'FW-944 - style/class bindings lose track of consts/vars when interpolation is present')
.it('should be able to query all active animations using :animating in a query', () => {
@Component({ @Component({
selector: 'ani-cmp', selector: 'ani-cmp',
template: ` template: `
@ -802,56 +803,58 @@ import {HostListener} from '../../src/metadata/directives';
expect(player.element.style.height).toEqual('444px'); expect(player.element.style.height).toEqual('444px');
}); });
fixmeIvy('unknown').it('should find newly inserted items in the component via :enter', () => { fixmeIvy(
@Component({ 'FW-945 - Ivy createComponent calls CD while VE waits for CD to be explicitly called')
selector: 'ani-cmp', .it('should find newly inserted items in the component via :enter', () => {
template: ` @Component({
selector: 'ani-cmp',
template: `
<div @myAnimation> <div @myAnimation>
<div *ngFor="let item of items" class="child"> <div *ngFor="let item of items" class="child">
{{ item }} {{ item }}
</div> </div>
</div> </div>
`, `,
animations: [trigger( animations: [trigger(
'myAnimation', 'myAnimation',
[ [
transition( transition(
':enter', ':enter',
[ [
query( query(
':enter', ':enter',
[ [
style({opacity: 0}), style({opacity: 0}),
animate(1000, style({opacity: .5})), animate(1000, style({opacity: .5})),
]), ]),
]), ]),
])] ])]
}) })
class Cmp { class Cmp {
public items: any[] = [0, 1, 2]; public items: any[] = [0, 1, 2];
} }
TestBed.configureTestingModule({declarations: [Cmp]}); TestBed.configureTestingModule({declarations: [Cmp]});
const engine = TestBed.get(ɵAnimationEngine); const engine = TestBed.get(ɵAnimationEngine);
const fixture = TestBed.createComponent(Cmp); const fixture = TestBed.createComponent(Cmp);
const cmp = fixture.componentInstance; const cmp = fixture.componentInstance;
fixture.detectChanges(); fixture.detectChanges();
engine.flush(); engine.flush();
const players = getLog(); const players = getLog();
expect(players.length).toEqual(3); expect(players.length).toEqual(3);
const [p1, p2, p3] = players; const [p1, p2, p3] = players;
expect(p1.element.innerText.trim()).toEqual('0'); expect(p1.element.innerText.trim()).toEqual('0');
expect(p2.element.innerText.trim()).toEqual('1'); expect(p2.element.innerText.trim()).toEqual('1');
expect(p3.element.innerText.trim()).toEqual('2'); expect(p3.element.innerText.trim()).toEqual('2');
players.forEach(p => { players.forEach(p => {
expect(p.keyframes).toEqual([{opacity: '0', offset: 0}, {opacity: '0.5', offset: 1}]); expect(p.keyframes).toEqual([{opacity: '0', offset: 0}, {opacity: '0.5', offset: 1}]);
}); });
}); });
it('should cleanup :enter and :leave artifacts from nodes when any animation sequences fail to be built', it('should cleanup :enter and :leave artifacts from nodes when any animation sequences fail to be built',
() => { () => {
@ -2239,83 +2242,84 @@ import {HostListener} from '../../src/metadata/directives';
expect(p3.element.classList.contains('parent1')).toBeTruthy(); expect(p3.element.classList.contains('parent1')).toBeTruthy();
}); });
fixmeIvy('unknown').it( fixmeIvy(
'should emulate a leave animation on the nearest sub host elements when a parent is removed', 'FW-943 - elements are removed in the wrong renderer so far as host animation @triggers are concerned')
fakeAsync(() => { .it('should emulate a leave animation on the nearest sub host elements when a parent is removed',
@Component({ fakeAsync(() => {
selector: 'ani-cmp', @Component({
template: ` selector: 'ani-cmp',
template: `
<div @parent *ngIf="exp" class="parent1" #parent> <div @parent *ngIf="exp" class="parent1" #parent>
<child-cmp #child @leave (@leave.start)="animateStart($event)"></child-cmp> <child-cmp #child @leave (@leave.start)="animateStart($event)"></child-cmp>
</div> </div>
`, `,
animations: [ animations: [
trigger( trigger(
'leave', 'leave',
[ [
transition(':leave', [animate(1000, style({color: 'gold'}))]), transition(':leave', [animate(1000, style({color: 'gold'}))]),
]), ]),
trigger( trigger(
'parent', 'parent',
[ [
transition(':leave', [query(':leave', animateChild())]), transition(':leave', [query(':leave', animateChild())]),
]), ]),
] ]
}) })
class ParentCmp { class ParentCmp {
public exp: boolean = true; public exp: boolean = true;
@ViewChild('child') public childElm: any; @ViewChild('child') public childElm: any;
public childEvent: any; public childEvent: any;
animateStart(event: any) { animateStart(event: any) {
if (event.toState == 'void') { if (event.toState == 'void') {
this.childEvent = event; this.childEvent = event;
}
}
} }
}
}
@Component({ @Component({
selector: 'child-cmp', selector: 'child-cmp',
template: '...', template: '...',
animations: [ animations: [
trigger( trigger(
'child', 'child',
[ [
transition(':leave', [animate(1000, style({color: 'gold'}))]), transition(':leave', [animate(1000, style({color: 'gold'}))]),
]), ]),
] ]
}) })
class ChildCmp { class ChildCmp {
public childEvent: any; public childEvent: any;
@HostBinding('@child') public animate = true; @HostBinding('@child') public animate = true;
@HostListener('@child.start', ['$event']) @HostListener('@child.start', ['$event'])
animateStart(event: any) { animateStart(event: any) {
if (event.toState == 'void') { if (event.toState == 'void') {
this.childEvent = event; this.childEvent = event;
}
}
} }
}
}
TestBed.configureTestingModule({declarations: [ParentCmp, ChildCmp]}); TestBed.configureTestingModule({declarations: [ParentCmp, ChildCmp]});
const fixture = TestBed.createComponent(ParentCmp); const fixture = TestBed.createComponent(ParentCmp);
const cmp = fixture.componentInstance; const cmp = fixture.componentInstance;
fixture.detectChanges(); fixture.detectChanges();
const childCmp = cmp.childElm; const childCmp = cmp.childElm;
cmp.exp = false; cmp.exp = false;
fixture.detectChanges(); fixture.detectChanges();
flushMicrotasks(); flushMicrotasks();
expect(cmp.childEvent.toState).toEqual('void'); expect(cmp.childEvent.toState).toEqual('void');
expect(cmp.childEvent.totalTime).toEqual(1000); expect(cmp.childEvent.totalTime).toEqual(1000);
expect(childCmp.childEvent.toState).toEqual('void'); expect(childCmp.childEvent.toState).toEqual('void');
expect(childCmp.childEvent.totalTime).toEqual(1000); expect(childCmp.childEvent.totalTime).toEqual(1000);
})); }));
it('should emulate a leave animation on a sub component\'s inner elements when a parent leave animation occurs with animateChild', it('should emulate a leave animation on a sub component\'s inner elements when a parent leave animation occurs with animateChild',
() => { () => {