fix(animations): always recover from a failed animation step (#13604)
This commit is contained in:
parent
eb2ceff4ba
commit
842f52e841
|
@ -17,13 +17,11 @@ import {WebAnimationsDriver} from '@angular/platform-browser/src/dom/web_animati
|
||||||
import {WebAnimationsPlayer} from '@angular/platform-browser/src/dom/web_animations_player';
|
import {WebAnimationsPlayer} from '@angular/platform-browser/src/dom/web_animations_player';
|
||||||
import {expect} from '@angular/platform-browser/testing/matchers';
|
import {expect} from '@angular/platform-browser/testing/matchers';
|
||||||
import {MockAnimationDriver} from '@angular/platform-browser/testing/mock_animation_driver';
|
import {MockAnimationDriver} from '@angular/platform-browser/testing/mock_animation_driver';
|
||||||
|
|
||||||
import {DomAnimatePlayer} from '../../../platform-browser/src/dom/dom_animate_player';
|
|
||||||
import {ApplicationRef, Component, HostBinding, HostListener, NgModule, NgZone, destroyPlatform} from '../../index';
|
import {ApplicationRef, Component, HostBinding, HostListener, NgModule, NgZone, destroyPlatform} from '../../index';
|
||||||
import {DEFAULT_STATE} from '../../src/animation/animation_constants';
|
import {DEFAULT_STATE} from '../../src/animation/animation_constants';
|
||||||
import {AnimationGroupPlayer} from '../../src/animation/animation_group_player';
|
import {AnimationGroupPlayer} from '../../src/animation/animation_group_player';
|
||||||
import {AnimationKeyframe} from '../../src/animation/animation_keyframe';
|
import {AnimationKeyframe} from '../../src/animation/animation_keyframe';
|
||||||
import {AnimationPlayer} from '../../src/animation/animation_player';
|
import {AnimationPlayer, NoOpAnimationPlayer} from '../../src/animation/animation_player';
|
||||||
import {AnimationStyles} from '../../src/animation/animation_styles';
|
import {AnimationStyles} from '../../src/animation/animation_styles';
|
||||||
import {AnimationTransitionEvent} from '../../src/animation/animation_transition_event';
|
import {AnimationTransitionEvent} from '../../src/animation/animation_transition_event';
|
||||||
import {AUTO_STYLE, animate, group, keyframes, sequence, state, style, transition, trigger} from '../../src/animation/metadata';
|
import {AUTO_STYLE, animate, group, keyframes, sequence, state, style, transition, trigger} from '../../src/animation/metadata';
|
||||||
|
@ -2244,6 +2242,42 @@ function declareTests({useJit}: {useJit: boolean}) {
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('error handling', () => {
|
||||||
|
it('should recover if an animation driver or player throws an error during an animation',
|
||||||
|
fakeAsync(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
declarations: [DummyIfCmp],
|
||||||
|
providers: [{provide: AnimationDriver, useClass: ErroneousAnimationDriver}],
|
||||||
|
imports: [CommonModule]
|
||||||
|
});
|
||||||
|
TestBed.overrideComponent(DummyIfCmp, {
|
||||||
|
set: {
|
||||||
|
template: `
|
||||||
|
<div [@myAnimation]="exp" (@myAnimation.start)="callback1($event)" (@myAnimation.done)="callback2($event)"></div>
|
||||||
|
`,
|
||||||
|
animations: [trigger('myAnimation', [transition(
|
||||||
|
'* => *',
|
||||||
|
[
|
||||||
|
animate(1000, style({transform: 'noooooo'})),
|
||||||
|
])])]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const fixture = TestBed.createComponent(DummyIfCmp);
|
||||||
|
const cmp = fixture.componentInstance;
|
||||||
|
let started = false;
|
||||||
|
let done = false;
|
||||||
|
cmp.callback1 = (event: AnimationTransitionEvent) => started = true;
|
||||||
|
cmp.callback2 = (event: AnimationTransitionEvent) => done = true;
|
||||||
|
cmp.exp = true;
|
||||||
|
fixture.detectChanges();
|
||||||
|
flushMicrotasks();
|
||||||
|
|
||||||
|
expect(started).toBe(true);
|
||||||
|
expect(done).toBe(true);
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
describe('full animation integration tests', () => {
|
describe('full animation integration tests', () => {
|
||||||
if (!getDOM().supportsWebAnimation()) return;
|
if (!getDOM().supportsWebAnimation()) return;
|
||||||
|
|
||||||
|
@ -2537,3 +2571,11 @@ class ExtendedWebAnimationsDriver extends WebAnimationsDriver {
|
||||||
return player;
|
return player;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ErroneousAnimationDriver extends MockAnimationDriver {
|
||||||
|
animate(
|
||||||
|
element: any, startingStyles: AnimationStyles, keyframes: AnimationKeyframe[],
|
||||||
|
duration: number, delay: number, easing: string): WebAnimationsPlayer {
|
||||||
|
throw new Error();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
import {APP_ID, Inject, Injectable, RenderComponentType, Renderer, RootRenderer, ViewEncapsulation} from '@angular/core';
|
import {APP_ID, Inject, Injectable, RenderComponentType, Renderer, RootRenderer, ViewEncapsulation} from '@angular/core';
|
||||||
|
|
||||||
import {isBlank, isPresent, stringify} from '../facade/lang';
|
import {isBlank, isPresent, stringify} from '../facade/lang';
|
||||||
import {AnimationKeyframe, AnimationPlayer, AnimationStyles, DirectRenderer, RenderDebugInfo} from '../private_import_core';
|
import {AnimationKeyframe, AnimationPlayer, AnimationStyles, DirectRenderer, NoOpAnimationPlayer, RenderDebugInfo} from '../private_import_core';
|
||||||
|
|
||||||
import {AnimationDriver} from './animation_driver';
|
import {AnimationDriver} from './animation_driver';
|
||||||
import {DOCUMENT} from './dom_tokens';
|
import {DOCUMENT} from './dom_tokens';
|
||||||
|
@ -262,8 +262,12 @@ export class DomRenderer implements Renderer {
|
||||||
element: any, startingStyles: AnimationStyles, keyframes: AnimationKeyframe[],
|
element: any, startingStyles: AnimationStyles, keyframes: AnimationKeyframe[],
|
||||||
duration: number, delay: number, easing: string,
|
duration: number, delay: number, easing: string,
|
||||||
previousPlayers: AnimationPlayer[] = []): AnimationPlayer {
|
previousPlayers: AnimationPlayer[] = []): AnimationPlayer {
|
||||||
return this._animationDriver.animate(
|
try {
|
||||||
element, startingStyles, keyframes, duration, delay, easing, previousPlayers);
|
return this._animationDriver.animate(
|
||||||
|
element, startingStyles, keyframes, duration, delay, easing, previousPlayers);
|
||||||
|
} catch (e) {
|
||||||
|
return new NoOpAnimationPlayer();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,3 +21,5 @@ export type RenderDebugInfo = typeof r._RenderDebugInfo;
|
||||||
export var RenderDebugInfo: typeof r.RenderDebugInfo = r.RenderDebugInfo;
|
export var RenderDebugInfo: typeof r.RenderDebugInfo = r.RenderDebugInfo;
|
||||||
export type DebugDomRootRenderer = typeof r._DebugDomRootRenderer;
|
export type DebugDomRootRenderer = typeof r._DebugDomRootRenderer;
|
||||||
export var DebugDomRootRenderer: typeof r.DebugDomRootRenderer = r.DebugDomRootRenderer;
|
export var DebugDomRootRenderer: typeof r.DebugDomRootRenderer = r.DebugDomRootRenderer;
|
||||||
|
export type NoOpAnimationPlayer = typeof r._NoOpAnimationPlayer;
|
||||||
|
export var NoOpAnimationPlayer: typeof r.NoOpAnimationPlayer = r.NoOpAnimationPlayer;
|
||||||
|
|
|
@ -10,7 +10,7 @@ import {APP_ID, Inject, Injectable, NgZone, RenderComponentType, Renderer, RootR
|
||||||
import {AnimationDriver, DOCUMENT} from '@angular/platform-browser';
|
import {AnimationDriver, DOCUMENT} from '@angular/platform-browser';
|
||||||
|
|
||||||
import {isBlank, isPresent, stringify} from './facade/lang';
|
import {isBlank, isPresent, stringify} from './facade/lang';
|
||||||
import {AnimationKeyframe, AnimationPlayer, AnimationStyles, RenderDebugInfo} from './private_import_core';
|
import {AnimationKeyframe, AnimationPlayer, AnimationStyles, NoOpAnimationPlayer, RenderDebugInfo} from './private_import_core';
|
||||||
import {NAMESPACE_URIS, SharedStylesHost, flattenStyles, getDOM, isNamespaced, shimContentAttribute, shimHostAttribute, splitNamespace} from './private_import_platform-browser';
|
import {NAMESPACE_URIS, SharedStylesHost, flattenStyles, getDOM, isNamespaced, shimContentAttribute, shimHostAttribute, splitNamespace} from './private_import_platform-browser';
|
||||||
|
|
||||||
const TEMPLATE_COMMENT_TEXT = 'template bindings={}';
|
const TEMPLATE_COMMENT_TEXT = 'template bindings={}';
|
||||||
|
@ -208,8 +208,12 @@ export class ServerRenderer implements Renderer {
|
||||||
element: any, startingStyles: AnimationStyles, keyframes: AnimationKeyframe[],
|
element: any, startingStyles: AnimationStyles, keyframes: AnimationKeyframe[],
|
||||||
duration: number, delay: number, easing: string,
|
duration: number, delay: number, easing: string,
|
||||||
previousPlayers: AnimationPlayer[] = []): AnimationPlayer {
|
previousPlayers: AnimationPlayer[] = []): AnimationPlayer {
|
||||||
return this._animationDriver.animate(
|
try {
|
||||||
element, startingStyles, keyframes, duration, delay, easing, previousPlayers);
|
return this._animationDriver.animate(
|
||||||
|
element, startingStyles, keyframes, duration, delay, easing, previousPlayers);
|
||||||
|
} catch (e) {
|
||||||
|
return new NoOpAnimationPlayer();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue