test(ivy): enable more of @angular/core tests on node and in a browser (#27572)

PR Close #27572
This commit is contained in:
Pawel Kozlowski 2018-12-10 15:01:12 +01:00 committed by Alex Rickabaugh
parent 54e4bdb842
commit 2182be48c4
4 changed files with 577 additions and 592 deletions

View File

@ -66,49 +66,48 @@ const DEFAULT_COMPONENT_ID = '1';
} }
describe('fakeAsync testing', () => { describe('fakeAsync testing', () => {
fixmeIvy('unknown').it( it('should only require one flushMicrotasks call to kick off animation callbacks',
'should only require one flushMicrotasks call to kick off animation callbacks', fakeAsync(() => {
fakeAsync(() => { @Component({
@Component({ selector: 'cmp',
selector: 'cmp', template: `
template: `
<div [@myAnimation]="exp" (@myAnimation.start)="cb('start')" (@myAnimation.done)="cb('done')"></div> <div [@myAnimation]="exp" (@myAnimation.start)="cb('start')" (@myAnimation.done)="cb('done')"></div>
`, `,
animations: [trigger( animations: [trigger(
'myAnimation', 'myAnimation',
[transition('* => on, * => off', [animate(1000, style({opacity: 1}))])])] [transition('* => on, * => off', [animate(1000, style({opacity: 1}))])])]
}) })
class Cmp { class Cmp {
exp: any = false; exp: any = false;
status: string = ''; status: string = '';
cb(status: string) { this.status = status; } cb(status: string) { this.status = status; }
} }
TestBed.configureTestingModule({declarations: [Cmp]}); TestBed.configureTestingModule({declarations: [Cmp]});
const fixture = TestBed.createComponent(Cmp); const fixture = TestBed.createComponent(Cmp);
const cmp = fixture.componentInstance; const cmp = fixture.componentInstance;
cmp.exp = 'on'; cmp.exp = 'on';
fixture.detectChanges(); fixture.detectChanges();
expect(cmp.status).toEqual(''); expect(cmp.status).toEqual('');
flushMicrotasks(); flushMicrotasks();
expect(cmp.status).toEqual('start'); expect(cmp.status).toEqual('start');
let player = MockAnimationDriver.log.pop() !; let player = MockAnimationDriver.log.pop() !;
player.finish(); player.finish();
expect(cmp.status).toEqual('done'); expect(cmp.status).toEqual('done');
cmp.status = ''; cmp.status = '';
cmp.exp = 'off'; cmp.exp = 'off';
fixture.detectChanges(); fixture.detectChanges();
expect(cmp.status).toEqual(''); expect(cmp.status).toEqual('');
player = MockAnimationDriver.log.pop() !; player = MockAnimationDriver.log.pop() !;
player.finish(); player.finish();
expect(cmp.status).toEqual(''); expect(cmp.status).toEqual('');
flushMicrotasks(); flushMicrotasks();
expect(cmp.status).toEqual('done'); expect(cmp.status).toEqual('done');
})); }));
fixmeIvy('unknown').it( fixmeIvy('unknown').it(
'should always run .start callbacks before .done callbacks even for noop animations', 'should always run .start callbacks before .done callbacks even for noop animations',
@ -459,123 +458,120 @@ const DEFAULT_COMPONENT_ID = '1';
expect(player.duration).toEqual(1234); expect(player.duration).toEqual(1234);
}); });
fixmeIvy('unknown').it( it('should always cancel the previous transition if a follow-up transition is not matched',
'should always cancel the previous transition if a follow-up transition is not matched', fakeAsync(() => {
fakeAsync(() => { @Component({
@Component({ selector: 'if-cmp',
selector: 'if-cmp', template: `
template: `
<div [@myAnimation]="exp" (@myAnimation.start)="callback($event)" (@myAnimation.done)="callback($event)"></div> <div [@myAnimation]="exp" (@myAnimation.start)="callback($event)" (@myAnimation.done)="callback($event)"></div>
`, `,
animations: [trigger( animations: [trigger(
'myAnimation', 'myAnimation',
[transition( [transition(
'a => b', 'a => b', [style({'opacity': '0'}), animate(500, style({'opacity': '1'}))])])],
[style({'opacity': '0'}), animate(500, style({'opacity': '1'}))])])], })
}) class Cmp {
class Cmp { exp: any;
exp: any; startEvent: any;
startEvent: any; doneEvent: any;
doneEvent: any;
callback(event: any) { callback(event: any) {
if (event.phaseName == 'done') { if (event.phaseName == 'done') {
this.doneEvent = event; this.doneEvent = event;
} else { } else {
this.startEvent = event; this.startEvent = event;
} }
} }
} }
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;
cmp.exp = 'a'; cmp.exp = 'a';
fixture.detectChanges(); fixture.detectChanges();
engine.flush(); engine.flush();
expect(getLog().length).toEqual(0); expect(getLog().length).toEqual(0);
expect(engine.players.length).toEqual(0); expect(engine.players.length).toEqual(0);
flushMicrotasks(); flushMicrotasks();
expect(cmp.startEvent.toState).toEqual('a'); expect(cmp.startEvent.toState).toEqual('a');
expect(cmp.startEvent.totalTime).toEqual(0); expect(cmp.startEvent.totalTime).toEqual(0);
expect(cmp.startEvent.toState).toEqual('a'); expect(cmp.startEvent.toState).toEqual('a');
expect(cmp.startEvent.totalTime).toEqual(0); expect(cmp.startEvent.totalTime).toEqual(0);
resetLog(); resetLog();
cmp.exp = 'b'; cmp.exp = 'b';
fixture.detectChanges(); fixture.detectChanges();
engine.flush(); engine.flush();
const players = getLog(); const players = getLog();
expect(players.length).toEqual(1); expect(players.length).toEqual(1);
expect(engine.players.length).toEqual(1); expect(engine.players.length).toEqual(1);
flushMicrotasks(); flushMicrotasks();
expect(cmp.startEvent.toState).toEqual('b'); expect(cmp.startEvent.toState).toEqual('b');
expect(cmp.startEvent.totalTime).toEqual(500); expect(cmp.startEvent.totalTime).toEqual(500);
expect(cmp.startEvent.toState).toEqual('b'); expect(cmp.startEvent.toState).toEqual('b');
expect(cmp.startEvent.totalTime).toEqual(500); expect(cmp.startEvent.totalTime).toEqual(500);
resetLog(); resetLog();
let completed = false; let completed = false;
players[0].onDone(() => completed = true); players[0].onDone(() => completed = true);
cmp.exp = 'c'; cmp.exp = 'c';
fixture.detectChanges(); fixture.detectChanges();
engine.flush(); engine.flush();
expect(engine.players.length).toEqual(0); expect(engine.players.length).toEqual(0);
expect(getLog().length).toEqual(0); expect(getLog().length).toEqual(0);
flushMicrotasks(); flushMicrotasks();
expect(cmp.startEvent.toState).toEqual('c'); expect(cmp.startEvent.toState).toEqual('c');
expect(cmp.startEvent.totalTime).toEqual(0); expect(cmp.startEvent.totalTime).toEqual(0);
expect(cmp.startEvent.toState).toEqual('c'); expect(cmp.startEvent.toState).toEqual('c');
expect(cmp.startEvent.totalTime).toEqual(0); expect(cmp.startEvent.totalTime).toEqual(0);
expect(completed).toBe(true); expect(completed).toBe(true);
})); }));
fixmeIvy('unknown').it( it('should always fire inner callbacks even if no animation is fired when a view is inserted',
'should always fire inner callbacks even if no animation is fired when a view is inserted', fakeAsync(() => {
fakeAsync(() => { @Component({
@Component({ selector: 'if-cmp',
selector: 'if-cmp', template: `
template: `
<div *ngIf="exp"> <div *ngIf="exp">
<div @myAnimation (@myAnimation.start)="track($event)" (@myAnimation.done)="track($event)"></div> <div @myAnimation (@myAnimation.start)="track($event)" (@myAnimation.done)="track($event)"></div>
</div> </div>
`, `,
animations: [ animations: [
trigger('myAnimation', []), trigger('myAnimation', []),
] ]
}) })
class Cmp { class Cmp {
exp: any = false; exp: any = false;
log: string[] = []; log: string[] = [];
track(event: any) { this.log.push(`${event.triggerName}-${event.phaseName}`); } track(event: any) { this.log.push(`${event.triggerName}-${event.phaseName}`); }
} }
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();
flushMicrotasks(); flushMicrotasks();
expect(cmp.log).toEqual([]); expect(cmp.log).toEqual([]);
cmp.exp = true; cmp.exp = true;
fixture.detectChanges(); fixture.detectChanges();
flushMicrotasks(); flushMicrotasks();
expect(cmp.log).toEqual(['myAnimation-start', 'myAnimation-done']); expect(cmp.log).toEqual(['myAnimation-start', 'myAnimation-done']);
})); }));
fixmeIvy('unknown').it( fixmeIvy('unknown').it(
'should only turn a view removal as into `void` state transition', () => { 'should only turn a view removal as into `void` state transition', () => {
@ -2546,133 +2542,131 @@ const DEFAULT_COMPONENT_ID = '1';
expect(cmp.event.toState).toEqual('b'); expect(cmp.event.toState).toEqual('b');
})); }));
fixmeIvy('unknown').it( it('should handle callbacks for multiple triggers running simultaneously', fakeAsync(() => {
'should handle callbacks for multiple triggers running simultaneously', fakeAsync(() => { @Component({
@Component({ selector: 'if-cmp',
selector: 'if-cmp', template: `
template: `
<div [@ani1]="exp1" (@ani1.done)="callback1($event)"></div> <div [@ani1]="exp1" (@ani1.done)="callback1($event)"></div>
<div [@ani2]="exp2" (@ani2.done)="callback2($event)"></div> <div [@ani2]="exp2" (@ani2.done)="callback2($event)"></div>
`, `,
animations: [ animations: [
trigger( trigger(
'ani1', 'ani1',
[ [
transition( transition(
'* => a', '* => a',
[style({'opacity': '0'}), animate(999, style({'opacity': '1'}))]), [style({'opacity': '0'}), animate(999, style({'opacity': '1'}))]),
]), ]),
trigger( trigger(
'ani2', 'ani2',
[ [
transition( transition(
'* => b', '* => b',
[style({'width': '0px'}), animate(999, style({'width': '100px'}))]), [style({'width': '0px'}), animate(999, style({'width': '100px'}))]),
]) ])
], ],
}) })
class Cmp { class Cmp {
exp1: any = false; exp1: any = false;
exp2: any = false; exp2: any = false;
// TODO(issue/24571): remove '!'. // TODO(issue/24571): remove '!'.
event1 !: AnimationEvent; event1 !: AnimationEvent;
// TODO(issue/24571): remove '!'. // TODO(issue/24571): remove '!'.
event2 !: AnimationEvent; event2 !: AnimationEvent;
// tslint:disable:semicolon // tslint:disable:semicolon
callback1 = (event: any) => { this.event1 = event; }; callback1 = (event: any) => { this.event1 = event; };
// tslint:disable:semicolon // tslint:disable:semicolon
callback2 = (event: any) => { this.event2 = event; }; callback2 = (event: any) => { this.event2 = event; };
} }
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;
cmp.exp1 = 'a'; cmp.exp1 = 'a';
cmp.exp2 = 'b'; cmp.exp2 = 'b';
fixture.detectChanges(); fixture.detectChanges();
engine.flush(); engine.flush();
expect(cmp.event1).toBeFalsy(); expect(cmp.event1).toBeFalsy();
expect(cmp.event2).toBeFalsy(); expect(cmp.event2).toBeFalsy();
const player1 = engine.players[0]; const player1 = engine.players[0];
const player2 = engine.players[1]; const player2 = engine.players[1];
player1.finish(); player1.finish();
player2.finish(); player2.finish();
expect(cmp.event1).toBeFalsy(); expect(cmp.event1).toBeFalsy();
expect(cmp.event2).toBeFalsy(); expect(cmp.event2).toBeFalsy();
flushMicrotasks(); flushMicrotasks();
expect(cmp.event1.triggerName).toBeTruthy('ani1'); expect(cmp.event1.triggerName).toBeTruthy('ani1');
expect(cmp.event2.triggerName).toBeTruthy('ani2'); expect(cmp.event2.triggerName).toBeTruthy('ani2');
})); }));
fixmeIvy('unknown').it( it('should handle callbacks for multiple triggers running simultaneously on the same element',
'should handle callbacks for multiple triggers running simultaneously on the same element', fakeAsync(() => {
fakeAsync(() => { @Component({
@Component({ selector: 'if-cmp',
selector: 'if-cmp', template: `
template: `
<div [@ani1]="exp1" (@ani1.done)="callback1($event)" [@ani2]="exp2" (@ani2.done)="callback2($event)"></div> <div [@ani1]="exp1" (@ani1.done)="callback1($event)" [@ani2]="exp2" (@ani2.done)="callback2($event)"></div>
`, `,
animations: [ animations: [
trigger( trigger(
'ani1', 'ani1',
[ [
transition( transition(
'* => a', '* => a',
[style({'opacity': '0'}), animate(999, style({'opacity': '1'}))]), [style({'opacity': '0'}), animate(999, style({'opacity': '1'}))]),
]), ]),
trigger( trigger(
'ani2', 'ani2',
[ [
transition( transition(
'* => b', '* => b',
[style({'width': '0px'}), animate(999, style({'width': '100px'}))]), [style({'width': '0px'}), animate(999, style({'width': '100px'}))]),
]) ])
], ],
}) })
class Cmp { class Cmp {
exp1: any = false; exp1: any = false;
exp2: any = false; exp2: any = false;
// TODO(issue/24571): remove '!'. // TODO(issue/24571): remove '!'.
event1 !: AnimationEvent; event1 !: AnimationEvent;
// TODO(issue/24571): remove '!'. // TODO(issue/24571): remove '!'.
event2 !: AnimationEvent; event2 !: AnimationEvent;
callback1 = (event: any) => { this.event1 = event; }; callback1 = (event: any) => { this.event1 = event; };
callback2 = (event: any) => { this.event2 = event; }; callback2 = (event: any) => { this.event2 = event; };
} }
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;
cmp.exp1 = 'a'; cmp.exp1 = 'a';
cmp.exp2 = 'b'; cmp.exp2 = 'b';
fixture.detectChanges(); fixture.detectChanges();
engine.flush(); engine.flush();
expect(cmp.event1).toBeFalsy(); expect(cmp.event1).toBeFalsy();
expect(cmp.event2).toBeFalsy(); expect(cmp.event2).toBeFalsy();
const player1 = engine.players[0]; const player1 = engine.players[0];
const player2 = engine.players[1]; const player2 = engine.players[1];
player1.finish(); player1.finish();
player2.finish(); player2.finish();
expect(cmp.event1).toBeFalsy(); expect(cmp.event1).toBeFalsy();
expect(cmp.event2).toBeFalsy(); expect(cmp.event2).toBeFalsy();
flushMicrotasks(); flushMicrotasks();
expect(cmp.event1.triggerName).toBeTruthy('ani1'); expect(cmp.event1.triggerName).toBeTruthy('ani1');
expect(cmp.event2.triggerName).toBeTruthy('ani2'); expect(cmp.event2.triggerName).toBeTruthy('ani2');
})); }));
it('should handle a leave animation for multiple triggers even if not all triggers have their own leave transition specified', it('should handle a leave animation for multiple triggers even if not all triggers have their own leave transition specified',
fakeAsync(() => { fakeAsync(() => {
@ -2810,46 +2804,45 @@ const DEFAULT_COMPONENT_ID = '1';
expect(cmp.log).toEqual(['start => b', 'done => b']); expect(cmp.log).toEqual(['start => b', 'done => b']);
})); }));
fixmeIvy('unknown').it( it('should fire callback events for leave animations even if there is no leave transition',
'should fire callback events for leave animations even if there is no leave transition', fakeAsync(() => {
fakeAsync(() => { @Component({
@Component({ selector: 'my-cmp',
selector: 'my-cmp', template: `
template: `
<div *ngIf="exp" @myAnimation (@myAnimation.start)="callback($event)" (@myAnimation.done)="callback($event)"></div> <div *ngIf="exp" @myAnimation (@myAnimation.start)="callback($event)" (@myAnimation.done)="callback($event)"></div>
`, `,
animations: [trigger('myAnimation', [])] animations: [trigger('myAnimation', [])]
}) })
class Cmp { class Cmp {
exp: boolean = false; exp: boolean = false;
log: any[] = []; log: any[] = [];
callback = (event: any) => { callback = (event: any) => {
const state = event.toState || '_default_'; const state = event.toState || '_default_';
this.log.push(`${event.phaseName} => ${state}`); this.log.push(`${event.phaseName} => ${state}`);
} }
} }
TestBed.configureTestingModule({ TestBed.configureTestingModule({
providers: [{provide: AnimationDriver, useClass: NoopAnimationDriver}], providers: [{provide: AnimationDriver, useClass: NoopAnimationDriver}],
declarations: [Cmp] declarations: [Cmp]
}); });
const fixture = TestBed.createComponent(Cmp); const fixture = TestBed.createComponent(Cmp);
const cmp = fixture.componentInstance; const cmp = fixture.componentInstance;
cmp.exp = true; cmp.exp = true;
fixture.detectChanges(); fixture.detectChanges();
flushMicrotasks(); flushMicrotasks();
expect(cmp.log).toEqual(['start => _default_', 'done => _default_']); expect(cmp.log).toEqual(['start => _default_', 'done => _default_']);
cmp.log = []; cmp.log = [];
cmp.exp = false; cmp.exp = false;
fixture.detectChanges(); fixture.detectChanges();
flushMicrotasks(); flushMicrotasks();
expect(cmp.log).toEqual(['start => void', 'done => void']); expect(cmp.log).toEqual(['start => void', 'done => void']);
})); }));
fixmeIvy('unknown').it( fixmeIvy('unknown').it(
'should fire callbacks on a sub animation once it starts and finishes', fakeAsync(() => { 'should fire callbacks on a sub animation once it starts and finishes', fakeAsync(() => {
@ -3285,60 +3278,59 @@ const DEFAULT_COMPONENT_ID = '1';
expect(parent.childElementCount).toEqual(0); expect(parent.childElementCount).toEqual(0);
}); });
fixmeIvy('unknown').it( it('should properly resolve animation event listeners when disabled', fakeAsync(() => {
'should properly resolve animation event listeners when disabled', fakeAsync(() => { @Component({
@Component({ selector: 'if-cmp',
selector: 'if-cmp', template: `
template: `
<div [@.disabled]="disableExp"> <div [@.disabled]="disableExp">
<div [@myAnimation]="exp" (@myAnimation.start)="startEvent=$event" (@myAnimation.done)="doneEvent=$event"></div> <div [@myAnimation]="exp" (@myAnimation.start)="startEvent=$event" (@myAnimation.done)="doneEvent=$event"></div>
</div> </div>
`, `,
animations: [ animations: [
trigger( trigger(
'myAnimation', 'myAnimation',
[ [
transition( transition(
'* => 1, * => 2', '* => 1, * => 2',
[style({opacity: 0}), animate(9876, style({opacity: 1}))]), [style({opacity: 0}), animate(9876, style({opacity: 1}))]),
]), ]),
] ]
}) })
class Cmp { class Cmp {
disableExp = false; disableExp = false;
exp = ''; exp = '';
// TODO(issue/24571): remove '!'. // TODO(issue/24571): remove '!'.
startEvent !: AnimationEvent; startEvent !: AnimationEvent;
// TODO(issue/24571): remove '!'. // TODO(issue/24571): remove '!'.
doneEvent !: AnimationEvent; doneEvent !: AnimationEvent;
} }
TestBed.configureTestingModule({declarations: [Cmp]}); TestBed.configureTestingModule({declarations: [Cmp]});
const fixture = TestBed.createComponent(Cmp); const fixture = TestBed.createComponent(Cmp);
const cmp = fixture.componentInstance; const cmp = fixture.componentInstance;
cmp.disableExp = true; cmp.disableExp = true;
fixture.detectChanges(); fixture.detectChanges();
resetLog(); resetLog();
expect(cmp.startEvent).toBeFalsy(); expect(cmp.startEvent).toBeFalsy();
expect(cmp.doneEvent).toBeFalsy(); expect(cmp.doneEvent).toBeFalsy();
cmp.exp = '1'; cmp.exp = '1';
fixture.detectChanges(); fixture.detectChanges();
flushMicrotasks(); flushMicrotasks();
expect(cmp.startEvent.totalTime).toEqual(9876); expect(cmp.startEvent.totalTime).toEqual(9876);
expect(cmp.startEvent.disabled).toBeTruthy(); expect(cmp.startEvent.disabled).toBeTruthy();
expect(cmp.doneEvent.totalTime).toEqual(9876); expect(cmp.doneEvent.totalTime).toEqual(9876);
expect(cmp.doneEvent.disabled).toBeTruthy(); expect(cmp.doneEvent.disabled).toBeTruthy();
cmp.exp = '2'; cmp.exp = '2';
cmp.disableExp = false; cmp.disableExp = false;
fixture.detectChanges(); fixture.detectChanges();
flushMicrotasks(); flushMicrotasks();
expect(cmp.startEvent.totalTime).toEqual(9876); expect(cmp.startEvent.totalTime).toEqual(9876);
expect(cmp.startEvent.disabled).toBeFalsy(); expect(cmp.startEvent.disabled).toBeFalsy();
// the done event isn't fired because it's an actual animation // the done event isn't fired because it's an actual animation
})); }));
it('should work when there are no animations on the component handling the disable/enable flag', it('should work when there are no animations on the component handling the disable/enable flag',
() => { () => {
@ -3429,76 +3421,75 @@ const DEFAULT_COMPONENT_ID = '1';
expect(getLog().length).toEqual(0); expect(getLog().length).toEqual(0);
}); });
fixmeIvy('unknown').it( it('should respect parent/sub animations when the respective area in the DOM is disabled',
'should respect parent/sub animations when the respective area in the DOM is disabled', fakeAsync(() => {
fakeAsync(() => { @Component({
@Component({ selector: 'parent-cmp',
selector: 'parent-cmp', animations: [
animations: [ trigger(
trigger( 'parent',
'parent', [
[ transition(
transition( '* => empty',
'* => empty', [
[ style({opacity: 0}),
style({opacity: 0}), query(
query( '@child',
'@child', [
[ animateChild(),
animateChild(), ]),
]), animate('1s', style({opacity: 1})),
animate('1s', style({opacity: 1})), ]),
]), ]),
]), trigger(
trigger( 'child',
'child', [
[ transition(
transition( ':leave',
':leave', [
[ animate('1s', style({opacity: 0})),
animate('1s', style({opacity: 0})), ]),
]), ]),
]), ],
], template: `
template: `
<div [@.disabled]="disableExp" #container> <div [@.disabled]="disableExp" #container>
<div [@parent]="exp" (@parent.done)="onDone($event)"> <div [@parent]="exp" (@parent.done)="onDone($event)">
<div class="item" *ngFor="let item of items" @child (@child.done)="onDone($event)"></div> <div class="item" *ngFor="let item of items" @child (@child.done)="onDone($event)"></div>
</div> </div>
</div> </div>
` `
}) })
class Cmp { class Cmp {
@ViewChild('container') public container: any; @ViewChild('container') public container: any;
disableExp = false; disableExp = false;
exp = ''; exp = '';
items: any[] = []; items: any[] = [];
doneLog: any[] = []; doneLog: any[] = [];
onDone(event: any) { this.doneLog.push(event); } onDone(event: any) { this.doneLog.push(event); }
} }
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;
cmp.disableExp = true; cmp.disableExp = true;
cmp.items = [0, 1, 2, 3, 4]; cmp.items = [0, 1, 2, 3, 4];
fixture.detectChanges(); fixture.detectChanges();
flushMicrotasks(); flushMicrotasks();
cmp.exp = 'empty'; cmp.exp = 'empty';
cmp.items = []; cmp.items = [];
cmp.doneLog = []; cmp.doneLog = [];
fixture.detectChanges(); fixture.detectChanges();
flushMicrotasks(); flushMicrotasks();
const elms = cmp.container.nativeElement.querySelectorAll('.item'); const elms = cmp.container.nativeElement.querySelectorAll('.item');
expect(elms.length).toEqual(0); expect(elms.length).toEqual(0);
expect(cmp.doneLog.length).toEqual(6); expect(cmp.doneLog.length).toEqual(6);
})); }));
}); });
}); });
@ -3759,20 +3750,19 @@ const DEFAULT_COMPONENT_ID = '1';
'Found the synthetic property @myAnimation. Please include either "BrowserAnimationsModule" or "NoopAnimationsModule" in your application.'); 'Found the synthetic property @myAnimation. Please include either "BrowserAnimationsModule" or "NoopAnimationsModule" in your application.');
}); });
fixmeIvy('unknown').it( it('should throw when using an @prop listener without the animation module', () => {
'should throw when using an @prop listener without the animation module', () => { @Component({template: `<div (@myAnimation.start)="a = true"></div>`})
@Component({template: `<div (@myAnimation.start)="a = true"></div>`}) class Cmp {
class Cmp { a: any;
a: any; }
}
TestBed.configureTestingModule({declarations: [Cmp]}); TestBed.configureTestingModule({declarations: [Cmp]});
expect(() => TestBed.createComponent(Cmp)) expect(() => TestBed.createComponent(Cmp))
.toThrowError( .toThrowError(
'Found the synthetic listener @myAnimation.start. Please include either "BrowserAnimationsModule" or "NoopAnimationsModule" in your application.'); 'Found the synthetic listener @myAnimation.start. Please include either "BrowserAnimationsModule" or "NoopAnimationsModule" in your application.');
}); });
}); });
}); });
})(); })();

