fix(animations): properly handle cancelled animation style application
This commit is contained in:

committed by
Jason Aden

parent
858dea98e5
commit
105e920b69
@ -782,7 +782,7 @@ export function main() {
|
||||
expect(players.length).toEqual(3);
|
||||
const [p1, p2, p3] = players;
|
||||
expect(p1.previousStyles).toEqual({opacity: AUTO_STYLE});
|
||||
expect(p2.previousStyles).toEqual({});
|
||||
expect(p2.previousStyles).toEqual({opacity: AUTO_STYLE});
|
||||
expect(p3.previousStyles).toEqual({});
|
||||
});
|
||||
|
||||
|
@ -1000,8 +1000,9 @@ export function main() {
|
||||
}
|
||||
});
|
||||
|
||||
it('should properly cancel items that were queried into a former animation', () => {
|
||||
@Component({
|
||||
it('should properly cancel items that were queried into a former animation and pass in the associated styles into the follow-up players per element',
|
||||
() => {
|
||||
@Component({
|
||||
selector: 'ani-cmp',
|
||||
template: `
|
||||
<div [@myAnimation]="exp" class="parent">
|
||||
@ -1024,45 +1025,45 @@ export function main() {
|
||||
])]
|
||||
})
|
||||
class Cmp {
|
||||
public exp: any;
|
||||
public items: any[];
|
||||
}
|
||||
public exp: any;
|
||||
public items: any[];
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({declarations: [Cmp]});
|
||||
TestBed.configureTestingModule({declarations: [Cmp]});
|
||||
|
||||
const engine = TestBed.get(ɵAnimationEngine);
|
||||
const fixture = TestBed.createComponent(Cmp);
|
||||
const cmp = fixture.componentInstance;
|
||||
const engine = TestBed.get(ɵAnimationEngine);
|
||||
const fixture = TestBed.createComponent(Cmp);
|
||||
const cmp = fixture.componentInstance;
|
||||
|
||||
cmp.exp = 'on';
|
||||
cmp.items = [0, 1, 2, 3, 4];
|
||||
fixture.detectChanges();
|
||||
engine.flush();
|
||||
cmp.exp = 'on';
|
||||
cmp.items = [0, 1, 2, 3, 4];
|
||||
fixture.detectChanges();
|
||||
engine.flush();
|
||||
|
||||
const previousPlayers = getLog();
|
||||
expect(previousPlayers.length).toEqual(10);
|
||||
resetLog();
|
||||
const previousPlayers = getLog();
|
||||
expect(previousPlayers.length).toEqual(10);
|
||||
resetLog();
|
||||
|
||||
cmp.exp = 'off';
|
||||
cmp.items = [0, 1, 2];
|
||||
fixture.detectChanges();
|
||||
engine.flush();
|
||||
cmp.exp = 'off';
|
||||
cmp.items = [0, 1, 2];
|
||||
fixture.detectChanges();
|
||||
engine.flush();
|
||||
|
||||
const players = getLog();
|
||||
expect(players.length).toEqual(4);
|
||||
const players = getLog();
|
||||
expect(players.length).toEqual(4);
|
||||
|
||||
const [p1, p2, p3, p4] = players;
|
||||
const [p1p1, p1p2] = p1.previousPlayers;
|
||||
const [p2p1, p2p2] = p2.previousPlayers;
|
||||
const [p1, p2, p3, p4] = players;
|
||||
|
||||
expect(p1p1).toBe(previousPlayers[3]);
|
||||
expect(p1p2).toBe(previousPlayers[8]);
|
||||
expect(p2p1).toBe(previousPlayers[4]);
|
||||
expect(p2p2).toBe(previousPlayers[9]);
|
||||
// p1 && p2 are the starting players for item3 and item4
|
||||
expect(p1.previousStyles)
|
||||
.toEqual({opacity: AUTO_STYLE, width: AUTO_STYLE, height: AUTO_STYLE});
|
||||
expect(p2.previousStyles)
|
||||
.toEqual({opacity: AUTO_STYLE, width: AUTO_STYLE, height: AUTO_STYLE});
|
||||
|
||||
expect(p3.previousPlayers).toEqual([]);
|
||||
expect(p4.previousPlayers).toEqual([]);
|
||||
});
|
||||
// p3 && p4 are the following players for item3 and item4
|
||||
expect(p3.previousStyles).toEqual({});
|
||||
expect(p4.previousStyles).toEqual({});
|
||||
});
|
||||
|
||||
it('should not remove a parent container if its contents are queried into by an ancestor element',
|
||||
() => {
|
||||
|
@ -5,10 +5,10 @@
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
import {animate, state, style, transition, trigger} from '@angular/animations';
|
||||
import {AnimationDriver, ɵAnimationEngine} from '@angular/animations/browser';
|
||||
import {ɵWebAnimationsDriver, ɵWebAnimationsPlayer, ɵsupportsWebAnimations} from '@angular/animations/browser'
|
||||
import {Component, ViewChild} from '@angular/core';
|
||||
import {animate, query, state, style, transition, trigger} from '@angular/animations';
|
||||
import {AnimationDriver, ɵAnimationEngine, ɵWebAnimationsDriver, ɵWebAnimationsPlayer, ɵsupportsWebAnimations} from '@angular/animations/browser';
|
||||
import {AnimationGroupPlayer} from '@angular/animations/src/players/animation_group_player';
|
||||
import {Component} from '@angular/core';
|
||||
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
|
||||
|
||||
import {TestBed} from '../../testing';
|
||||
@ -172,15 +172,125 @@ export function main() {
|
||||
{height: '100px', offset: 0}, {height: '80px', offset: 1}
|
||||
]);
|
||||
});
|
||||
|
||||
it('should compute intermediate styles properly when an animation is cancelled', () => {
|
||||
@Component({
|
||||
selector: 'ani-cmp',
|
||||
template: `
|
||||
<div [@myAnimation]="exp">...</div>
|
||||
`,
|
||||
animations: [
|
||||
trigger(
|
||||
'myAnimation',
|
||||
[
|
||||
transition(
|
||||
'* => a',
|
||||
[
|
||||
style({width: 0, height: 0}),
|
||||
animate('1s', style({width: '300px', height: '600px'})),
|
||||
]),
|
||||
transition('* => b', [animate('1s', style({opacity: 0}))]),
|
||||
]),
|
||||
]
|
||||
})
|
||||
class Cmp {
|
||||
public exp: string;
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({declarations: [Cmp]});
|
||||
|
||||
const engine = TestBed.get(ɵAnimationEngine);
|
||||
const fixture = TestBed.createComponent(Cmp);
|
||||
const cmp = fixture.componentInstance;
|
||||
|
||||
cmp.exp = 'a';
|
||||
fixture.detectChanges();
|
||||
|
||||
let player = engine.players[0] !;
|
||||
let webPlayer = player.getRealPlayer() as ɵWebAnimationsPlayer;
|
||||
webPlayer.setPosition(0.5);
|
||||
|
||||
cmp.exp = 'b';
|
||||
fixture.detectChanges();
|
||||
|
||||
player = engine.players[0] !;
|
||||
webPlayer = player.getRealPlayer() as ɵWebAnimationsPlayer;
|
||||
expect(approximate(parseFloat(webPlayer.previousStyles['width'] as string), 150))
|
||||
.toBeLessThan(0.05);
|
||||
expect(approximate(parseFloat(webPlayer.previousStyles['height'] as string), 300))
|
||||
.toBeLessThan(0.05);
|
||||
});
|
||||
|
||||
it('should compute intermediate styles properly for multiple queried elements when an animation is cancelled',
|
||||
() => {
|
||||
@Component({
|
||||
selector: 'ani-cmp',
|
||||
template: `
|
||||
<div [@myAnimation]="exp">
|
||||
<div *ngFor="let item of items" class="target"></div>
|
||||
</div>
|
||||
`,
|
||||
animations: [
|
||||
trigger(
|
||||
'myAnimation',
|
||||
[
|
||||
transition(
|
||||
'* => full', [query(
|
||||
'.target',
|
||||
[
|
||||
style({width: 0, height: 0}),
|
||||
animate('1s', style({width: '500px', height: '1000px'})),
|
||||
])]),
|
||||
transition(
|
||||
'* => empty', [query('.target', [animate('1s', style({opacity: 0}))])]),
|
||||
]),
|
||||
]
|
||||
})
|
||||
class Cmp {
|
||||
public exp: string;
|
||||
public items: any[] = [];
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({declarations: [Cmp]});
|
||||
|
||||
const engine = TestBed.get(ɵAnimationEngine);
|
||||
const fixture = TestBed.createComponent(Cmp);
|
||||
const cmp = fixture.componentInstance;
|
||||
|
||||
cmp.exp = 'full';
|
||||
cmp.items = [0, 1, 2, 3, 4];
|
||||
fixture.detectChanges();
|
||||
|
||||
let player = engine.players[0] !;
|
||||
let groupPlayer = player.getRealPlayer() as AnimationGroupPlayer;
|
||||
let players = groupPlayer.players;
|
||||
expect(players.length).toEqual(5);
|
||||
|
||||
for (let i = 0; i < players.length; i++) {
|
||||
const p = players[i] as ɵWebAnimationsPlayer;
|
||||
p.setPosition(0.5);
|
||||
}
|
||||
|
||||
cmp.exp = 'empty';
|
||||
cmp.items = [];
|
||||
fixture.detectChanges();
|
||||
|
||||
player = engine.players[0];
|
||||
groupPlayer = player.getRealPlayer() as AnimationGroupPlayer;
|
||||
players = groupPlayer.players;
|
||||
|
||||
expect(players.length).toEqual(5);
|
||||
for (let i = 0; i < players.length; i++) {
|
||||
const p = players[i] as ɵWebAnimationsPlayer;
|
||||
expect(approximate(parseFloat(p.previousStyles['width'] as string), 250))
|
||||
.toBeLessThan(0.05);
|
||||
expect(approximate(parseFloat(p.previousStyles['height'] as string), 500))
|
||||
.toBeLessThan(0.05);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function assertStyleBetween(
|
||||
element: any, prop: string, start: string | number, end: string | number) {
|
||||
const style = (window.getComputedStyle(element) as any)[prop] as string;
|
||||
if (typeof start == 'number' && typeof end == 'number') {
|
||||
const value = parseFloat(style);
|
||||
expect(value).toBeGreaterThan(start);
|
||||
expect(value).toBeLessThan(end);
|
||||
}
|
||||
}
|
||||
function approximate(value: number, target: number) {
|
||||
return Math.abs(target - value) / value;
|
||||
}
|
Reference in New Issue
Block a user