test(ivy): enable ivy tests for platform-browser/animations (#27478)

PR Close #27478
This commit is contained in:
Olivier Combe 2018-12-05 14:39:54 +01:00 committed by Igor Minar
parent 8973dd5a7e
commit b82f62a11d
6 changed files with 204 additions and 194 deletions

View File

@ -5,7 +5,7 @@
* Use of this source code is governed by an MIT-style license that can be * 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 * found in the LICENSE file at https://angular.io/license
*/ */
import {AnimationBuilder, AnimationFactory, AnimationMetadata, AnimationOptions, AnimationPlayer, NoopAnimationPlayer, sequence} from '@angular/animations'; import {AnimationBuilder, AnimationFactory, AnimationMetadata, AnimationOptions, AnimationPlayer, sequence} from '@angular/animations';
import {Inject, Injectable, RendererFactory2, RendererType2, ViewEncapsulation} from '@angular/core'; import {Inject, Injectable, RendererFactory2, RendererType2, ViewEncapsulation} from '@angular/core';
import {DOCUMENT} from '@angular/platform-browser'; import {DOCUMENT} from '@angular/platform-browser';

View File

@ -7,3 +7,4 @@
*/ */
export {BrowserAnimationBuilder as ɵBrowserAnimationBuilder, BrowserAnimationFactory as ɵBrowserAnimationFactory} from './animation_builder'; export {BrowserAnimationBuilder as ɵBrowserAnimationBuilder, BrowserAnimationFactory as ɵBrowserAnimationFactory} from './animation_builder';
export {AnimationRenderer as ɵAnimationRenderer, AnimationRendererFactory as ɵAnimationRendererFactory} from './animation_renderer'; export {AnimationRenderer as ɵAnimationRenderer, AnimationRendererFactory as ɵAnimationRendererFactory} from './animation_renderer';
export {InjectableAnimationEngine as ɵInjectableAnimationEngine} from './providers';

View File

@ -17,6 +17,7 @@ ts_library(
"//packages/platform-browser-dynamic", "//packages/platform-browser-dynamic",
"//packages/platform-browser/animations", "//packages/platform-browser/animations",
"//packages/platform-browser/testing", "//packages/platform-browser/testing",
"//packages/private/testing",
"@rxjs", "@rxjs",
], ],
) )
@ -24,9 +25,6 @@ ts_library(
jasmine_node_test( jasmine_node_test(
name = "test", name = "test",
bootstrap = ["angular/tools/testing/init_node_spec.js"], bootstrap = ["angular/tools/testing/init_node_spec.js"],
tags = [
"fixme-ivy-aot",
],
deps = [ deps = [
":test_lib", ":test_lib",
"//tools/testing:node", "//tools/testing:node",
@ -35,9 +33,6 @@ jasmine_node_test(
ts_web_test_suite( ts_web_test_suite(
name = "test_web", name = "test_web",
tags = [
"fixme-ivy-aot",
],
deps = [ deps = [
":test_lib", ":test_lib",
], ],

View File

@ -9,11 +9,11 @@ import {AnimationPlayer, AnimationTriggerMetadata, animate, state, style, transi
import {ɵAnimationEngine as AnimationEngine} from '@angular/animations/browser'; import {ɵAnimationEngine as AnimationEngine} from '@angular/animations/browser';
import {Component, Injectable, NgZone, RendererFactory2, RendererType2, ViewChild} from '@angular/core'; import {Component, Injectable, NgZone, RendererFactory2, RendererType2, ViewChild} from '@angular/core';
import {TestBed} from '@angular/core/testing'; import {TestBed} from '@angular/core/testing';
import {BrowserAnimationsModule, ɵAnimationRendererFactory as AnimationRendererFactory} from '@angular/platform-browser/animations'; import {BrowserAnimationsModule, ɵAnimationRendererFactory as AnimationRendererFactory, ɵInjectableAnimationEngine as InjectableAnimationEngine} from '@angular/platform-browser/animations';
import {DomRendererFactory2} from '@angular/platform-browser/src/dom/dom_renderer'; import {DomRendererFactory2} from '@angular/platform-browser/src/dom/dom_renderer';
import {fixmeIvy} from '@angular/private/testing';
import {el} from '../../testing/src/browser_util'; import {el} from '../../testing/src/browser_util';
import {InjectableAnimationEngine} from '../src/providers';
(function() { (function() {
if (isNode) return; if (isNode) return;
@ -120,42 +120,44 @@ import {InjectableAnimationEngine} from '../src/providers';
// these tests are only mean't to be run within the DOM // these tests are only mean't to be run within the DOM
if (isNode) return; if (isNode) return;
it('should flush and fire callbacks when the zone becomes stable', (async) => { fixmeIvy(
@Component({ `FW-643: Components with animations throw with "Failed to execute 'setAttribute' on 'Element'`) &&
selector: 'my-cmp', it('should flush and fire callbacks when the zone becomes stable', (async) => {
template: '<div [@myAnimation]="exp" (@myAnimation.start)="onStart($event)"></div>', @Component({
animations: [trigger( selector: 'my-cmp',
'myAnimation', template: '<div [@myAnimation]="exp" (@myAnimation.start)="onStart($event)"></div>',
[transition( animations: [trigger(
'* => state', 'myAnimation',
[style({'opacity': '0'}), animate(500, style({'opacity': '1'}))])])], [transition(
}) '* => state',
class Cmp { [style({'opacity': '0'}), animate(500, style({'opacity': '1'}))])])],
exp: any; })
event: any; class Cmp {
onStart(event: any) { this.event = event; } exp: any;
} event: any;
onStart(event: any) { this.event = event; }
}
TestBed.configureTestingModule({ TestBed.configureTestingModule({
providers: [{provide: AnimationEngine, useClass: InjectableAnimationEngine}], providers: [{provide: AnimationEngine, useClass: InjectableAnimationEngine}],
declarations: [Cmp] 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;
cmp.exp = 'state'; cmp.exp = 'state';
fixture.detectChanges(); fixture.detectChanges();
fixture.whenStable().then(() => { fixture.whenStable().then(() => {
expect(cmp.event.triggerName).toEqual('myAnimation'); expect(cmp.event.triggerName).toEqual('myAnimation');
expect(cmp.event.phaseName).toEqual('start'); expect(cmp.event.phaseName).toEqual('start');
cmp.event = null; cmp.event = null;
engine.flush(); engine.flush();
expect(cmp.event).toBeFalsy(); expect(cmp.event).toBeFalsy();
async(); async();
}); });
}); });
it('should properly insert/remove nodes through the animation renderer that do not contain animations', it('should properly insert/remove nodes through the animation renderer that do not contain animations',
(async) => { (async) => {
@ -195,75 +197,77 @@ import {InjectableAnimationEngine} from '../src/providers';
}); });
}); });
it('should only queue up dom removals if the element itself contains a valid leave animation', fixmeIvy(
() => { `FW-643: Components with animations throw with "Failed to execute 'setAttribute' on 'Element'`) &&
@Component({ it('should only queue up dom removals if the element itself contains a valid leave animation',
selector: 'my-cmp', () => {
template: ` @Component({
selector: 'my-cmp',
template: `
<div #elm1 *ngIf="exp1"></div> <div #elm1 *ngIf="exp1"></div>
<div #elm2 @animation1 *ngIf="exp2"></div> <div #elm2 @animation1 *ngIf="exp2"></div>
<div #elm3 @animation2 *ngIf="exp3"></div> <div #elm3 @animation2 *ngIf="exp3"></div>
`, `,
animations: [ animations: [
trigger('animation1', [transition('a => b', [])]), trigger('animation1', [transition('a => b', [])]),
trigger('animation2', [transition(':leave', [])]), trigger('animation2', [transition(':leave', [])]),
] ]
}) })
class Cmp { class Cmp {
exp1: any = true; exp1: any = true;
exp2: any = true; exp2: any = true;
exp3: any = true; exp3: any = true;
@ViewChild('elm1') public elm1: any; @ViewChild('elm1') public elm1: any;
@ViewChild('elm2') public elm2: any; @ViewChild('elm2') public elm2: any;
@ViewChild('elm3') public elm3: any; @ViewChild('elm3') public elm3: any;
} }
TestBed.configureTestingModule({ TestBed.configureTestingModule({
providers: [{provide: AnimationEngine, useClass: InjectableAnimationEngine}], providers: [{provide: AnimationEngine, useClass: InjectableAnimationEngine}],
declarations: [Cmp] 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();
const elm1 = cmp.elm1; const elm1 = cmp.elm1;
const elm2 = cmp.elm2; const elm2 = cmp.elm2;
const elm3 = cmp.elm3; const elm3 = cmp.elm3;
assertHasParent(elm1); assertHasParent(elm1);
assertHasParent(elm2); assertHasParent(elm2);
assertHasParent(elm3); assertHasParent(elm3);
engine.flush(); engine.flush();
finishPlayers(engine.players); finishPlayers(engine.players);
cmp.exp1 = false; cmp.exp1 = false;
fixture.detectChanges(); fixture.detectChanges();
assertHasParent(elm1, false); assertHasParent(elm1, false);
assertHasParent(elm2); assertHasParent(elm2);
assertHasParent(elm3); assertHasParent(elm3);
engine.flush(); engine.flush();
expect(engine.players.length).toEqual(0); expect(engine.players.length).toEqual(0);
cmp.exp2 = false; cmp.exp2 = false;
fixture.detectChanges(); fixture.detectChanges();
assertHasParent(elm1, false); assertHasParent(elm1, false);
assertHasParent(elm2, false); assertHasParent(elm2, false);
assertHasParent(elm3); assertHasParent(elm3);
engine.flush(); engine.flush();
expect(engine.players.length).toEqual(0); expect(engine.players.length).toEqual(0);
cmp.exp3 = false; cmp.exp3 = false;
fixture.detectChanges(); fixture.detectChanges();
assertHasParent(elm1, false); assertHasParent(elm1, false);
assertHasParent(elm2, false); assertHasParent(elm2, false);
assertHasParent(elm3); assertHasParent(elm3);
engine.flush(); engine.flush();
expect(engine.players.length).toEqual(1); expect(engine.players.length).toEqual(1);
}); });
}); });
}); });
@ -279,35 +283,37 @@ import {InjectableAnimationEngine} from '../src/providers';
}); });
}); });
it('should provide hooks at the start and end of change detection', () => { fixmeIvy(
@Component({ `FW-643: Components with animations throw with "Failed to execute 'setAttribute' on 'Element'`) &&
selector: 'my-cmp', it('should provide hooks at the start and end of change detection', () => {
template: ` @Component({
selector: 'my-cmp',
template: `
<div [@myAnimation]="exp"></div> <div [@myAnimation]="exp"></div>
`, `,
animations: [trigger('myAnimation', [])] animations: [trigger('myAnimation', [])]
}) })
class Cmp { class Cmp {
public exp: any; public exp: any;
} }
TestBed.configureTestingModule({ TestBed.configureTestingModule({
providers: [{provide: AnimationEngine, useClass: InjectableAnimationEngine}], providers: [{provide: AnimationEngine, useClass: InjectableAnimationEngine}],
declarations: [Cmp] declarations: [Cmp]
}); });
const renderer = TestBed.get(RendererFactory2) as ExtendedAnimationRendererFactory; const renderer = TestBed.get(RendererFactory2) as ExtendedAnimationRendererFactory;
const fixture = TestBed.createComponent(Cmp); const fixture = TestBed.createComponent(Cmp);
const cmp = fixture.componentInstance; const cmp = fixture.componentInstance;
renderer.log = []; renderer.log = [];
fixture.detectChanges(); fixture.detectChanges();
expect(renderer.log).toEqual(['begin', 'end']); expect(renderer.log).toEqual(['begin', 'end']);
renderer.log = []; renderer.log = [];
fixture.detectChanges(); fixture.detectChanges();
expect(renderer.log).toEqual(['begin', 'end']); expect(renderer.log).toEqual(['begin', 'end']);
}); });
}); });
})(); })();

