refactor(animations): make animation testing work with fixture.whenRenderingDone
This commit is contained in:
parent
8a6eb1ac78
commit
54a6e4ff9e
|
@ -92,4 +92,6 @@ export class AnimationEngine {
|
|||
return (this._transitionEngine.players as AnimationPlayer[])
|
||||
.concat(this._timelineEngine.players as AnimationPlayer[]);
|
||||
}
|
||||
|
||||
whenRenderingDone(): Promise<any> { return this._transitionEngine.whenRenderingDone(); }
|
||||
}
|
||||
|
|
|
@ -617,6 +617,16 @@ export class TransitionAnimationEngine {
|
|||
});
|
||||
}
|
||||
|
||||
whenRenderingDone(): Promise<any> {
|
||||
return new Promise(resolve => {
|
||||
if (this.players.length) {
|
||||
return optimizeGroupPlayer(this.players).onDone(() => resolve());
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
flush() {
|
||||
let players: AnimationPlayer[] = [];
|
||||
if (this.newHostElements.size) {
|
||||
|
|
|
@ -130,6 +130,7 @@ export abstract class RendererFactory2 {
|
|||
abstract createRenderer(hostElement: any, type: RendererType2|null): Renderer2;
|
||||
abstract begin?(): void;
|
||||
abstract end?(): void;
|
||||
abstract whenRenderingDone?(): Promise<any>;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -607,6 +607,13 @@ class DebugRendererFactory2 implements RendererFactory2 {
|
|||
this.delegate.end();
|
||||
}
|
||||
}
|
||||
|
||||
whenRenderingDone(): Promise<any> {
|
||||
if (this.delegate.whenRenderingDone) {
|
||||
return this.delegate.whenRenderingDone();
|
||||
}
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -37,6 +37,116 @@ export function main() {
|
|||
});
|
||||
});
|
||||
|
||||
describe('component fixture integration', () => {
|
||||
describe('whenRenderingDone', () => {
|
||||
it('should wait until the animations are finished until continuing', fakeAsync(() => {
|
||||
@Component({
|
||||
selector: 'cmp',
|
||||
template: `
|
||||
<div [@myAnimation]="exp"></div>
|
||||
`,
|
||||
animations: [trigger(
|
||||
'myAnimation', [transition('* => on', [animate(1000, style({opacity: 1}))])])]
|
||||
})
|
||||
class Cmp {
|
||||
exp: any = false;
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({declarations: [Cmp]});
|
||||
const engine = TestBed.get(ɵAnimationEngine);
|
||||
const fixture = TestBed.createComponent(Cmp);
|
||||
const cmp = fixture.componentInstance;
|
||||
|
||||
let isDone = false;
|
||||
fixture.whenRenderingDone().then(() => isDone = true);
|
||||
expect(isDone).toBe(false);
|
||||
|
||||
cmp.exp = 'on';
|
||||
fixture.detectChanges();
|
||||
engine.flush();
|
||||
expect(isDone).toBe(false);
|
||||
|
||||
const players = engine.players;
|
||||
expect(players.length).toEqual(1);
|
||||
players[0].finish();
|
||||
expect(isDone).toBe(false);
|
||||
|
||||
flushMicrotasks();
|
||||
expect(isDone).toBe(true);
|
||||
}));
|
||||
|
||||
it('should wait for a noop animation to finish before continuing', fakeAsync(() => {
|
||||
@Component({
|
||||
selector: 'cmp',
|
||||
template: `
|
||||
<div [@myAnimation]="exp"></div>
|
||||
`,
|
||||
animations: [trigger(
|
||||
'myAnimation', [transition('* => on', [animate(1000, style({opacity: 1}))])])]
|
||||
})
|
||||
class Cmp {
|
||||
exp: any = false;
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
providers: [{provide: AnimationDriver, useClass: ɵNoopAnimationDriver}],
|
||||
declarations: [Cmp]
|
||||
});
|
||||
|
||||
const engine = TestBed.get(ɵAnimationEngine);
|
||||
const fixture = TestBed.createComponent(Cmp);
|
||||
const cmp = fixture.componentInstance;
|
||||
|
||||
let isDone = false;
|
||||
fixture.whenRenderingDone().then(() => isDone = true);
|
||||
expect(isDone).toBe(false);
|
||||
|
||||
cmp.exp = 'off';
|
||||
fixture.detectChanges();
|
||||
engine.flush();
|
||||
expect(isDone).toBe(false);
|
||||
|
||||
flushMicrotasks();
|
||||
expect(isDone).toBe(true);
|
||||
}));
|
||||
|
||||
it('should wait for active animations to finish even if they have already started',
|
||||
fakeAsync(() => {
|
||||
@Component({
|
||||
selector: 'cmp',
|
||||
template: `
|
||||
<div [@myAnimation]="exp"></div>
|
||||
`,
|
||||
animations: [trigger(
|
||||
'myAnimation', [transition('* => on', [animate(1000, style({opacity: 1}))])])]
|
||||
})
|
||||
class Cmp {
|
||||
exp: any = false;
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({declarations: [Cmp]});
|
||||
const engine = TestBed.get(ɵAnimationEngine);
|
||||
const fixture = TestBed.createComponent(Cmp);
|
||||
const cmp = fixture.componentInstance;
|
||||
cmp.exp = 'on';
|
||||
fixture.detectChanges();
|
||||
engine.flush();
|
||||
|
||||
const players = engine.players;
|
||||
expect(players.length).toEqual(1);
|
||||
|
||||
let isDone = false;
|
||||
fixture.whenRenderingDone().then(() => isDone = true);
|
||||
flushMicrotasks();
|
||||
expect(isDone).toBe(false);
|
||||
|
||||
players[0].finish();
|
||||
flushMicrotasks();
|
||||
expect(isDone).toBe(true);
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
describe('animation triggers', () => {
|
||||
it('should trigger a state change animation from void => state', () => {
|
||||
@Component({
|
||||
|
|
|
@ -158,25 +158,6 @@ export function main() {
|
|||
});
|
||||
}));
|
||||
|
||||
it('should signal through whenRenderingDone when the fixture is stable', async(() => {
|
||||
const componentFixture = TestBed.createComponent(AsyncComp);
|
||||
|
||||
componentFixture.detectChanges();
|
||||
expect(componentFixture.nativeElement).toHaveText('1');
|
||||
|
||||
const element = componentFixture.debugElement.children[0];
|
||||
dispatchEvent(element.nativeElement, 'click');
|
||||
expect(componentFixture.nativeElement).toHaveText('1');
|
||||
|
||||
// Component is updated asynchronously. Wait for the fixture to become stable
|
||||
// before checking.
|
||||
componentFixture.whenRenderingDone().then((waited) => {
|
||||
expect(waited).toBe(true);
|
||||
componentFixture.detectChanges();
|
||||
expect(componentFixture.nativeElement).toHaveText('11');
|
||||
});
|
||||
}));
|
||||
|
||||
it('should wait for macroTask(setTimeout) while checking for whenStable ' +
|
||||
'(autoDetectChanges)',
|
||||
async(() => {
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {ChangeDetectorRef, ComponentRef, DebugElement, ElementRef, NgZone, getDebugNode} from '@angular/core';
|
||||
import {ChangeDetectorRef, ComponentRef, DebugElement, ElementRef, NgZone, RendererFactory2, getDebugNode} from '@angular/core';
|
||||
|
||||
|
||||
/**
|
||||
|
@ -40,6 +40,7 @@ export class ComponentFixture<T> {
|
|||
*/
|
||||
changeDetectorRef: ChangeDetectorRef;
|
||||
|
||||
private _renderer: RendererFactory2|null|undefined;
|
||||
private _isStable: boolean = true;
|
||||
private _isDestroyed: boolean = false;
|
||||
private _resolve: ((result: any) => void)|null = null;
|
||||
|
@ -160,11 +161,22 @@ export class ComponentFixture<T> {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
private _getRenderer() {
|
||||
if (this._renderer === undefined) {
|
||||
this._renderer = this.componentRef.injector.get(RendererFactory2, null);
|
||||
}
|
||||
return this._renderer as RendererFactory2 | null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a promise that resolves when the ui state is stable following animations.
|
||||
*/
|
||||
* Get a promise that resolves when the ui state is stable following animations.
|
||||
*/
|
||||
whenRenderingDone(): Promise<any> {
|
||||
// this is temporary until this is functional
|
||||
const renderer = this._getRenderer();
|
||||
if (renderer && renderer.whenRenderingDone) {
|
||||
return renderer.whenRenderingDone();
|
||||
}
|
||||
return this.whenStable();
|
||||
}
|
||||
|
||||
|
|
|
@ -53,6 +53,8 @@ export class AnimationRendererFactory implements RendererFactory2 {
|
|||
this.delegate.end();
|
||||
}
|
||||
}
|
||||
|
||||
whenRenderingDone(): Promise<any> { return this._engine.whenRenderingDone(); }
|
||||
}
|
||||
|
||||
export class AnimationRenderer implements Renderer2 {
|
||||
|
|
|
@ -846,6 +846,7 @@ export declare abstract class RendererFactory2 {
|
|||
abstract begin?(): void;
|
||||
abstract createRenderer(hostElement: any, type: RendererType2 | null): Renderer2;
|
||||
abstract end?(): void;
|
||||
abstract whenRenderingDone?(): Promise<any>;
|
||||
}
|
||||
|
||||
/** @experimental */
|
||||
|
|
Loading…
Reference in New Issue