Skip to content

Commit 6557bc3

Browse files
matskovicb
authored andcommitted
fix(animations): throw errors and normalize offset beyond the range of [0,1]
Closes #13348 Closes #13440
1 parent e2622ad commit 6557bc3

File tree

4 files changed

+76
-1
lines changed

4 files changed

+76
-1
lines changed

modules/@angular/compiler/src/animation/animation_parser.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,11 @@ function _normalizeStyleMetadata(
174174
entry: CompileAnimationStyleMetadata, stateStyles: {[key: string]: AnimationStylesAst},
175175
schema: ElementSchemaRegistry, errors: AnimationParseError[],
176176
permitStateReferences: boolean): {[key: string]: string | number}[] {
177+
const offset = entry.offset;
178+
if (offset > 1 || offset < 0) {
179+
errors.push(new AnimationParseError(`Offset values for animations must be between 0 and 1`));
180+
}
181+
177182
const normalizedStyles: {[key: string]: string | number}[] = [];
178183
entry.styles.forEach(styleEntry => {
179184
if (typeof styleEntry === 'string') {

modules/@angular/core/test/animation/animation_integration_spec.ts

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,60 @@ function declareTests({useJit}: {useJit: boolean}) {
156156
expect(kf[1]).toEqual([1, {'backgroundColor': 'blue'}]);
157157
}));
158158

159+
it('should throw an error when a provided offset for an animation step if an offset value is greater than 1',
160+
fakeAsync(() => {
161+
TestBed.overrideComponent(DummyIfCmp, {
162+
set: {
163+
template: `
164+
<div *ngIf="exp" [@tooBig]="exp"></div>
165+
`,
166+
animations: [trigger(
167+
'tooBig',
168+
[transition(
169+
'* => *', [animate('444ms', style({'opacity': '1', offset: 1.1}))])])]
170+
}
171+
});
172+
173+
let message = '';
174+
try {
175+
const fixture = TestBed.createComponent(DummyIfCmp);
176+
} catch (e) {
177+
message = e.message;
178+
}
179+
180+
const lines = message.split(/\n+/);
181+
expect(lines[1]).toMatch(
182+
/Unable to parse the animation sequence for "tooBig" on the DummyIfCmp component due to the following errors:/);
183+
expect(lines[2]).toMatch(/Offset values for animations must be between 0 and 1/);
184+
}));
185+
186+
it('should throw an error when a provided offset for an animation step if an offset value is less than 0',
187+
fakeAsync(() => {
188+
TestBed.overrideComponent(DummyIfCmp, {
189+
set: {
190+
template: `
191+
<div *ngIf="exp" [@tooSmall]="exp"></div>
192+
`,
193+
animations: [trigger(
194+
'tooSmall',
195+
[transition(
196+
'* => *', [animate('444ms', style({'opacity': '0', offset: -1}))])])]
197+
}
198+
});
199+
200+
let message = '';
201+
try {
202+
const fixture = TestBed.createComponent(DummyIfCmp);
203+
} catch (e) {
204+
message = e.message;
205+
}
206+
207+
const lines = message.split(/\n+/);
208+
expect(lines[1]).toMatch(
209+
/Unable to parse the animation sequence for "tooSmall" on the DummyIfCmp component due to the following errors:/);
210+
expect(lines[2]).toMatch(/Offset values for animations must be between 0 and 1/);
211+
}));
212+
159213
describe('animation aliases', () => {
160214
it('should animate the ":enter" animation alias as "void => *"', fakeAsync(() => {
161215
TestBed.overrideComponent(DummyIfCmp, {

modules/@angular/platform-browser/src/dom/web_animations_driver.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ export class WebAnimationsDriver implements AnimationDriver {
2828

2929
keyframes.forEach((keyframe: AnimationKeyframe) => {
3030
const data = _populateStyles(keyframe.styles, startingStyleLookup);
31-
data['offset'] = keyframe.offset;
31+
data['offset'] = Math.max(0, Math.min(1, keyframe.offset));
3232
formattedSteps.push(data);
3333
});
3434

modules/@angular/platform-browser/test/dom/web_animations_driver_spec.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,22 @@ export function main() {
8585
elm, startingStyles, styles, 1000, 1000, null, <AnimationPlayer[]>previousPlayers);
8686
expect(player.previousStyles).toEqual({});
8787
});
88+
89+
it('should round down offset values that are bigger than 1', () => {
90+
const startingStyles = _makeStyles({});
91+
const styles = [_makeKeyframe(0, {}), _makeKeyframe(2, {})];
92+
const player = driver.animate(elm, startingStyles, styles, 1000, 1000, null);
93+
expect(player.keyframes.pop()['offset']).toEqual(1);
94+
});
95+
96+
it('should round down offset values that are bigger less than 0', () => {
97+
const startingStyles = _makeStyles({});
98+
const styles = [_makeKeyframe(-99, {}), _makeKeyframe(-0.1, {}), _makeKeyframe(1, {})];
99+
const player = driver.animate(elm, startingStyles, styles, 1000, 1000, null);
100+
player.keyframes.pop(); // remove the final keyframe that is `1`
101+
const allZero = player.keyframes.every(kf => kf['offset'] == 0);
102+
expect(allZero).toBe(true);
103+
});
88104
});
89105
}
90106

0 commit comments

Comments
 (0)