View File

@ -10,10 +10,9 @@ import {AnimationDriver} from '@angular/animations/browser';
import {MockAnimationDriver} from '@angular/animations/browser/testing'; import {MockAnimationDriver} from '@angular/animations/browser/testing';
import {Component, ViewChild} from '@angular/core'; import {Component, ViewChild} from '@angular/core';
import {TestBed, fakeAsync, flushMicrotasks} from '@angular/core/testing'; import {TestBed, fakeAsync, flushMicrotasks} from '@angular/core/testing';
import {NoopAnimationsModule} from '@angular/platform-browser/animations'; import {NoopAnimationsModule, ɵBrowserAnimationBuilder as BrowserAnimationBuilder} from '@angular/platform-browser/animations';
import {el} from '../../testing/src/browser_util'; import {el} from '../../testing/src/browser_util';
import {BrowserAnimationBuilder} from '../src/animation_builder';
{ {
describe('BrowserAnimationBuilder', () => { describe('BrowserAnimationBuilder', () => {

View File

@ -9,88 +9,97 @@ import {animate, style, transition, trigger} from '@angular/animations';
import {ɵAnimationEngine} from '@angular/animations/browser'; import {ɵAnimationEngine} from '@angular/animations/browser';
import {Component} from '@angular/core'; import {Component} from '@angular/core';
import {TestBed} from '@angular/core/testing'; import {TestBed} from '@angular/core/testing';
import {NoopAnimationsModule} from '@angular/platform-browser/animations';
import {NoopAnimationsModule} from '../src/module'; import {fixmeIvy} from '@angular/private/testing';
{ {
describe('NoopAnimationsModule', () => { describe('NoopAnimationsModule', () => {
beforeEach(() => { TestBed.configureTestingModule({imports: [NoopAnimationsModule]}); }); beforeEach(() => { TestBed.configureTestingModule({imports: [NoopAnimationsModule]}); });
it('should flush and fire callbacks when the zone becomes stable', (async) => { it('should be removed once FW-643 is fixed', () => { expect(true).toBeTruthy(); });
@Component({
selector: 'my-cmp',
template:
'<div [@myAnimation]="exp" (@myAnimation.start)="onStart($event)" (@myAnimation.done)="onDone($event)"></div>',
animations: [trigger(
'myAnimation',
[transition(
'* => state', [style({'opacity': '0'}), animate(500, style({'opacity': '1'}))])])],
})
class Cmp {
exp: any;
startEvent: any;
doneEvent: any;
onStart(event: any) { this.startEvent = event; }
onDone(event: any) { this.doneEvent = event; }
}
TestBed.configureTestingModule({declarations: [Cmp]}); // TODO: remove the dummy test above ^ once the bug FW-643 has been fixed
fixmeIvy(
`FW-643: Components with animations throw with "Failed to execute 'setAttribute' on 'Element'`) &&
it('should flush and fire callbacks when the zone becomes stable', (async) => {
@Component({
selector: 'my-cmp',
template:
'<div [@myAnimation]="exp" (@myAnimation.start)="onStart($event)" (@myAnimation.done)="onDone($event)"></div>',
animations: [trigger(
'myAnimation',
[transition(
'* => state',
[style({'opacity': '0'}), animate(500, style({'opacity': '1'}))])])],
})
class Cmp {
exp: any;
startEvent: any;
doneEvent: any;
onStart(event: any) { this.startEvent = event; }
onDone(event: any) { this.doneEvent = event; }
}
const fixture = TestBed.createComponent(Cmp); TestBed.configureTestingModule({declarations: [Cmp]});
const cmp = fixture.componentInstance;
cmp.exp = 'state';
fixture.detectChanges();
fixture.whenStable().then(() => {
expect(cmp.startEvent.triggerName).toEqual('myAnimation');
expect(cmp.startEvent.phaseName).toEqual('start');
expect(cmp.doneEvent.triggerName).toEqual('myAnimation');
expect(cmp.doneEvent.phaseName).toEqual('done');
async();
});
});
it('should handle leave animation callbacks even if the element is destroyed in the process', const fixture = TestBed.createComponent(Cmp);
(async) => { const cmp = fixture.componentInstance;
@Component({ cmp.exp = 'state';
selector: 'my-cmp', fixture.detectChanges();
template: fixture.whenStable().then(() => {
'<div *ngIf="exp" @myAnimation (@myAnimation.start)="onStart($event)" (@myAnimation.done)="onDone($event)"></div>', expect(cmp.startEvent.triggerName).toEqual('myAnimation');
animations: [trigger( expect(cmp.startEvent.phaseName).toEqual('start');
'myAnimation', expect(cmp.doneEvent.triggerName).toEqual('myAnimation');
[transition( expect(cmp.doneEvent.phaseName).toEqual('done');
':leave', [style({'opacity': '0'}), animate(500, style({'opacity': '1'}))])])], async();
}) });
class Cmp { });
exp: any;
startEvent: any;
doneEvent: any;
onStart(event: any) { this.startEvent = event; }
onDone(event: any) { this.doneEvent = event; }
}
TestBed.configureTestingModule({declarations: [Cmp]}); fixmeIvy(
const engine = TestBed.get(ɵAnimationEngine); `FW-643: Components with animations throw with "Failed to execute 'setAttribute' on 'Element'`) &&
const fixture = TestBed.createComponent(Cmp); it('should handle leave animation callbacks even if the element is destroyed in the process',
const cmp = fixture.componentInstance; (async) => {
@Component({
selector: 'my-cmp',
template:
'<div *ngIf="exp" @myAnimation (@myAnimation.start)="onStart($event)" (@myAnimation.done)="onDone($event)"></div>',
animations: [trigger(
'myAnimation',
[transition(
':leave',
[style({'opacity': '0'}), animate(500, style({'opacity': '1'}))])])],
})
class Cmp {
exp: any;
startEvent: any;
doneEvent: any;
onStart(event: any) { this.startEvent = event; }
onDone(event: any) { this.doneEvent = event; }
}
cmp.exp = true; TestBed.configureTestingModule({declarations: [Cmp]});
fixture.detectChanges(); const engine = TestBed.get(ɵAnimationEngine);
fixture.whenStable().then(() => { const fixture = TestBed.createComponent(Cmp);
cmp.startEvent = null; const cmp = fixture.componentInstance;
cmp.doneEvent = null;
cmp.exp = false; cmp.exp = true;
fixture.detectChanges(); fixture.detectChanges();
fixture.whenStable().then(() => { fixture.whenStable().then(() => {
expect(cmp.startEvent.triggerName).toEqual('myAnimation'); cmp.startEvent = null;
expect(cmp.startEvent.phaseName).toEqual('start'); cmp.doneEvent = null;
expect(cmp.startEvent.toState).toEqual('void');
expect(cmp.doneEvent.triggerName).toEqual('myAnimation'); cmp.exp = false;
expect(cmp.doneEvent.phaseName).toEqual('done'); fixture.detectChanges();
expect(cmp.doneEvent.toState).toEqual('void'); fixture.whenStable().then(() => {
async(); expect(cmp.startEvent.triggerName).toEqual('myAnimation');
expect(cmp.startEvent.phaseName).toEqual('start');
expect(cmp.startEvent.toState).toEqual('void');
expect(cmp.doneEvent.triggerName).toEqual('myAnimation');
expect(cmp.doneEvent.phaseName).toEqual('done');
expect(cmp.doneEvent.toState).toEqual('void');
async();
});
});
}); });
});
});
}); });
} }