View File

@ -2635,59 +2635,58 @@ import {HostListener} from '../../src/metadata/directives';
expect(p3.element.classList.contains('page2')).toBe(true); expect(p3.element.classList.contains('page2')).toBe(true);
}); });
fixmeIvy('unknown').it( it('should emulate leave animation callbacks for all sub elements that have leave triggers within the component',
'should emulate leave animation callbacks for all sub elements that have leave triggers within the component', fakeAsync(() => {
fakeAsync(() => { @Component({
@Component({ selector: 'ani-cmp',
selector: 'ani-cmp', animations: [
animations: [ trigger('parent', []), trigger('child', []),
trigger('parent', []), trigger('child', []), trigger(
trigger( 'childWithAnimation',
'childWithAnimation', [
[ transition(
transition( ':leave',
':leave', [
[ animate(1000, style({background: 'red'})),
animate(1000, style({background: 'red'})), ]),
]), ])
]) ],
], template: `
template: `
<div data-name="p" class="parent" @parent *ngIf="exp" (@parent.start)="callback($event)" (@parent.done)="callback($event)"> <div data-name="p" class="parent" @parent *ngIf="exp" (@parent.start)="callback($event)" (@parent.done)="callback($event)">
<div data-name="c1" @child (@child.start)="callback($event)" (@child.done)="callback($event)"></div> <div data-name="c1" @child (@child.start)="callback($event)" (@child.done)="callback($event)"></div>
<div data-name="c2" @child (@child.start)="callback($event)" (@child.done)="callback($event)"></div> <div data-name="c2" @child (@child.start)="callback($event)" (@child.done)="callback($event)"></div>
<div data-name="c3" @childWithAnimation (@childWithAnimation.start)="callback($event)" (@childWithAnimation.done)="callback($event)"></div> <div data-name="c3" @childWithAnimation (@childWithAnimation.start)="callback($event)" (@childWithAnimation.done)="callback($event)"></div>
</div> </div>
` `
}) })
class Cmp { class Cmp {
// TODO(issue/24571): remove '!'. // TODO(issue/24571): remove '!'.
public exp !: boolean; public exp !: boolean;
public log: string[] = []; public log: string[] = [];
callback(event: any) { callback(event: any) {
this.log.push(event.element.getAttribute('data-name') + '-' + event.phaseName); this.log.push(event.element.getAttribute('data-name') + '-' + event.phaseName);
} }
} }
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;
cmp.exp = true; cmp.exp = true;
fixture.detectChanges(); fixture.detectChanges();
flushMicrotasks(); flushMicrotasks();
cmp.log = []; cmp.log = [];
cmp.exp = false; cmp.exp = false;
fixture.detectChanges(); fixture.detectChanges();
flushMicrotasks(); flushMicrotasks();
expect(cmp.log).toEqual([ expect(cmp.log).toEqual([
'c1-start', 'c1-done', 'c2-start', 'c2-done', 'p-start', 'c3-start', 'c3-done', 'c1-start', 'c1-done', 'c2-start', 'c2-done', 'p-start', 'c3-start', 'c3-done',
'p-done' 'p-done'
]); ]);
})); }));
it('should build, but not run sub triggers when a parent animation is scheduled', () => { it('should build, but not run sub triggers when a parent animation is scheduled', () => {
@Component({ @Component({
@ -2737,24 +2736,23 @@ import {HostListener} from '../../src/metadata/directives';
expect(engine.players[0].getRealPlayer()).toBe(players[1]); expect(engine.players[0].getRealPlayer()).toBe(players[1]);
}); });
fixmeIvy('unknown').it( it('should fire and synchronize the start/done callbacks on sub triggers even if they are not allowed to animate within the animation',
'should fire and synchronize the start/done callbacks on sub triggers even if they are not allowed to animate within the animation', fakeAsync(() => {
fakeAsync(() => { @Component({
@Component({ selector: 'parent-cmp',
selector: 'parent-cmp', animations: [
animations: [ trigger(
trigger( 'parent',
'parent', [
[ transition(
transition( '* => go',
'* => go', [
[ style({height: '0px'}),
style({height: '0px'}), animate(1000, style({height: '100px'})),
animate(1000, style({height: '100px'})), ]),
]), ]),
]), ],
], template: `
template: `
<div *ngIf="!remove" <div *ngIf="!remove"
[@parent]="exp" [@parent]="exp"
(@parent.start)="track($event)" (@parent.start)="track($event)"
@ -2762,172 +2760,171 @@ import {HostListener} from '../../src/metadata/directives';
<child-cmp #child></child-cmp> <child-cmp #child></child-cmp>
</div> </div>
` `
}) })
class ParentCmp { class ParentCmp {
@ViewChild('child') public childCmp: any; @ViewChild('child') public childCmp: any;
public exp: any; public exp: any;
public log: string[] = []; public log: string[] = [];
public remove = false; public remove = false;
track(event: any) { this.log.push(`${event.triggerName}-${event.phaseName}`); } track(event: any) { this.log.push(`${event.triggerName}-${event.phaseName}`); }
} }
@Component({ @Component({
selector: 'child-cmp', selector: 'child-cmp',
animations: [ animations: [
trigger( trigger(
'child', 'child',
[ [
transition( transition(
'* => go', '* => go',
[ [
style({width: '0px'}), style({width: '0px'}),
animate(1000, style({width: '100px'})), animate(1000, style({width: '100px'})),
]), ]),
]), ]),
], ],
template: ` template: `
<div [@child]="exp" <div [@child]="exp"
(@child.start)="track($event)" (@child.start)="track($event)"
(@child.done)="track($event)"></div> (@child.done)="track($event)"></div>
` `
}) })
class ChildCmp { class ChildCmp {
public exp: any; public exp: any;
public log: string[] = []; public log: string[] = [];
track(event: any) { this.log.push(`${event.triggerName}-${event.phaseName}`); } track(event: any) { this.log.push(`${event.triggerName}-${event.phaseName}`); }
} }
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);
fixture.detectChanges(); fixture.detectChanges();
flushMicrotasks(); flushMicrotasks();
const cmp = fixture.componentInstance; const cmp = fixture.componentInstance;
const child = cmp.childCmp; const child = cmp.childCmp;
expect(cmp.log).toEqual(['parent-start', 'parent-done']); expect(cmp.log).toEqual(['parent-start', 'parent-done']);
expect(child.log).toEqual(['child-start', 'child-done']); expect(child.log).toEqual(['child-start', 'child-done']);
cmp.log = []; cmp.log = [];
child.log = []; child.log = [];
cmp.exp = 'go'; cmp.exp = 'go';
cmp.childCmp.exp = 'go'; cmp.childCmp.exp = 'go';
fixture.detectChanges(); fixture.detectChanges();
flushMicrotasks(); flushMicrotasks();
expect(cmp.log).toEqual(['parent-start']); expect(cmp.log).toEqual(['parent-start']);
expect(child.log).toEqual(['child-start']); expect(child.log).toEqual(['child-start']);
const players = engine.players; const players = engine.players;
expect(players.length).toEqual(1); expect(players.length).toEqual(1);
players[0].finish(); players[0].finish();
expect(cmp.log).toEqual(['parent-start', 'parent-done']); expect(cmp.log).toEqual(['parent-start', 'parent-done']);
expect(child.log).toEqual(['child-start', 'child-done']); expect(child.log).toEqual(['child-start', 'child-done']);
cmp.log = []; cmp.log = [];
child.log = []; child.log = [];
cmp.remove = true; cmp.remove = true;
fixture.detectChanges(); fixture.detectChanges();
flushMicrotasks(); flushMicrotasks();
expect(cmp.log).toEqual(['parent-start', 'parent-done']); expect(cmp.log).toEqual(['parent-start', 'parent-done']);
expect(child.log).toEqual(['child-start', 'child-done']); expect(child.log).toEqual(['child-start', 'child-done']);
})); }));
fixmeIvy('unknown').it( it('should fire and synchronize the start/done callbacks on multiple blocked sub triggers',
'should fire and synchronize the start/done callbacks on multiple blocked sub triggers', fakeAsync(() => {
fakeAsync(() => { @Component({
@Component({ selector: 'cmp',
selector: 'cmp', animations: [
animations: [ trigger(
trigger( 'parent1',
'parent1', [
[ transition(
transition( '* => go, * => go-again',
'* => go, * => go-again', [
[ style({opacity: 0}),
style({opacity: 0}), animate('1s', style({opacity: 1})),
animate('1s', style({opacity: 1})), ]),
]), ]),
]), trigger(
trigger( 'parent2',
'parent2', [
[ transition(
transition( '* => go, * => go-again',
'* => go, * => go-again', [
[ style({lineHeight: '0px'}),
style({lineHeight: '0px'}), animate('1s', style({lineHeight: '10px'})),
animate('1s', style({lineHeight: '10px'})), ]),
]), ]),
]), trigger(
trigger( 'child1',
'child1', [
[ transition(
transition( '* => go, * => go-again',
'* => go, * => go-again', [
[ style({width: '0px'}),
style({width: '0px'}), animate('1s', style({width: '100px'})),
animate('1s', style({width: '100px'})), ]),
]), ]),
]), trigger(
trigger( 'child2',
'child2', [
[ transition(
transition( '* => go, * => go-again',
'* => go, * => go-again', [
[ style({height: '0px'}),
style({height: '0px'}), animate('1s', style({height: '100px'})),
animate('1s', style({height: '100px'})), ]),
]), ]),
]), ],
], template: `
template: `
<div [@parent1]="parent1Exp" (@parent1.start)="track($event)" <div [@parent1]="parent1Exp" (@parent1.start)="track($event)"
[@parent2]="parent2Exp" (@parent2.start)="track($event)"> [@parent2]="parent2Exp" (@parent2.start)="track($event)">
<div [@child1]="child1Exp" (@child1.start)="track($event)" <div [@child1]="child1Exp" (@child1.start)="track($event)"
[@child2]="child2Exp" (@child2.start)="track($event)"></div> [@child2]="child2Exp" (@child2.start)="track($event)"></div>
</div> </div>
` `
}) })
class Cmp { class Cmp {
public parent1Exp = ''; public parent1Exp = '';
public parent2Exp = ''; public parent2Exp = '';
public child1Exp = ''; public child1Exp = '';
public child2Exp = ''; public child2Exp = '';
public log: string[] = []; public log: string[] = [];
track(event: any) { this.log.push(`${event.triggerName}-${event.phaseName}`); } track(event: any) { this.log.push(`${event.triggerName}-${event.phaseName}`); }
} }
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);
fixture.detectChanges(); fixture.detectChanges();
flushMicrotasks(); flushMicrotasks();
const cmp = fixture.componentInstance; const cmp = fixture.componentInstance;
cmp.log = []; cmp.log = [];
cmp.parent1Exp = 'go'; cmp.parent1Exp = 'go';
cmp.parent2Exp = 'go'; cmp.parent2Exp = 'go';
cmp.child1Exp = 'go'; cmp.child1Exp = 'go';
cmp.child2Exp = 'go'; cmp.child2Exp = 'go';
fixture.detectChanges(); fixture.detectChanges();
flushMicrotasks(); flushMicrotasks();
expect(cmp.log).toEqual( expect(cmp.log).toEqual(
['parent1-start', 'parent2-start', 'child1-start', 'child2-start']); ['parent1-start', 'parent2-start', 'child1-start', 'child2-start']);
cmp.parent1Exp = 'go-again'; cmp.parent1Exp = 'go-again';
cmp.parent2Exp = 'go-again'; cmp.parent2Exp = 'go-again';
cmp.child1Exp = 'go-again'; cmp.child1Exp = 'go-again';
cmp.child2Exp = 'go-again'; cmp.child2Exp = 'go-again';
fixture.detectChanges(); fixture.detectChanges();
flushMicrotasks(); flushMicrotasks();
})); }));
it('should stretch the starting keyframe of a child animation queries are issued by the parent', it('should stretch the starting keyframe of a child animation queries are issued by the parent',
() => { () => {

View File

@ -78,8 +78,6 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
} }
describe(`ChangeDetection`, () => { describe(`ChangeDetection`, () => {
// On CJS fakeAsync is not supported...
if (!getDOM().supportsDOMEvents()) return;
beforeEach(() => { beforeEach(() => {
TestBed.configureCompiler({providers: TEST_COMPILER_PROVIDERS}); TestBed.configureCompiler({providers: TEST_COMPILER_PROVIDERS});
@ -1211,16 +1209,16 @@ const TEST_COMPILER_PROVIDERS: Provider[] = [
}); });
describe('mode', () => { describe('mode', () => {
fixmeIvy('unknown').it('Detached', fakeAsync(() => { it('Detached', fakeAsync(() => {
const ctx = createCompFixture('<comp-with-ref></comp-with-ref>'); const ctx = createCompFixture('<comp-with-ref></comp-with-ref>');
const cmp: CompWithRef = queryDirs(ctx.debugElement, CompWithRef)[0]; const cmp: CompWithRef = queryDirs(ctx.debugElement, CompWithRef)[0];
cmp.value = 'hello'; cmp.value = 'hello';
cmp.changeDetectorRef.detach(); cmp.changeDetectorRef.detach();
ctx.detectChanges(); ctx.detectChanges();
expect(renderLog.log).toEqual([]); expect(renderLog.log).toEqual([]);
})); }));
it('Detached should disable OnPush', fakeAsync(() => { it('Detached should disable OnPush', fakeAsync(() => {
const ctx = createCompFixture('<push-cmp [value]="value"></push-cmp>'); const ctx = createCompFixture('<push-cmp [value]="value"></push-cmp>');

View File

@ -9,7 +9,7 @@
import {ResourceLoader} from '@angular/compiler'; import {ResourceLoader} from '@angular/compiler';
import {CompileMetadataResolver} from '@angular/compiler/src/metadata_resolver'; import {CompileMetadataResolver} from '@angular/compiler/src/metadata_resolver';
import {MockResourceLoader} from '@angular/compiler/testing/src/resource_loader_mock'; import {MockResourceLoader} from '@angular/compiler/testing/src/resource_loader_mock';
import {Component, Directive, Injectable, NgModule, OnDestroy, Pipe, Type} from '@angular/core'; import {Component, Directive, Injectable, NgModule, OnDestroy, Pipe} from '@angular/core';
import {TestBed, async, getTestBed} from '@angular/core/testing'; import {TestBed, async, getTestBed} from '@angular/core/testing';
import {expect} from '@angular/platform-browser/testing/src/matchers'; import {expect} from '@angular/platform-browser/testing/src/matchers';
import {fixmeIvy} from '@angular/private/testing'; import {fixmeIvy} from '@angular/private/testing';