build: reformat repo to new clang@1.4.0 (#36628)

PR Close #36628
This commit is contained in:
Joey Perrott
2020-04-13 17:43:52 -07:00
committed by atscott
parent 4b3f9ac739
commit 26f49151e7
1163 changed files with 31727 additions and 24036 deletions

File diff suppressed because it is too large Load Diff

View File

@ -10,376 +10,377 @@ import {AnimationDriver, ɵAnimationEngine} from '@angular/animations/browser';
import {TransitionAnimationPlayer} from '@angular/animations/browser/src/render/transition_animation_engine';
import {MockAnimationDriver, MockAnimationPlayer} from '@angular/animations/browser/testing';
import {Component, HostBinding} from '@angular/core';
import {TestBed, fakeAsync, flushMicrotasks, tick} from '@angular/core/testing';
import {fakeAsync, flushMicrotasks, TestBed, tick} from '@angular/core/testing';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
import {ActivatedRoute, Router, RouterOutlet} from '@angular/router';
import {RouterTestingModule} from '@angular/router/testing';
(function() {
// these tests are only mean't to be run within the DOM (for now)
if (isNode) return;
// these tests are only mean't to be run within the DOM (for now)
if (isNode) return;
describe('Animation Router Tests', function() {
function getLog(): MockAnimationPlayer[] {
return MockAnimationDriver.log as MockAnimationPlayer[];
}
describe('Animation Router Tests', function() {
function getLog(): MockAnimationPlayer[] {
return MockAnimationDriver.log as MockAnimationPlayer[];
}
function resetLog() { MockAnimationDriver.log = []; }
function resetLog() {
MockAnimationDriver.log = [];
}
beforeEach(() => {
resetLog();
TestBed.configureTestingModule({
imports: [RouterTestingModule, BrowserAnimationsModule],
providers: [{provide: AnimationDriver, useClass: MockAnimationDriver}]
});
beforeEach(() => {
resetLog();
TestBed.configureTestingModule({
imports: [RouterTestingModule, BrowserAnimationsModule],
providers: [{provide: AnimationDriver, useClass: MockAnimationDriver}]
});
});
it('should query the old and new routes via :leave and :enter', fakeAsync(() => {
@Component({
animations: [
trigger(
'routerAnimations',
[
transition(
'page1 => page2',
[
query(':leave', animateChild()),
query(':enter', animateChild()),
]),
]),
],
template: `
it('should query the old and new routes via :leave and :enter', fakeAsync(() => {
@Component({
animations: [
trigger(
'routerAnimations',
[
transition(
'page1 => page2',
[
query(':leave', animateChild()),
query(':enter', animateChild()),
]),
]),
],
template: `
<div [@routerAnimations]="prepareRouteAnimation(r)">
<router-outlet #r="outlet"></router-outlet>
</div>
`
})
class ContainerCmp {
constructor(public router: Router) {}
})
class ContainerCmp {
constructor(public router: Router) {}
prepareRouteAnimation(r: RouterOutlet) {
const animation = r.activatedRouteData['animation'];
const value = animation ? animation['value'] : null;
return value;
}
prepareRouteAnimation(r: RouterOutlet) {
const animation = r.activatedRouteData['animation'];
const value = animation ? animation['value'] : null;
return value;
}
}
@Component({
selector: 'page1',
template: `page1`,
animations: [
trigger(
'page1Animation',
[
transition(
':leave',
[
style({width: '200px'}),
animate(1000, style({width: '0px'})),
]),
]),
]
})
class Page1Cmp {
@HostBinding('@page1Animation') public doAnimate = true;
}
@Component({
selector: 'page1',
template: `page1`,
animations: [
trigger(
'page1Animation',
[
transition(
':leave',
[
style({width: '200px'}),
animate(1000, style({width: '0px'})),
]),
]),
]
})
class Page1Cmp {
@HostBinding('@page1Animation') public doAnimate = true;
}
@Component({
selector: 'page2',
template: `page2`,
animations: [
trigger(
'page2Animation',
[
transition(
':enter',
[
style({opacity: 0}),
animate(1000, style({opacity: 1})),
]),
]),
]
})
class Page2Cmp {
@HostBinding('@page2Animation') public doAnimate = true;
}
@Component({
selector: 'page2',
template: `page2`,
animations: [
trigger(
'page2Animation',
[
transition(
':enter',
[
style({opacity: 0}),
animate(1000, style({opacity: 1})),
]),
]),
]
})
class Page2Cmp {
@HostBinding('@page2Animation') public doAnimate = true;
}
TestBed.configureTestingModule({
declarations: [Page1Cmp, Page2Cmp, ContainerCmp],
imports: [RouterTestingModule.withRoutes([
{path: 'page1', component: Page1Cmp, data: makeAnimationData('page1')},
{path: 'page2', component: Page2Cmp, data: makeAnimationData('page2')}
])]
});
TestBed.configureTestingModule({
declarations: [Page1Cmp, Page2Cmp, ContainerCmp],
imports: [RouterTestingModule.withRoutes([
{path: 'page1', component: Page1Cmp, data: makeAnimationData('page1')},
{path: 'page2', component: Page2Cmp, data: makeAnimationData('page2')}
])]
});
const engine = TestBed.inject(ɵAnimationEngine);
const fixture = TestBed.createComponent(ContainerCmp);
const cmp = fixture.componentInstance;
cmp.router.initialNavigation();
tick();
fixture.detectChanges();
engine.flush();
const engine = TestBed.inject(ɵAnimationEngine);
const fixture = TestBed.createComponent(ContainerCmp);
const cmp = fixture.componentInstance;
cmp.router.initialNavigation();
tick();
fixture.detectChanges();
engine.flush();
cmp.router.navigateByUrl('/page1');
tick();
fixture.detectChanges();
engine.flush();
cmp.router.navigateByUrl('/page1');
tick();
fixture.detectChanges();
engine.flush();
cmp.router.navigateByUrl('/page2');
tick();
fixture.detectChanges();
engine.flush();
cmp.router.navigateByUrl('/page2');
tick();
fixture.detectChanges();
engine.flush();
const player = engine.players[0] !;
const groupPlayer =
(player as TransitionAnimationPlayer).getRealPlayer() as AnimationGroupPlayer;
const players = groupPlayer.players as MockAnimationPlayer[];
const player = engine.players[0]!;
const groupPlayer =
(player as TransitionAnimationPlayer).getRealPlayer() as AnimationGroupPlayer;
const players = groupPlayer.players as MockAnimationPlayer[];
expect(players.length).toEqual(2);
const [p1, p2] = players;
expect(players.length).toEqual(2);
const [p1, p2] = players;
expect(p1.duration).toEqual(1000);
expect(p1.keyframes).toEqual([
{offset: 0, width: '200px'},
{offset: 1, width: '0px'},
]);
expect(p1.duration).toEqual(1000);
expect(p1.keyframes).toEqual([
{offset: 0, width: '200px'},
{offset: 1, width: '0px'},
]);
expect(p2.duration).toEqual(2000);
expect(p2.keyframes).toEqual([
{offset: 0, opacity: '0'},
{offset: .5, opacity: '0'},
{offset: 1, opacity: '1'},
]);
}));
expect(p2.duration).toEqual(2000);
expect(p2.keyframes).toEqual([
{offset: 0, opacity: '0'},
{offset: .5, opacity: '0'},
{offset: 1, opacity: '1'},
]);
}));
it('should allow inner enter animations to be emulated within a routed item', fakeAsync(() => {
@Component({
animations: [
trigger(
'routerAnimations',
[
transition(
'page1 => page2',
[
query(':enter', animateChild()),
]),
]),
],
template: `
it('should allow inner enter animations to be emulated within a routed item', fakeAsync(() => {
@Component({
animations: [
trigger(
'routerAnimations',
[
transition(
'page1 => page2',
[
query(':enter', animateChild()),
]),
]),
],
template: `
<div [@routerAnimations]="prepareRouteAnimation(r)">
<router-outlet #r="outlet"></router-outlet>
</div>
`
})
class ContainerCmp {
constructor(public router: Router) {}
})
class ContainerCmp {
constructor(public router: Router) {}
prepareRouteAnimation(r: RouterOutlet) {
const animation = r.activatedRouteData['animation'];
const value = animation ? animation['value'] : null;
return value;
}
prepareRouteAnimation(r: RouterOutlet) {
const animation = r.activatedRouteData['animation'];
const value = animation ? animation['value'] : null;
return value;
}
}
@Component({selector: 'page1', template: `page1`, animations: []})
class Page1Cmp {
}
@Component({selector: 'page1', template: `page1`, animations: []})
class Page1Cmp {
}
@Component({
selector: 'page2',
template: `
@Component({
selector: 'page2',
template: `
<h1>Page 2</h1>
<div *ngIf="exp" class="if-one" @ifAnimation></div>
<div *ngIf="exp" class="if-two" @ifAnimation></div>
`,
animations: [
trigger(
'page2Animation',
[
transition(
':enter',
[query('.if-one', animateChild()), query('.if-two', animateChild())]),
]),
trigger(
'ifAnimation',
[transition(
':enter', [style({opacity: 0}), animate(1000, style({opacity: 1}))])])
]
})
class Page2Cmp {
@HostBinding('@page2Animation') public doAnimate = true;
animations: [
trigger(
'page2Animation',
[
transition(
':enter',
[query('.if-one', animateChild()), query('.if-two', animateChild())]),
]),
trigger(
'ifAnimation',
[transition(':enter', [style({opacity: 0}), animate(1000, style({opacity: 1}))])])
]
})
class Page2Cmp {
@HostBinding('@page2Animation') public doAnimate = true;
public exp = true;
}
public exp = true;
}
TestBed.configureTestingModule({
declarations: [Page1Cmp, Page2Cmp, ContainerCmp],
imports: [RouterTestingModule.withRoutes([
{path: 'page1', component: Page1Cmp, data: makeAnimationData('page1')},
{path: 'page2', component: Page2Cmp, data: makeAnimationData('page2')}
])]
});
TestBed.configureTestingModule({
declarations: [Page1Cmp, Page2Cmp, ContainerCmp],
imports: [RouterTestingModule.withRoutes([
{path: 'page1', component: Page1Cmp, data: makeAnimationData('page1')},
{path: 'page2', component: Page2Cmp, data: makeAnimationData('page2')}
])]
});
const engine = TestBed.inject(ɵAnimationEngine);
const fixture = TestBed.createComponent(ContainerCmp);
const cmp = fixture.componentInstance;
cmp.router.initialNavigation();
tick();
fixture.detectChanges();
engine.flush();
const engine = TestBed.inject(ɵAnimationEngine);
const fixture = TestBed.createComponent(ContainerCmp);
const cmp = fixture.componentInstance;
cmp.router.initialNavigation();
tick();
fixture.detectChanges();
engine.flush();
cmp.router.navigateByUrl('/page1');
tick();
fixture.detectChanges();
engine.flush();
cmp.router.navigateByUrl('/page1');
tick();
fixture.detectChanges();
engine.flush();
cmp.router.navigateByUrl('/page2');
tick();
fixture.detectChanges();
engine.flush();
cmp.router.navigateByUrl('/page2');
tick();
fixture.detectChanges();
engine.flush();
const player = engine.players[0] !;
const groupPlayer =
(player as TransitionAnimationPlayer).getRealPlayer() as AnimationGroupPlayer;
const players = groupPlayer.players as MockAnimationPlayer[];
const player = engine.players[0]!;
const groupPlayer =
(player as TransitionAnimationPlayer).getRealPlayer() as AnimationGroupPlayer;
const players = groupPlayer.players as MockAnimationPlayer[];
expect(players.length).toEqual(2);
const [p1, p2] = players;
expect(players.length).toEqual(2);
const [p1, p2] = players;
expect(p1.keyframes).toEqual([
{offset: 0, opacity: '0'},
{offset: 1, opacity: '1'},
]);
expect(p1.keyframes).toEqual([
{offset: 0, opacity: '0'},
{offset: 1, opacity: '1'},
]);
expect(p2.keyframes).toEqual([
{offset: 0, opacity: '0'},
{offset: .5, opacity: '0'},
{offset: 1, opacity: '1'},
]);
}));
expect(p2.keyframes).toEqual([
{offset: 0, opacity: '0'},
{offset: .5, opacity: '0'},
{offset: 1, opacity: '1'},
]);
}));
it('should allow inner leave animations to be emulated within a routed item', fakeAsync(() => {
@Component({
animations: [
trigger(
'routerAnimations',
[
transition(
'page1 => page2',
[
query(':leave', animateChild()),
]),
]),
],
template: `
it('should allow inner leave animations to be emulated within a routed item', fakeAsync(() => {
@Component({
animations: [
trigger(
'routerAnimations',
[
transition(
'page1 => page2',
[
query(':leave', animateChild()),
]),
]),
],
template: `
<div [@routerAnimations]="prepareRouteAnimation(r)">
<router-outlet #r="outlet"></router-outlet>
</div>
`
})
class ContainerCmp {
constructor(public router: Router) {}
})
class ContainerCmp {
constructor(public router: Router) {}
prepareRouteAnimation(r: RouterOutlet) {
const animation = r.activatedRouteData['animation'];
const value = animation ? animation['value'] : null;
return value;
}
prepareRouteAnimation(r: RouterOutlet) {
const animation = r.activatedRouteData['animation'];
const value = animation ? animation['value'] : null;
return value;
}
}
@Component({
selector: 'page1',
template: `
@Component({
selector: 'page1',
template: `
<h1>Page 1</h1>
<div *ngIf="exp" class="if-one" @ifAnimation></div>
<div *ngIf="exp" class="if-two" @ifAnimation></div>
`,
animations: [
trigger(
'page1Animation',
[
transition(
':leave',
[query('.if-one', animateChild()), query('.if-two', animateChild())]),
]),
trigger(
'ifAnimation',
[transition(':leave', [style({opacity: 1}), animate(1000, style({opacity: 0}))])]),
]
})
class Page1Cmp {
@HostBinding('@page1Animation') public doAnimate = true;
animations: [
trigger(
'page1Animation',
[
transition(
':leave',
[query('.if-one', animateChild()), query('.if-two', animateChild())]),
]),
trigger(
'ifAnimation',
[transition(':leave', [style({opacity: 1}), animate(1000, style({opacity: 0}))])]),
]
})
class Page1Cmp {
@HostBinding('@page1Animation') public doAnimate = true;
public exp = true;
}
public exp = true;
}
@Component({selector: 'page2', template: `page2`, animations: []})
class Page2Cmp {
}
@Component({selector: 'page2', template: `page2`, animations: []})
class Page2Cmp {
}
TestBed.configureTestingModule({
declarations: [Page1Cmp, Page2Cmp, ContainerCmp],
imports: [RouterTestingModule.withRoutes([
{path: 'page1', component: Page1Cmp, data: makeAnimationData('page1')},
{path: 'page2', component: Page2Cmp, data: makeAnimationData('page2')}
])]
});
TestBed.configureTestingModule({
declarations: [Page1Cmp, Page2Cmp, ContainerCmp],
imports: [RouterTestingModule.withRoutes([
{path: 'page1', component: Page1Cmp, data: makeAnimationData('page1')},
{path: 'page2', component: Page2Cmp, data: makeAnimationData('page2')}
])]
});
const engine = TestBed.inject(ɵAnimationEngine);
const fixture = TestBed.createComponent(ContainerCmp);
const cmp = fixture.componentInstance;
cmp.router.initialNavigation();
tick();
fixture.detectChanges();
engine.flush();
const engine = TestBed.inject(ɵAnimationEngine);
const fixture = TestBed.createComponent(ContainerCmp);
const cmp = fixture.componentInstance;
cmp.router.initialNavigation();
tick();
fixture.detectChanges();
engine.flush();
cmp.router.navigateByUrl('/page1');
tick();
fixture.detectChanges();
engine.flush();
cmp.router.navigateByUrl('/page1');
tick();
fixture.detectChanges();
engine.flush();
cmp.router.navigateByUrl('/page2');
tick();
fixture.detectChanges();
engine.flush();
cmp.router.navigateByUrl('/page2');
tick();
fixture.detectChanges();
engine.flush();
const player = engine.players[0] !;
const groupPlayer =
(player as TransitionAnimationPlayer).getRealPlayer() as AnimationGroupPlayer;
const players = groupPlayer.players as MockAnimationPlayer[];
const player = engine.players[0]!;
const groupPlayer =
(player as TransitionAnimationPlayer).getRealPlayer() as AnimationGroupPlayer;
const players = groupPlayer.players as MockAnimationPlayer[];
expect(players.length).toEqual(2);
const [p1, p2] = players;
expect(players.length).toEqual(2);
const [p1, p2] = players;
expect(p1.keyframes).toEqual([
{offset: 0, opacity: '1'},
{offset: 1, opacity: '0'},
]);
expect(p1.keyframes).toEqual([
{offset: 0, opacity: '1'},
{offset: 1, opacity: '0'},
]);
expect(p2.keyframes).toEqual([
{offset: 0, opacity: '1'},
{offset: .5, opacity: '1'},
{offset: 1, opacity: '0'},
]);
}));
expect(p2.keyframes).toEqual([
{offset: 0, opacity: '1'},
{offset: .5, opacity: '1'},
{offset: 1, opacity: '0'},
]);
}));
it('should properly collect :enter / :leave router nodes even when another non-router *template component is within the trigger boundaries',
fakeAsync(() => {
@Component({
selector: 'ani-cmp',
animations: [
trigger(
'pageAnimation',
[
transition(
'page1 => page2',
[
query('.router-container :leave', animate('1s', style({opacity: 0}))),
query('.router-container :enter', animate('1s', style({opacity: 1}))),
]),
]),
],
template: `
it('should properly collect :enter / :leave router nodes even when another non-router *template component is within the trigger boundaries',
fakeAsync(() => {
@Component({
selector: 'ani-cmp',
animations: [
trigger(
'pageAnimation',
[
transition(
'page1 => page2',
[
query('.router-container :leave', animate('1s', style({opacity: 0}))),
query('.router-container :enter', animate('1s', style({opacity: 1}))),
]),
]),
],
template: `
<div [@pageAnimation]="prepRoute(outlet)">
<header>
<div class="inner">
@ -392,138 +393,144 @@ import {RouterTestingModule} from '@angular/router/testing';
</section>
</div>
`
})
class ContainerCmp {
loading = false;
})
class ContainerCmp {
loading = false;
constructor(public router: Router) {}
constructor(public router: Router) {}
prepRoute(outlet: any) { return outlet.activatedRouteData['animation']; }
prepRoute(outlet: any) {
return outlet.activatedRouteData['animation'];
}
}
@Component({selector: 'page1', template: `page1`})
class Page1Cmp {
}
@Component({selector: 'page2', template: `page2`})
class Page2Cmp {
}
TestBed.configureTestingModule({
declarations: [Page1Cmp, Page2Cmp, ContainerCmp],
imports: [RouterTestingModule.withRoutes([
{path: 'page1', component: Page1Cmp, data: makeAnimationData('page1')},
{path: 'page2', component: Page2Cmp, data: makeAnimationData('page2')}
])]
});
const engine = TestBed.inject(ɵAnimationEngine);
const fixture = TestBed.createComponent(ContainerCmp);
const cmp = fixture.componentInstance;
cmp.router.initialNavigation();
tick();
fixture.detectChanges();
engine.flush();
cmp.router.navigateByUrl('/page1');
tick();
cmp.loading = true;
fixture.detectChanges();
engine.flush();
cmp.router.navigateByUrl('/page2');
tick();
cmp.loading = false;
fixture.detectChanges();
engine.flush();
const players = engine.players;
expect(players.length).toEqual(1);
const [p1] = players;
const innerPlayers =
((p1 as TransitionAnimationPlayer).getRealPlayer() as AnimationGroupPlayer).players;
expect(innerPlayers.length).toEqual(2);
const [ip1, ip2] = innerPlayers as any;
expect(ip1.element.innerText).toEqual('page1');
expect(ip2.element.innerText).toEqual('page2');
}));
it('should allow a recursive set of :leave animations to occur for nested routes',
fakeAsync(() => {
@Component({selector: 'ani-cmp', template: '<router-outlet name="recur"></router-outlet>'})
class ContainerCmp {
constructor(private _router: Router) {}
log: string[] = [];
enter() {
this._router.navigateByUrl('/(recur:recur/nested)');
}
@Component({selector: 'page1', template: `page1`})
class Page1Cmp {
leave() {
this._router.navigateByUrl('/');
}
}
@Component({selector: 'page2', template: `page2`})
class Page2Cmp {
@Component({
selector: 'recur-page',
template: 'Depth: {{ depth }} \n <router-outlet></router-outlet>',
animations: [
trigger(
'pageAnimations',
[
transition(':leave', [group([
sequence([style({opacity: 1}), animate('1s', style({opacity: 0}))]),
query('@*', animateChild(), {optional: true})
])]),
]),
]
})
class RecurPageCmp {
@HostBinding('@pageAnimations') public animatePage = true;
@HostBinding('attr.data-depth') public depth = 0;
constructor(private container: ContainerCmp, private route: ActivatedRoute) {
this.route.data.subscribe(data => {
this.container.log.push(`DEPTH ${data.depth}`);
this.depth = data.depth;
});
}
}
TestBed.configureTestingModule({
declarations: [Page1Cmp, Page2Cmp, ContainerCmp],
imports: [RouterTestingModule.withRoutes([
{path: 'page1', component: Page1Cmp, data: makeAnimationData('page1')},
{path: 'page2', component: Page2Cmp, data: makeAnimationData('page2')}
])]
});
TestBed.configureTestingModule({
declarations: [ContainerCmp, RecurPageCmp],
imports: [RouterTestingModule.withRoutes([{
path: 'recur',
component: RecurPageCmp,
outlet: 'recur',
data: {depth: 0},
children: [{path: 'nested', component: RecurPageCmp, data: {depth: 1}}]
}])]
});
const engine = TestBed.inject(ɵAnimationEngine);
const fixture = TestBed.createComponent(ContainerCmp);
const cmp = fixture.componentInstance;
cmp.router.initialNavigation();
tick();
fixture.detectChanges();
engine.flush();
const fixture = TestBed.createComponent(ContainerCmp);
const cmp = fixture.componentInstance;
cmp.enter();
tick();
fixture.detectChanges();
flushMicrotasks();
cmp.router.navigateByUrl('/page1');
tick();
cmp.loading = true;
fixture.detectChanges();
engine.flush();
expect(cmp.log).toEqual([
'DEPTH 0',
'DEPTH 1',
]);
cmp.router.navigateByUrl('/page2');
tick();
cmp.loading = false;
fixture.detectChanges();
engine.flush();
cmp.leave();
tick();
fixture.detectChanges();
const players = engine.players;
expect(players.length).toEqual(1);
const [p1] = players;
const players = getLog();
expect(players.length).toEqual(2);
const innerPlayers =
((p1 as TransitionAnimationPlayer).getRealPlayer() as AnimationGroupPlayer).players;
expect(innerPlayers.length).toEqual(2);
const [ip1, ip2] = innerPlayers as any;
expect(ip1.element.innerText).toEqual('page1');
expect(ip2.element.innerText).toEqual('page2');
}));
it('should allow a recursive set of :leave animations to occur for nested routes',
fakeAsync(() => {
@Component({selector: 'ani-cmp', template: '<router-outlet name="recur"></router-outlet>'})
class ContainerCmp {
constructor(private _router: Router) {}
log: string[] = [];
enter() { this._router.navigateByUrl('/(recur:recur/nested)'); }
leave() { this._router.navigateByUrl('/'); }
}
@Component({
selector: 'recur-page',
template: 'Depth: {{ depth }} \n <router-outlet></router-outlet>',
animations: [
trigger(
'pageAnimations',
[
transition(':leave', [group([
sequence([style({opacity: 1}), animate('1s', style({opacity: 0}))]),
query('@*', animateChild(), {optional: true})
])]),
]),
]
})
class RecurPageCmp {
@HostBinding('@pageAnimations') public animatePage = true;
@HostBinding('attr.data-depth') public depth = 0;
constructor(private container: ContainerCmp, private route: ActivatedRoute) {
this.route.data.subscribe(data => {
this.container.log.push(`DEPTH ${data.depth}`);
this.depth = data.depth;
});
}
}
TestBed.configureTestingModule({
declarations: [ContainerCmp, RecurPageCmp],
imports: [RouterTestingModule.withRoutes([{
path: 'recur',
component: RecurPageCmp,
outlet: 'recur',
data: {depth: 0},
children: [{path: 'nested', component: RecurPageCmp, data: {depth: 1}}]
}])]
});
const fixture = TestBed.createComponent(ContainerCmp);
const cmp = fixture.componentInstance;
cmp.enter();
tick();
fixture.detectChanges();
flushMicrotasks();
expect(cmp.log).toEqual([
'DEPTH 0',
'DEPTH 1',
]);
cmp.leave();
tick();
fixture.detectChanges();
const players = getLog();
expect(players.length).toEqual(2);
const [p1, p2] = players;
expect(p1.element.getAttribute('data-depth')).toEqual('0');
expect(p2.element.getAttribute('data-depth')).toEqual('1');
}));
});
const [p1, p2] = players;
expect(p1.element.getAttribute('data-depth')).toEqual('0');
expect(p2.element.getAttribute('data-depth')).toEqual('1');
}));
});
});
function makeAnimationData(value: string, params: {[key: string]: any} = {}): {[key: string]: any} {

View File

@ -15,23 +15,22 @@ import {browserDetection} from '@angular/platform-browser/testing/src/browser_ut
import {TestBed} from '../../testing';
(function() {
// these tests are only mean't to be run within the DOM (for now)
// Buggy in Chromium 39, see https://github.com/angular/angular/issues/15793
if (isNode) return;
// these tests are only mean't to be run within the DOM (for now)
// Buggy in Chromium 39, see https://github.com/angular/angular/issues/15793
if (isNode) return;
describe('animation integration tests using css keyframe animations', function() {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [{provide: AnimationDriver, useClass: CssKeyframesDriver}],
imports: [BrowserAnimationsModule]
});
describe('animation integration tests using css keyframe animations', function() {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [{provide: AnimationDriver, useClass: CssKeyframesDriver}],
imports: [BrowserAnimationsModule]
});
});
it('should compute (*) animation styles for a container that is being removed', () => {
@Component({
selector: 'ani-cmp',
template: `
it('should compute (*) animation styles for a container that is being removed', () => {
@Component({
selector: 'ani-cmp',
template: `
<div @auto *ngIf="exp">
<div style="line-height:20px;">1</div>
<div style="line-height:20px;">2</div>
@ -40,46 +39,46 @@ import {TestBed} from '../../testing';
<div style="line-height:20px;">5</div>
</div>
`,
animations: [trigger(
'auto',
[
state('void', style({height: '0px'})),
state('*', style({height: '*'})),
transition('* => *', animate(1000)),
])]
})
class Cmp {
public exp: boolean = false;
}
animations: [trigger(
'auto',
[
state('void', style({height: '0px'})),
state('*', style({height: '*'})),
transition('* => *', animate(1000)),
])]
})
class Cmp {
public exp: boolean = false;
}
TestBed.configureTestingModule({declarations: [Cmp]});
TestBed.configureTestingModule({declarations: [Cmp]});
const engine = TestBed.inject(AnimationEngine);
const fixture = TestBed.createComponent(Cmp);
const cmp = fixture.componentInstance;
const engine = TestBed.inject(AnimationEngine);
const fixture = TestBed.createComponent(Cmp);
const cmp = fixture.componentInstance;
cmp.exp = true;
fixture.detectChanges();
cmp.exp = true;
fixture.detectChanges();
expect(engine.players.length).toEqual(1);
let player = getPlayer(engine) as CssKeyframesPlayer;
expect(player.keyframes).toEqual([{height: '0px', offset: 0}, {height: '100px', offset: 1}]);
expect(engine.players.length).toEqual(1);
let player = getPlayer(engine) as CssKeyframesPlayer;
expect(player.keyframes).toEqual([{height: '0px', offset: 0}, {height: '100px', offset: 1}]);
player.finish();
if (browserDetection.isOldChrome) return;
player.finish();
if (browserDetection.isOldChrome) return;
cmp.exp = false;
fixture.detectChanges();
cmp.exp = false;
fixture.detectChanges();
player = getPlayer(engine) as CssKeyframesPlayer;
expect(player.keyframes).toEqual([{height: '100px', offset: 0}, {height: '0px', offset: 1}]);
});
player = getPlayer(engine) as CssKeyframesPlayer;
expect(player.keyframes).toEqual([{height: '100px', offset: 0}, {height: '0px', offset: 1}]);
});
it('should cleanup all existing @keyframe <style> objects after the animation has finished',
() => {
@Component({
selector: 'ani-cmp',
template: `
it('should cleanup all existing @keyframe <style> objects after the animation has finished',
() => {
@Component({
selector: 'ani-cmp',
template: `
<div [@myAnimation]="myAnimationExp">
<div>1</div>
<div>2</div>
@ -88,278 +87,278 @@ import {TestBed} from '../../testing';
<div>5</div>
</div>
`,
animations: [trigger(
'myAnimation',
[
transition(
'* => go',
[
query(
'div',
[
style({opacity: 0}),
animate('1s', style({opacity: 0})),
]),
]),
])]
})
class Cmp {
public myAnimationExp = '';
}
animations: [trigger(
'myAnimation',
[
transition(
'* => go',
[
query(
'div',
[
style({opacity: 0}),
animate('1s', style({opacity: 0})),
]),
]),
])]
})
class Cmp {
public myAnimationExp = '';
}
TestBed.configureTestingModule({declarations: [Cmp]});
TestBed.configureTestingModule({declarations: [Cmp]});
const engine = TestBed.inject(AnimationEngine);
const fixture = TestBed.createComponent(Cmp);
const cmp = fixture.componentInstance;
const engine = TestBed.inject(AnimationEngine);
const fixture = TestBed.createComponent(Cmp);
const cmp = fixture.componentInstance;
cmp.myAnimationExp = 'go';
fixture.detectChanges();
cmp.myAnimationExp = 'go';
fixture.detectChanges();
const webPlayer = <AnimationGroupPlayer>getPlayer(engine);
const players = webPlayer.players as CssKeyframesPlayer[];
expect(players.length).toEqual(5);
const webPlayer = <AnimationGroupPlayer>getPlayer(engine);
const players = webPlayer.players as CssKeyframesPlayer[];
expect(players.length).toEqual(5);
const head = document.querySelector('head') !;
const sheets: any[] = [];
for (let i = 0; i < 5; i++) {
const sheet = findStyleObjectWithKeyframes(i);
expect(head.contains(sheet)).toBeTruthy();
sheets.push(sheet);
}
const head = document.querySelector('head')!;
const sheets: any[] = [];
for (let i = 0; i < 5; i++) {
const sheet = findStyleObjectWithKeyframes(i);
expect(head.contains(sheet)).toBeTruthy();
sheets.push(sheet);
}
cmp.myAnimationExp = 'go-back';
fixture.detectChanges();
cmp.myAnimationExp = 'go-back';
fixture.detectChanges();
for (let i = 0; i < 5; i++) {
expect(head.contains(sheets[i])).toBeFalsy();
}
});
for (let i = 0; i < 5; i++) {
expect(head.contains(sheets[i])).toBeFalsy();
}
});
it('should properly handle easing values that are apart of the sequence', () => {
@Component({
selector: 'ani-cmp',
template: `
it('should properly handle easing values that are apart of the sequence', () => {
@Component({
selector: 'ani-cmp',
template: `
<div #elm [@myAnimation]="myAnimationExp"></div>
`,
animations: [
trigger(
'myAnimation',
[
transition(
'* => goSteps',
[
style({opacity: 0}),
animate('1s ease-out', style({opacity: 1})),
]),
transition(
'* => goKeyframes',
[
animate('1s cubic-bezier(0.5, 1, 0.5, 1)', keyframes([
style({opacity: 0}),
style({opacity: 0.5}),
style({opacity: 1}),
])),
]),
]),
]
})
class Cmp {
@ViewChild('elm') public element: any;
animations: [
trigger(
'myAnimation',
[
transition(
'* => goSteps',
[
style({opacity: 0}),
animate('1s ease-out', style({opacity: 1})),
]),
transition(
'* => goKeyframes',
[
animate('1s cubic-bezier(0.5, 1, 0.5, 1)', keyframes([
style({opacity: 0}),
style({opacity: 0.5}),
style({opacity: 1}),
])),
]),
]),
]
})
class Cmp {
@ViewChild('elm') public element: any;
public myAnimationExp = '';
}
public myAnimationExp = '';
}
TestBed.configureTestingModule({declarations: [Cmp]});
TestBed.configureTestingModule({declarations: [Cmp]});
const engine = TestBed.inject(AnimationEngine);
const fixture = TestBed.createComponent(Cmp);
const cmp = fixture.componentInstance;
const engine = TestBed.inject(AnimationEngine);
const fixture = TestBed.createComponent(Cmp);
const cmp = fixture.componentInstance;
cmp.myAnimationExp = 'goSteps';
fixture.detectChanges();
cmp.myAnimationExp = 'goSteps';
fixture.detectChanges();
let kfElm = findStyleObjectWithKeyframes();
const [r1, r2] = kfElm.sheet.cssRules[0].cssRules;
assertEasing(r1, 'ease-out');
assertEasing(r2, '');
let kfElm = findStyleObjectWithKeyframes();
const [r1, r2] = kfElm.sheet.cssRules[0].cssRules;
assertEasing(r1, 'ease-out');
assertEasing(r2, '');
const element = cmp.element.nativeElement;
const element = cmp.element.nativeElement;
const webPlayer = getPlayer(engine);
cmp.myAnimationExp = 'goKeyframes';
fixture.detectChanges();
const webPlayer = getPlayer(engine);
cmp.myAnimationExp = 'goKeyframes';
fixture.detectChanges();
assertEasing(element, 'cubic-bezier(0.5,1,0.5,1)');
});
assertEasing(element, 'cubic-bezier(0.5,1,0.5,1)');
});
it('should restore existing style values once the animation completes', () => {
@Component({
selector: 'ani-cmp',
template: `
it('should restore existing style values once the animation completes', () => {
@Component({
selector: 'ani-cmp',
template: `
<div #elm [@myAnimation]="myAnimationExp"></div>
`,
animations: [
trigger(
'myAnimation',
[
state('go', style({width: '200px'})),
transition(
'* => go',
[
style({height: '100px', width: '100px'}), group([
animate('1s', style({height: '200px'})),
animate('1s', style({width: '200px'}))
])
]),
]),
]
})
class Cmp {
@ViewChild('elm') public element: any;
animations: [
trigger(
'myAnimation',
[
state('go', style({width: '200px'})),
transition(
'* => go',
[
style({height: '100px', width: '100px'}), group([
animate('1s', style({height: '200px'})),
animate('1s', style({width: '200px'}))
])
]),
]),
]
})
class Cmp {
@ViewChild('elm') public element: any;
public myAnimationExp = '';
}
public myAnimationExp = '';
}
TestBed.configureTestingModule({declarations: [Cmp]});
TestBed.configureTestingModule({declarations: [Cmp]});
const engine = TestBed.inject(AnimationEngine);
const fixture = TestBed.createComponent(Cmp);
const cmp = fixture.componentInstance;
const engine = TestBed.inject(AnimationEngine);
const fixture = TestBed.createComponent(Cmp);
const cmp = fixture.componentInstance;
fixture.detectChanges();
const element = cmp.element.nativeElement;
element.style['width'] = '50px';
element.style['height'] = '50px';
fixture.detectChanges();
const element = cmp.element.nativeElement;
element.style['width'] = '50px';
element.style['height'] = '50px';
assertStyle(element, 'width', '50px');
assertStyle(element, 'height', '50px');
assertStyle(element, 'width', '50px');
assertStyle(element, 'height', '50px');
cmp.myAnimationExp = 'go';
fixture.detectChanges();
cmp.myAnimationExp = 'go';
fixture.detectChanges();
const player = getPlayer(engine);
const player = getPlayer(engine);
assertStyle(element, 'width', '100px');
assertStyle(element, 'height', '100px');
assertStyle(element, 'width', '100px');
assertStyle(element, 'height', '100px');
player.finish();
player.finish();
assertStyle(element, 'width', '200px');
assertStyle(element, 'height', '50px');
});
assertStyle(element, 'width', '200px');
assertStyle(element, 'height', '50px');
});
it('should clean up 0 second animation styles (queried styles) that contain camel casing when complete',
() => {
@Component({
selector: 'ani-cmp',
template: `
it('should clean up 0 second animation styles (queried styles) that contain camel casing when complete',
() => {
@Component({
selector: 'ani-cmp',
template: `
<div #elm [@myAnimation]="myAnimationExp">
<div class="foo"></div>
<div class="bar"></div>
</div>
`,
animations: [
trigger(
'myAnimation',
[
state('go', style({width: '200px'})),
transition(
'* => go',
[
query('.foo', [style({maxHeight: '0px'})]),
query(
'.bar',
[
style({width: '0px'}),
animate('1s', style({width: '100px'})),
]),
]),
]),
]
})
class Cmp {
@ViewChild('elm', {static: true}) public element: any;
animations: [
trigger(
'myAnimation',
[
state('go', style({width: '200px'})),
transition(
'* => go',
[
query('.foo', [style({maxHeight: '0px'})]),
query(
'.bar',
[
style({width: '0px'}),
animate('1s', style({width: '100px'})),
]),
]),
]),
]
})
class Cmp {
@ViewChild('elm', {static: true}) public element: any;
public myAnimationExp = '';
}
public myAnimationExp = '';
}
TestBed.configureTestingModule({declarations: [Cmp]});
TestBed.configureTestingModule({declarations: [Cmp]});
const engine = TestBed.inject(AnimationEngine);
const fixture = TestBed.createComponent(Cmp);
const cmp = fixture.componentInstance;
const engine = TestBed.inject(AnimationEngine);
const fixture = TestBed.createComponent(Cmp);
const cmp = fixture.componentInstance;
const elm = cmp.element.nativeElement;
const foo = elm.querySelector('.foo') as HTMLElement;
const elm = cmp.element.nativeElement;
const foo = elm.querySelector('.foo') as HTMLElement;
cmp.myAnimationExp = 'go';
fixture.detectChanges();
cmp.myAnimationExp = 'go';
fixture.detectChanges();
expect(foo.style.getPropertyValue('max-height')).toEqual('0px');
expect(foo.style.getPropertyValue('max-height')).toEqual('0px');
const player = engine.players.pop() !;
player.finish();
const player = engine.players.pop()!;
player.finish();
expect(foo.style.getPropertyValue('max-height')).toBeFalsy();
});
expect(foo.style.getPropertyValue('max-height')).toBeFalsy();
});
it('should apply the `display` and `position` styles as regular inline styles for the duration of the animation',
() => {
@Component({
selector: 'ani-cmp',
template: `
it('should apply the `display` and `position` styles as regular inline styles for the duration of the animation',
() => {
@Component({
selector: 'ani-cmp',
template: `
<div #elm [@myAnimation]="myAnimationExp" style="display:table; position:fixed"></div>
`,
animations: [
trigger(
'myAnimation',
[
state('go', style({display: 'inline-block'})),
transition(
'* => go',
[
style({display: 'inline', position: 'absolute', opacity: 0}),
animate('1s', style({display: 'inline', opacity: 1, position: 'static'})),
animate('1s', style({display: 'flexbox', opacity: 0})),
])
]),
]
})
class Cmp {
@ViewChild('elm', {static: true}) public element: any;
animations: [
trigger(
'myAnimation',
[
state('go', style({display: 'inline-block'})),
transition(
'* => go',
[
style({display: 'inline', position: 'absolute', opacity: 0}),
animate('1s', style({display: 'inline', opacity: 1, position: 'static'})),
animate('1s', style({display: 'flexbox', opacity: 0})),
])
]),
]
})
class Cmp {
@ViewChild('elm', {static: true}) public element: any;
public myAnimationExp = '';
}
public myAnimationExp = '';
}
TestBed.configureTestingModule({declarations: [Cmp]});
TestBed.configureTestingModule({declarations: [Cmp]});
const engine = TestBed.inject(AnimationEngine);
const fixture = TestBed.createComponent(Cmp);
const cmp = fixture.componentInstance;
const engine = TestBed.inject(AnimationEngine);
const fixture = TestBed.createComponent(Cmp);
const cmp = fixture.componentInstance;
const elm = cmp.element.nativeElement;
expect(elm.style.getPropertyValue('display')).toEqual('table');
expect(elm.style.getPropertyValue('position')).toEqual('fixed');
const elm = cmp.element.nativeElement;
expect(elm.style.getPropertyValue('display')).toEqual('table');
expect(elm.style.getPropertyValue('position')).toEqual('fixed');
cmp.myAnimationExp = 'go';
fixture.detectChanges();
cmp.myAnimationExp = 'go';
fixture.detectChanges();
expect(elm.style.getPropertyValue('display')).toEqual('inline');
expect(elm.style.getPropertyValue('position')).toEqual('absolute');
expect(elm.style.getPropertyValue('display')).toEqual('inline');
expect(elm.style.getPropertyValue('position')).toEqual('absolute');
const player = engine.players.pop() !;
player.finish();
player.destroy();
const player = engine.players.pop()!;
player.finish();
player.destroy();
expect(elm.style.getPropertyValue('display')).toEqual('inline-block');
expect(elm.style.getPropertyValue('position')).toEqual('fixed');
});
});
expect(elm.style.getPropertyValue('display')).toEqual('inline-block');
expect(elm.style.getPropertyValue('position')).toEqual('fixed');
});
});
})();
function getPlayer(engine: AnimationEngine, index = 0) {
return (engine.players[index] as any) !.getRealPlayer();
return (engine.players[index] as any)!.getRealPlayer();
}
function findStyleObjectWithKeyframes(index?: number): any|null {

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {animate, query, state, style, transition, trigger} from '@angular/animations';
import {AnimationDriver, ɵAnimationEngine, ɵWebAnimationsDriver, ɵWebAnimationsPlayer, ɵsupportsWebAnimations} from '@angular/animations/browser';
import {AnimationDriver, ɵAnimationEngine, ɵsupportsWebAnimations, ɵWebAnimationsDriver, ɵWebAnimationsPlayer} from '@angular/animations/browser';
import {TransitionAnimationPlayer} from '@angular/animations/browser/src/render/transition_animation_engine';
import {AnimationGroupPlayer} from '@angular/animations/src/players/animation_group_player';
import {Component, ViewChild} from '@angular/core';
@ -15,23 +15,22 @@ import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
import {browserDetection} from '@angular/platform-browser/testing/src/browser_util';
(function() {
// these tests are only mean't to be run within the DOM (for now)
// Buggy in Chromium 39, see https://github.com/angular/angular/issues/15793
if (isNode || !ɵsupportsWebAnimations()) return;
// these tests are only mean't to be run within the DOM (for now)
// Buggy in Chromium 39, see https://github.com/angular/angular/issues/15793
if (isNode || !ɵsupportsWebAnimations()) return;
describe('animation integration tests using web animations', function() {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [{provide: AnimationDriver, useClass: ɵWebAnimationsDriver}],
imports: [BrowserAnimationsModule]
});
describe('animation integration tests using web animations', function() {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [{provide: AnimationDriver, useClass: ɵWebAnimationsDriver}],
imports: [BrowserAnimationsModule]
});
});
it('should compute (*) animation styles for a container that is being removed', () => {
@Component({
selector: 'ani-cmp',
template: `
it('should compute (*) animation styles for a container that is being removed', () => {
@Component({
selector: 'ani-cmp',
template: `
<div @auto *ngIf="exp">
<div style="line-height:20px;">1</div>
<div style="line-height:20px;">2</div>
@ -40,152 +39,147 @@ import {browserDetection} from '@angular/platform-browser/testing/src/browser_ut
<div style="line-height:20px;">5</div>
</div>
`,
animations: [trigger(
'auto',
[
state('void', style({height: '0px'})), state('*', style({height: '*'})),
transition('* => *', animate(1000))
])]
})
class Cmp {
public exp: boolean = false;
}
animations: [trigger(
'auto',
[
state('void', style({height: '0px'})), state('*', style({height: '*'})),
transition('* => *', animate(1000))
])]
})
class Cmp {
public exp: boolean = false;
}
TestBed.configureTestingModule({declarations: [Cmp]});
TestBed.configureTestingModule({declarations: [Cmp]});
const engine = TestBed.inject(ɵAnimationEngine);
const fixture = TestBed.createComponent(Cmp);
const cmp = fixture.componentInstance;
const engine = TestBed.inject(ɵAnimationEngine);
const fixture = TestBed.createComponent(Cmp);
const cmp = fixture.componentInstance;
cmp.exp = true;
fixture.detectChanges();
cmp.exp = true;
fixture.detectChanges();
expect(engine.players.length).toEqual(1);
let webPlayer =
(engine.players[0] as TransitionAnimationPlayer).getRealPlayer() as ɵWebAnimationsPlayer;
expect(engine.players.length).toEqual(1);
let webPlayer =
(engine.players[0] as TransitionAnimationPlayer).getRealPlayer() as ɵWebAnimationsPlayer;
expect(webPlayer.keyframes).toEqual([
{height: '0px', offset: 0}, {height: '100px', offset: 1}
]);
expect(webPlayer.keyframes).toEqual([{height: '0px', offset: 0}, {height: '100px', offset: 1}]);
webPlayer.finish();
webPlayer.finish();
if (!browserDetection.isOldChrome) {
cmp.exp = false;
fixture.detectChanges();
engine.flush();
expect(engine.players.length).toEqual(1);
webPlayer = (engine.players[0] as TransitionAnimationPlayer)
.getRealPlayer() as ɵWebAnimationsPlayer;
expect(webPlayer.keyframes).toEqual([
{height: '100px', offset: 0}, {height: '0px', offset: 1}
]);
}
});
it('should compute (!) animation styles for a container that is being inserted', () => {
@Component({
selector: 'ani-cmp',
template: `
<div @auto *ngIf="exp">
<div style="line-height:20px;">1</div>
<div style="line-height:20px;">2</div>
<div style="line-height:20px;">3</div>
<div style="line-height:20px;">4</div>
<div style="line-height:20px;">5</div>
</div>
`,
animations: [trigger(
'auto',
[transition(
':enter', [style({height: '!'}), animate(1000, style({height: '120px'}))])])]
})
class Cmp {
public exp: boolean = false;
}
TestBed.configureTestingModule({declarations: [Cmp]});
const engine = TestBed.inject(ɵAnimationEngine);
const fixture = TestBed.createComponent(Cmp);
const cmp = fixture.componentInstance;
cmp.exp = true;
if (!browserDetection.isOldChrome) {
cmp.exp = false;
fixture.detectChanges();
engine.flush();
expect(engine.players.length).toEqual(1);
let webPlayer =
webPlayer =
(engine.players[0] as TransitionAnimationPlayer).getRealPlayer() as ɵWebAnimationsPlayer;
expect(webPlayer.keyframes).toEqual([
{height: '100px', offset: 0}, {height: '120px', offset: 1}
{height: '100px', offset: 0}, {height: '0px', offset: 1}
]);
});
}
});
it('should compute pre (!) and post (*) animation styles with different dom states', () => {
@Component({
selector: 'ani-cmp',
template: `
it('should compute (!) animation styles for a container that is being inserted', () => {
@Component({
selector: 'ani-cmp',
template: `
<div @auto *ngIf="exp">
<div style="line-height:20px;">1</div>
<div style="line-height:20px;">2</div>
<div style="line-height:20px;">3</div>
<div style="line-height:20px;">4</div>
<div style="line-height:20px;">5</div>
</div>
`,
animations: [trigger(
'auto',
[transition(':enter', [style({height: '!'}), animate(1000, style({height: '120px'}))])])]
})
class Cmp {
public exp: boolean = false;
}
TestBed.configureTestingModule({declarations: [Cmp]});
const engine = TestBed.inject(ɵAnimationEngine);
const fixture = TestBed.createComponent(Cmp);
const cmp = fixture.componentInstance;
cmp.exp = true;
fixture.detectChanges();
engine.flush();
expect(engine.players.length).toEqual(1);
let webPlayer =
(engine.players[0] as TransitionAnimationPlayer).getRealPlayer() as ɵWebAnimationsPlayer;
expect(webPlayer.keyframes).toEqual([
{height: '100px', offset: 0}, {height: '120px', offset: 1}
]);
});
it('should compute pre (!) and post (*) animation styles with different dom states', () => {
@Component({
selector: 'ani-cmp',
template: `
<div [@myAnimation]="exp" #parent>
<div *ngFor="let item of items" class="child" style="line-height:20px">
- {{ item }}
</div>
</div>
`,
animations: [trigger(
'myAnimation',
[transition('* => *', [style({height: '!'}), animate(1000, style({height: '*'}))])])]
})
class Cmp {
// TODO(issue/24571): remove '!'.
public exp !: number;
public items = [0, 1, 2, 3, 4];
}
animations: [trigger(
'myAnimation',
[transition('* => *', [style({height: '!'}), animate(1000, style({height: '*'}))])])]
})
class Cmp {
// TODO(issue/24571): remove '!'.
public exp!: number;
public items = [0, 1, 2, 3, 4];
}
TestBed.configureTestingModule({declarations: [Cmp]});
TestBed.configureTestingModule({declarations: [Cmp]});
const engine = TestBed.inject(ɵAnimationEngine);
const fixture = TestBed.createComponent(Cmp);
const cmp = fixture.componentInstance;
const engine = TestBed.inject(ɵAnimationEngine);
const fixture = TestBed.createComponent(Cmp);
const cmp = fixture.componentInstance;
cmp.exp = 1;
fixture.detectChanges();
engine.flush();
cmp.exp = 1;
fixture.detectChanges();
engine.flush();
expect(engine.players.length).toEqual(1);
let player = engine.players[0];
let webPlayer = (player as TransitionAnimationPlayer).getRealPlayer() as ɵWebAnimationsPlayer;
expect(engine.players.length).toEqual(1);
let player = engine.players[0];
let webPlayer = (player as TransitionAnimationPlayer).getRealPlayer() as ɵWebAnimationsPlayer;
expect(webPlayer.keyframes).toEqual([
{height: '0px', offset: 0}, {height: '100px', offset: 1}
]);
expect(webPlayer.keyframes).toEqual([{height: '0px', offset: 0}, {height: '100px', offset: 1}]);
// we destroy the player because since it has started and is
// at 0ms duration a height value of `0px` will be extracted
// from the element and passed into the follow-up animation.
player.destroy();
// we destroy the player because since it has started and is
// at 0ms duration a height value of `0px` will be extracted
// from the element and passed into the follow-up animation.
player.destroy();
cmp.exp = 2;
cmp.items = [0, 1, 2, 6];
fixture.detectChanges();
engine.flush();
cmp.exp = 2;
cmp.items = [0, 1, 2, 6];
fixture.detectChanges();
engine.flush();
expect(engine.players.length).toEqual(1);
player = engine.players[0];
webPlayer = (player as TransitionAnimationPlayer).getRealPlayer() as ɵWebAnimationsPlayer;
expect(engine.players.length).toEqual(1);
player = engine.players[0];
webPlayer = (player as TransitionAnimationPlayer).getRealPlayer() as ɵWebAnimationsPlayer;
expect(webPlayer.keyframes).toEqual([
{height: '100px', offset: 0}, {height: '80px', offset: 1}
]);
});
expect(webPlayer.keyframes).toEqual([
{height: '100px', offset: 0}, {height: '80px', offset: 1}
]);
});
it('should treat * styles as ! when a removal animation is being rendered', () => {
@Component({
selector: 'ani-cmp',
styles: [`
it('should treat * styles as ! when a removal animation is being rendered', () => {
@Component({
selector: 'ani-cmp',
styles: [`
.box {
width: 500px;
overflow:hidden;
@ -195,58 +189,60 @@ import {browserDetection} from '@angular/platform-browser/testing/src/browser_ut
text-align:center;
}
`],
template: `
template: `
<button (click)="toggle()">Open / Close</button>
<hr />
<div *ngIf="exp" @slide class="box">
...
</div>
`,
animations: [trigger(
'slide',
[
state('void', style({height: '0px'})),
state('*', style({height: '*'})),
transition('* => *', animate('500ms')),
])]
})
class Cmp {
exp = false;
animations: [trigger(
'slide',
[
state('void', style({height: '0px'})),
state('*', style({height: '*'})),
transition('* => *', animate('500ms')),
])]
})
class Cmp {
exp = false;
toggle() { this.exp = !this.exp; }
toggle() {
this.exp = !this.exp;
}
}
TestBed.configureTestingModule({declarations: [Cmp]});
TestBed.configureTestingModule({declarations: [Cmp]});
const engine = TestBed.inject(ɵAnimationEngine);
const fixture = TestBed.createComponent(Cmp);
const cmp = fixture.componentInstance;
const engine = TestBed.inject(ɵAnimationEngine);
const fixture = TestBed.createComponent(Cmp);
const cmp = fixture.componentInstance;
cmp.exp = true;
fixture.detectChanges();
cmp.exp = true;
fixture.detectChanges();
let player = engine.players[0] !;
let webPlayer = (player as TransitionAnimationPlayer).getRealPlayer() as ɵWebAnimationsPlayer;
expect(webPlayer.keyframes).toEqual([
{height: '0px', offset: 0},
{height: '300px', offset: 1},
]);
player.finish();
let player = engine.players[0]!;
let webPlayer = (player as TransitionAnimationPlayer).getRealPlayer() as ɵWebAnimationsPlayer;
expect(webPlayer.keyframes).toEqual([
{height: '0px', offset: 0},
{height: '300px', offset: 1},
]);
player.finish();
cmp.exp = false;
fixture.detectChanges();
cmp.exp = false;
fixture.detectChanges();
player = engine.players[0] !;
webPlayer = (player as TransitionAnimationPlayer).getRealPlayer() as ɵWebAnimationsPlayer;
expect(webPlayer.keyframes).toEqual([
{height: '300px', offset: 0},
{height: '0px', offset: 1},
]);
});
player = engine.players[0]!;
webPlayer = (player as TransitionAnimationPlayer).getRealPlayer() as ɵWebAnimationsPlayer;
expect(webPlayer.keyframes).toEqual([
{height: '300px', offset: 0},
{height: '0px', offset: 1},
]);
});
it('should treat * styles as ! for queried items that are collected in a container that is being removed',
() => {
@Component({
it('should treat * styles as ! for queried items that are collected in a container that is being removed',
() => {
@Component({
selector: 'my-app',
styles: [`
.list .outer {
@ -287,235 +283,236 @@ import {browserDetection} from '@angular/platform-browser/testing/src/browser_ut
]
})
class Cmp {
items: any[] = [];
items: any[] = [];
get exp() { return this.items.length ? 'full' : 'empty'; }
empty() { this.items = []; }
full() { this.items = [0, 1, 2, 3, 4]; }
get exp() {
return this.items.length ? 'full' : 'empty';
}
TestBed.configureTestingModule({declarations: [Cmp]});
empty() {
this.items = [];
}
const engine = TestBed.inject(ɵAnimationEngine);
const fixture = TestBed.createComponent(Cmp);
const cmp = fixture.componentInstance;
full() {
this.items = [0, 1, 2, 3, 4];
}
}
cmp.empty();
fixture.detectChanges();
let player = engine.players[0] !as TransitionAnimationPlayer;
TestBed.configureTestingModule({declarations: [Cmp]});
const engine = TestBed.inject(ɵAnimationEngine);
const fixture = TestBed.createComponent(Cmp);
const cmp = fixture.componentInstance;
cmp.empty();
fixture.detectChanges();
let player = engine.players[0]! as TransitionAnimationPlayer;
player.finish();
cmp.full();
fixture.detectChanges();
player = engine.players[0]! as TransitionAnimationPlayer;
let queriedPlayers =
((player as TransitionAnimationPlayer).getRealPlayer() as AnimationGroupPlayer).players;
expect(queriedPlayers.length).toEqual(5);
let i = 0;
for (i = 0; i < queriedPlayers.length; i++) {
let player = queriedPlayers[i] as ɵWebAnimationsPlayer;
expect(player.keyframes).toEqual([
{height: '0px', offset: 0},
{height: '50px', offset: 1},
]);
player.finish();
}
cmp.full();
fixture.detectChanges();
cmp.empty();
fixture.detectChanges();
player = engine.players[0] !as TransitionAnimationPlayer;
let queriedPlayers =
((player as TransitionAnimationPlayer).getRealPlayer() as AnimationGroupPlayer)
.players;
expect(queriedPlayers.length).toEqual(5);
player = engine.players[0]! as TransitionAnimationPlayer;
queriedPlayers =
((player as TransitionAnimationPlayer).getRealPlayer() as AnimationGroupPlayer).players;
expect(queriedPlayers.length).toEqual(5);
let i = 0;
for (i = 0; i < queriedPlayers.length; i++) {
let player = queriedPlayers[i] as ɵWebAnimationsPlayer;
expect(player.keyframes).toEqual([
{height: '0px', offset: 0},
{height: '50px', offset: 1},
]);
player.finish();
}
for (i = 0; i < queriedPlayers.length; i++) {
let player = queriedPlayers[i] as ɵWebAnimationsPlayer;
expect(player.keyframes).toEqual([
{height: '50px', offset: 0},
{height: '0px', offset: 1},
]);
}
});
cmp.empty();
fixture.detectChanges();
player = engine.players[0] !as TransitionAnimationPlayer;
queriedPlayers =
((player as TransitionAnimationPlayer).getRealPlayer() as AnimationGroupPlayer)
.players;
expect(queriedPlayers.length).toEqual(5);
for (i = 0; i < queriedPlayers.length; i++) {
let player = queriedPlayers[i] as ɵWebAnimationsPlayer;
expect(player.keyframes).toEqual([
{height: '50px', offset: 0},
{height: '0px', offset: 1},
]);
}
});
it('should compute intermediate styles properly when an animation is cancelled', () => {
@Component({
selector: 'ani-cmp',
template: `
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 {
// TODO(issue/24571): remove '!'.
public exp !: string;
}
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 {
// TODO(issue/24571): remove '!'.
public exp!: string;
}
TestBed.configureTestingModule({declarations: [Cmp]});
TestBed.configureTestingModule({declarations: [Cmp]});
const engine = TestBed.inject(ɵAnimationEngine);
const fixture = TestBed.createComponent(Cmp);
const cmp = fixture.componentInstance;
const engine = TestBed.inject(ɵAnimationEngine);
const fixture = TestBed.createComponent(Cmp);
const cmp = fixture.componentInstance;
cmp.exp = 'a';
fixture.detectChanges();
cmp.exp = 'a';
fixture.detectChanges();
let player = engine.players[0] !;
let webPlayer = (player as TransitionAnimationPlayer).getRealPlayer() as ɵWebAnimationsPlayer;
webPlayer.setPosition(0.5);
let player = engine.players[0]!;
let webPlayer = (player as TransitionAnimationPlayer).getRealPlayer() as ɵWebAnimationsPlayer;
webPlayer.setPosition(0.5);
cmp.exp = 'b';
fixture.detectChanges();
cmp.exp = 'b';
fixture.detectChanges();
player = engine.players[0] !;
webPlayer = (player as TransitionAnimationPlayer).getRealPlayer() as ɵWebAnimationsPlayer;
expect(approximate(parseFloat(webPlayer.keyframes[0]['width'] as string), 150))
.toBeLessThan(0.05);
expect(approximate(parseFloat(webPlayer.keyframes[0]['height'] as string), 300))
.toBeLessThan(0.05);
});
player = engine.players[0]!;
webPlayer = (player as TransitionAnimationPlayer).getRealPlayer() as ɵWebAnimationsPlayer;
expect(approximate(parseFloat(webPlayer.keyframes[0]['width'] as string), 150))
.toBeLessThan(0.05);
expect(approximate(parseFloat(webPlayer.keyframes[0]['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: `
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 {
// TODO(issue/24571): remove '!'.
public exp !: string;
public items: any[] = [];
}
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 {
// TODO(issue/24571): remove '!'.
public exp!: string;
public items: any[] = [];
}
TestBed.configureTestingModule({declarations: [Cmp]});
TestBed.configureTestingModule({declarations: [Cmp]});
const engine = TestBed.inject(ɵAnimationEngine);
const fixture = TestBed.createComponent(Cmp);
const cmp = fixture.componentInstance;
const engine = TestBed.inject(ɵAnimationEngine);
const fixture = TestBed.createComponent(Cmp);
const cmp = fixture.componentInstance;
cmp.exp = 'full';
cmp.items = [0, 1, 2, 3, 4];
fixture.detectChanges();
cmp.exp = 'full';
cmp.items = [0, 1, 2, 3, 4];
fixture.detectChanges();
let player = engine.players[0] !;
let groupPlayer =
(player as TransitionAnimationPlayer).getRealPlayer() as AnimationGroupPlayer;
let players = groupPlayer.players;
expect(players.length).toEqual(5);
let player = engine.players[0]!;
let groupPlayer =
(player as TransitionAnimationPlayer).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);
}
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();
cmp.exp = 'empty';
cmp.items = [];
fixture.detectChanges();
player = engine.players[0];
groupPlayer =
(player as TransitionAnimationPlayer).getRealPlayer() as AnimationGroupPlayer;
players = groupPlayer.players;
player = engine.players[0];
groupPlayer = (player as TransitionAnimationPlayer).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.keyframes[0]['width'] as string), 250))
.toBeLessThan(0.05);
expect(approximate(parseFloat(p.keyframes[0]['height'] as string), 500))
.toBeLessThan(0.05);
}
});
expect(players.length).toEqual(5);
for (let i = 0; i < players.length; i++) {
const p = players[i] as ɵWebAnimationsPlayer;
expect(approximate(parseFloat(p.keyframes[0]['width'] as string), 250)).toBeLessThan(0.05);
expect(approximate(parseFloat(p.keyframes[0]['height'] as string), 500))
.toBeLessThan(0.05);
}
});
it('should apply the `display` and `position` styles as regular inline styles for the duration of the animation',
() => {
@Component({
selector: 'ani-cmp',
template: `
it('should apply the `display` and `position` styles as regular inline styles for the duration of the animation',
() => {
@Component({
selector: 'ani-cmp',
template: `
<div #elm [@myAnimation]="myAnimationExp" style="display:table; position:fixed"></div>
`,
animations: [
trigger(
'myAnimation',
[
state('go', style({display: 'inline-block'})),
transition(
'* => go',
[
style({display: 'inline', position: 'absolute', opacity: 0}),
animate('1s', style({display: 'inline', opacity: 1, position: 'static'})),
animate('1s', style({display: 'flexbox', opacity: 0})),
])
]),
]
})
class Cmp {
@ViewChild('elm', {static: true}) public element: any;
animations: [
trigger(
'myAnimation',
[
state('go', style({display: 'inline-block'})),
transition(
'* => go',
[
style({display: 'inline', position: 'absolute', opacity: 0}),
animate('1s', style({display: 'inline', opacity: 1, position: 'static'})),
animate('1s', style({display: 'flexbox', opacity: 0})),
])
]),
]
})
class Cmp {
@ViewChild('elm', {static: true}) public element: any;
public myAnimationExp = '';
}
public myAnimationExp = '';
}
TestBed.configureTestingModule({declarations: [Cmp]});
TestBed.configureTestingModule({declarations: [Cmp]});
const engine = TestBed.inject(ɵAnimationEngine);
const fixture = TestBed.createComponent(Cmp);
const cmp = fixture.componentInstance;
const engine = TestBed.inject(ɵAnimationEngine);
const fixture = TestBed.createComponent(Cmp);
const cmp = fixture.componentInstance;
const elm = cmp.element.nativeElement;
expect(elm.style.getPropertyValue('display')).toEqual('table');
expect(elm.style.getPropertyValue('position')).toEqual('fixed');
const elm = cmp.element.nativeElement;
expect(elm.style.getPropertyValue('display')).toEqual('table');
expect(elm.style.getPropertyValue('position')).toEqual('fixed');
cmp.myAnimationExp = 'go';
fixture.detectChanges();
cmp.myAnimationExp = 'go';
fixture.detectChanges();
expect(elm.style.getPropertyValue('display')).toEqual('inline');
expect(elm.style.getPropertyValue('position')).toEqual('absolute');
expect(elm.style.getPropertyValue('display')).toEqual('inline');
expect(elm.style.getPropertyValue('position')).toEqual('absolute');
const player = engine.players.pop() !;
player.finish();
player.destroy();
const player = engine.players.pop()!;
player.finish();
player.destroy();
expect(elm.style.getPropertyValue('display')).toEqual('inline-block');
expect(elm.style.getPropertyValue('position')).toEqual('fixed');
});
});
expect(elm.style.getPropertyValue('display')).toEqual('inline-block');
expect(elm.style.getPropertyValue('position')).toEqual('fixed');
});
});
})();
function approximate(value: number, target: number) {