Bug 1398038 - Simplify keyframe test data; r?hiro draft
authorBrian Birtles <birtles@gmail.com>
Wed, 18 Oct 2017 14:12:16 +0900
changeset 683759 58d28e186b0e432d688155fdd19378c7936257fb
parent 683758 d4511953876de02c104ee65bc36320e1fa62f2d1
child 683760 73670b56f52537e3586b79d13532084cba88a497
push id85456
push userbmo:bbirtles@mozilla.com
push dateFri, 20 Oct 2017 06:31:55 +0000
reviewershiro
bugs1398038
milestone58.0a1
Bug 1398038 - Simplify keyframe test data; r?hiro Writing out the full keyframes actually makes the tests harder to read, especially when combined with an 80 character line length. By adding some very simple helper methods we can improve the readability of these tests. MozReview-Commit-ID: LxhelUrWAe8
testing/web-platform/tests/web-animations/resources/keyframe-tests.js
--- a/testing/web-platform/tests/web-animations/resources/keyframe-tests.js
+++ b/testing/web-platform/tests/web-animations/resources/keyframe-tests.js
@@ -28,463 +28,400 @@ const gBadCompositeValueTests = [
 // ------------------------------
 
 const gEmptyKeyframeListTests = [
   [],
   null,
   undefined,
 ];
 
+// Helper methods to make defining computed keyframes more readable.
+
+const offset = offset => ({
+  offset,
+  computedOffset: offset,
+});
+
+const computedOffset = computedOffset => ({
+  offset: null,
+  computedOffset,
+});
+
+const keyframe = (offset, props, easing='linear', composite) => {
+  // The object spread operator is not yet available in all browsers so we use
+  // Object.assign instead.
+  const result = {};
+  Object.assign(result, offset, props, { easing });
+  if (composite) {
+    result.composite = composite;
+  }
+  return result;
+};
+
 const gKeyframesTests = [
   {
     desc:   'a one property two value property-indexed keyframes specification',
     input:  { left: ['10px', '20px'] },
-    output: [{ offset: null, computedOffset: 0, easing: 'linear',
-               left: '10px' },
-             { offset: null, computedOffset: 1, easing: 'linear',
-               left: '20px' }],
+    output: [keyframe(computedOffset(0), { left: '10px' }),
+             keyframe(computedOffset(1), { left: '20px' })],
   },
   {
     desc:   'a one shorthand property two value property-indexed keyframes'
             + ' specification',
     input:  { margin: ['10px', '10px 20px 30px 40px'] },
-    output: [{ offset: null, computedOffset: 0, easing: 'linear',
-               margin: '10px' },
-             { offset: null, computedOffset: 1, easing: 'linear',
-               margin: '10px 20px 30px 40px' }],
+    output: [keyframe(computedOffset(0), { margin: '10px' }),
+             keyframe(computedOffset(1), { margin: '10px 20px 30px 40px' })],
   },
   {
     desc:   'a two property (one shorthand and one of its longhand components)'
             + ' two value property-indexed keyframes specification',
     input:  { marginTop: ['50px', '60px'],
               margin: ['10px', '10px 20px 30px 40px'] },
-    output: [{ offset: null, computedOffset: 0, easing: 'linear',
-               marginTop: '50px', margin: '10px' },
-             { offset: null, computedOffset: 1, easing: 'linear',
-               marginTop: '60px', margin: '10px 20px 30px 40px' }],
+    output: [keyframe(computedOffset(0),
+                      { marginTop: '50px', margin: '10px' }),
+             keyframe(computedOffset(1),
+                      { marginTop: '60px', margin: '10px 20px 30px 40px' })],
   },
   {
     desc:   'a two property two value property-indexed keyframes specification',
     input:  { left: ['10px', '20px'],
               top: ['30px', '40px'] },
-    output: [{ offset: null, computedOffset: 0, easing: 'linear',
-               left: '10px', top: '30px' },
-             { offset: null, computedOffset: 1, easing: 'linear',
-               left: '20px', top: '40px' }],
+    output: [keyframe(computedOffset(0), { left: '10px', top: '30px' }),
+             keyframe(computedOffset(1), { left: '20px', top: '40px' })],
   },
   {
     desc:   'a two property property-indexed keyframes specification with'
             + ' different numbers of values',
     input:  { left: ['10px', '20px', '30px'],
               top: ['40px', '50px'] },
-    output: [{ offset: null, computedOffset: 0.0, easing: 'linear',
-               left: '10px', top: '40px' },
-             { offset: null, computedOffset: 0.5, easing: 'linear',
-               left: '20px' },
-             { offset: null, computedOffset: 1.0, easing: 'linear',
-               left: '30px', top: '50px' }],
+    output: [keyframe(computedOffset(0),   { left: '10px', top: '40px' }),
+             keyframe(computedOffset(0.5), { left: '20px' }),
+             keyframe(computedOffset(1),   { left: '30px', top: '50px' })],
   },
   {
     desc:   'a property-indexed keyframes specification with an invalid value',
     input:  { left: ['10px', '20px', '30px', '40px', '50px'],
               top:  ['15px', '25px', 'invalid', '45px', '55px'] },
-    output: [{ offset: null, computedOffset: 0.00, easing: 'linear',
-               left: '10px', top: '15px' },
-             { offset: null, computedOffset: 0.25, easing: 'linear',
-               left: '20px', top: '25px' },
-             { offset: null, computedOffset: 0.50, easing: 'linear',
-               left: '30px' },
-             { offset: null, computedOffset: 0.75, easing: 'linear',
-               left: '40px', top: '45px' },
-             { offset: null, computedOffset: 1.00, easing: 'linear',
-               left: '50px', top: '55px' }],
+    output: [keyframe(computedOffset(0),    { left: '10px', top: '15px' }),
+             keyframe(computedOffset(0.25), { left: '20px', top: '25px' }),
+             keyframe(computedOffset(0.5),  { left: '30px' }),
+             keyframe(computedOffset(0.75), { left: '40px', top: '45px' }),
+             keyframe(computedOffset(1),    { left: '50px', top: '55px' })],
   },
   {
     desc:   'a one property two value property-indexed keyframes specification'
             + ' that needs to stringify its values',
     input:  { opacity: [0, 1] },
-    output: [{ offset: null, computedOffset: 0, easing: 'linear',
-               opacity: '0' },
-             { offset: null, computedOffset: 1, easing: 'linear',
-               opacity: '1' }],
+    output: [keyframe(computedOffset(0), { opacity: '0' }),
+             keyframe(computedOffset(1), { opacity: '1' })],
   },
   {
     desc:   'a property-indexed keyframes specification with a CSS variable'
             + ' reference',
     input:  { left: [ 'var(--dist)', 'calc(var(--dist) + 100px)' ] },
-    output: [{ offset: null, computedOffset: 0.0, easing: 'linear',
-               left: 'var(--dist)' },
-             { offset: null, computedOffset: 1.0, easing: 'linear',
-               left: 'calc(var(--dist) + 100px)' }],
+    output: [keyframe(computedOffset(0), { left: 'var(--dist)' }),
+             keyframe(computedOffset(1), { left: 'calc(var(--dist) + 100px)' })]
   },
   {
     desc:   'a property-indexed keyframes specification with a CSS variable'
             + ' reference in a shorthand property',
     input:  { margin: [ 'var(--dist)', 'calc(var(--dist) + 100px)' ] },
-    output: [{ offset: null, computedOffset: 0.0, easing: 'linear',
-               margin: 'var(--dist)' },
-             { offset: null, computedOffset: 1.0, easing: 'linear',
-               margin: 'calc(var(--dist) + 100px)' }],
+    output: [keyframe(computedOffset(0),
+                      { margin: 'var(--dist)' }),
+             keyframe(computedOffset(1),
+                      { margin: 'calc(var(--dist) + 100px)' })],
   },
   {
     desc:   'a one property one value property-indexed keyframes specification',
     input:  { left: ['10px'] },
-    output: [{ offset: null, computedOffset: 1, easing: 'linear',
-               left: '10px' }],
+    output: [keyframe(computedOffset(1), { left: '10px' })],
   },
   {
     desc:   'a one property one non-array value property-indexed keyframes'
             + ' specification',
     input:  { left: '10px' },
-    output: [{ offset: null, computedOffset: 1, easing: 'linear',
-               left: '10px' }],
+    output: [keyframe(computedOffset(1), { left: '10px' })],
   },
   {
     desc:   'a one property two value property-indexed keyframes specification'
             + ' where the first value is invalid',
     input:  { left: ['invalid', '10px'] },
-    output: [{ offset: null, computedOffset: 0, easing: 'linear' },
-             { offset: null, computedOffset: 1, easing: 'linear',
-               left: '10px' }],
+    output: [keyframe(computedOffset(0), {}),
+             keyframe(computedOffset(1), { left: '10px' })]
   },
   {
     desc:   'a one property two value property-indexed keyframes specification'
             + ' where the second value is invalid',
     input:  { left: ['10px', 'invalid'] },
-    output: [{ offset: null, computedOffset: 0, easing: 'linear',
-               left: '10px' },
-             { offset: null, computedOffset: 1, easing: 'linear' }],
+    output: [keyframe(computedOffset(0), { left: '10px' }),
+             keyframe(computedOffset(1), {})]
   },
   {
     desc:   'a one property one keyframe sequence',
     input:  [{ offset: 1, left: '10px' }],
-    output: [{ offset: 1, computedOffset: 1, easing: 'linear',
-               left: '10px' }],
+    output: [keyframe(offset(1), { left: '10px' })],
   },
   {
     desc:   'a one property two keyframe sequence',
     input:  [{ offset: 0, left: '10px' },
              { offset: 1, left: '20px' }],
-    output: [{ offset: 0, computedOffset: 0, easing: 'linear', left: '10px' },
-             { offset: 1, computedOffset: 1, easing: 'linear', left: '20px' }],
+    output: [keyframe(offset(0), { left: '10px' }),
+             keyframe(offset(1), { left: '20px' })],
   },
   {
     desc:   'a two property two keyframe sequence',
     input:  [{ offset: 0, left: '10px', top: '30px' },
              { offset: 1, left: '20px', top: '40px' }],
-    output: [{ offset: 0, computedOffset: 0, easing: 'linear',
-               left: '10px', top: '30px' },
-             { offset: 1, computedOffset: 1, easing: 'linear',
-               left: '20px', top: '40px' }],
+    output: [keyframe(offset(0), { left: '10px', top: '30px' }),
+             keyframe(offset(1), { left: '20px', top: '40px' })],
   },
   {
     desc:   'a one shorthand property two keyframe sequence',
     input:  [{ offset: 0, margin: '10px' },
              { offset: 1, margin: '20px 30px 40px 50px' }],
-    output: [{ offset: 0, computedOffset: 0, easing: 'linear',
-               margin: '10px' },
-             { offset: 1, computedOffset: 1, easing: 'linear',
-               margin: '20px 30px 40px 50px' }],
+    output: [keyframe(offset(0), { margin: '10px' }),
+             keyframe(offset(1), { margin: '20px 30px 40px 50px' })],
   },
   {
     desc:   'a two property (a shorthand and one of its component longhands)'
             + ' two keyframe sequence',
     input:  [{ offset: 0, margin: '10px', marginTop: '20px' },
              { offset: 1, marginTop: '70px', margin: '30px 40px 50px 60px' }],
-    output: [{ offset: 0, computedOffset: 0, easing: 'linear',
-               margin: '10px', marginTop: '20px' },
-             { offset: 1, computedOffset: 1, easing: 'linear',
-               marginTop: '70px', margin: '30px 40px 50px 60px' }],
+    output: [keyframe(offset(0), { margin: '10px', marginTop: '20px' }),
+             keyframe(offset(1), { marginTop: '70px',
+                                   margin: '30px 40px 50px 60px' })],
   },
   {
     desc:   'a keyframe sequence with duplicate values for a given interior'
             + ' offset',
     input:  [{ offset: 0.0, left: '10px' },
              { offset: 0.5, left: '20px' },
              { offset: 0.5, left: '30px' },
              { offset: 0.5, left: '40px' },
              { offset: 1.0, left: '50px' }],
-    output: [{ offset: 0.0, computedOffset: 0.0, easing: 'linear',
-               left: '10px' },
-             { offset: 0.5, computedOffset: 0.5, easing: 'linear',
-               left: '20px' },
-             { offset: 0.5, computedOffset: 0.5, easing: 'linear',
-               left: '30px' },
-             { offset: 0.5, computedOffset: 0.5, easing: 'linear',
-               left: '40px' },
-             { offset: 1.0, computedOffset: 1.0, easing: 'linear',
-               left: '50px' }],
+    output: [keyframe(offset(0),   { left: '10px' }),
+             keyframe(offset(0.5), { left: '20px' }),
+             keyframe(offset(0.5), { left: '30px' }),
+             keyframe(offset(0.5), { left: '40px' }),
+             keyframe(offset(1),   { left: '50px' })],
   },
   {
     desc:   'a keyframe sequence with duplicate values for offsets 0 and 1',
     input:  [{ offset: 0, left: '10px' },
              { offset: 0, left: '20px' },
              { offset: 0, left: '30px' },
              { offset: 1, left: '40px' },
              { offset: 1, left: '50px' },
              { offset: 1, left: '60px' }],
-    output: [{ offset: 0, computedOffset: 0, easing: 'linear', left: '10px' },
-             { offset: 0, computedOffset: 0, easing: 'linear', left: '20px' },
-             { offset: 0, computedOffset: 0, easing: 'linear', left: '30px' },
-             { offset: 1, computedOffset: 1, easing: 'linear', left: '40px' },
-             { offset: 1, computedOffset: 1, easing: 'linear', left: '50px' },
-             { offset: 1, computedOffset: 1, easing: 'linear', left: '60px' }],
+    output: [keyframe(offset(0), { left: '10px' }),
+             keyframe(offset(0), { left: '20px' }),
+             keyframe(offset(0), { left: '30px' }),
+             keyframe(offset(1), { left: '40px' }),
+             keyframe(offset(1), { left: '50px' }),
+             keyframe(offset(1), { left: '60px' })],
   },
   {
     desc:   'a two property four keyframe sequence',
     input:  [{ offset: 0, left: '10px' },
              { offset: 0, top: '20px' },
              { offset: 1, top: '30px' },
              { offset: 1, left: '40px' }],
-    output: [{ offset: 0, computedOffset: 0, easing: 'linear', left: '10px' },
-             { offset: 0, computedOffset: 0, easing: 'linear', top: '20px' },
-             { offset: 1, computedOffset: 1, easing: 'linear', top: '30px' },
-             { offset: 1, computedOffset: 1, easing: 'linear', left: '40px' }],
+    output: [keyframe(offset(0), { left: '10px' }),
+             keyframe(offset(0), { top:  '20px' }),
+             keyframe(offset(1), { top:  '30px' }),
+             keyframe(offset(1), { left: '40px' })],
   },
   {
     desc:   'a single keyframe sequence with omitted offset',
     input:  [{ left: '10px' }],
-    output: [{ offset: null, computedOffset: 1, easing: 'linear',
-               left: '10px' }],
+    output: [keyframe(computedOffset(1), { left: '10px' })],
   },
   {
     desc:   'a single keyframe sequence with null offset',
     input:  [{ offset: null, left: '10px' }],
-    output: [{ offset: null, computedOffset: 1, easing: 'linear',
-               left: '10px' }],
+    output: [keyframe(computedOffset(1), { left: '10px' })],
   },
   {
     desc:   'a single keyframe sequence with string offset',
     input:  [{ offset: '0.5', left: '10px' }],
-    output: [{ offset: 0.5, computedOffset: 0.5, easing: 'linear',
-               left: '10px' }],
+    output: [keyframe(offset(0.5), { left: '10px' })],
   },
   {
     desc:   'a one property keyframe sequence with some omitted offsets',
     input:  [{ offset: 0.00, left: '10px' },
              { offset: 0.25, left: '20px' },
              { left: '30px' },
              { left: '40px' },
              { offset: 1.00, left: '50px' }],
-    output: [{ offset: 0.00, computedOffset: 0.00, easing: 'linear',
-               left: '10px' },
-             { offset: 0.25, computedOffset: 0.25, easing: 'linear',
-               left: '20px' },
-             { offset: null, computedOffset: 0.50, easing: 'linear',
-               left: '30px' },
-             { offset: null, computedOffset: 0.75, easing: 'linear',
-               left: '40px' },
-             { offset: 1.00, computedOffset: 1.00, easing: 'linear',
-               left: '50px' }],
+    output: [keyframe(offset(0),            { left: '10px' }),
+             keyframe(offset(0.25),         { left: '20px' }),
+             keyframe(computedOffset(0.5),  { left: '30px' }),
+             keyframe(computedOffset(0.75), { left: '40px' }),
+             keyframe(offset(1),            { left: '50px' })],
   },
   {
     desc:   'a one property keyframe sequence with some null offsets',
     input:  [{ offset: 0.00, left: '10px' },
              { offset: 0.25, left: '20px' },
              { offset: null, left: '30px' },
              { offset: null, left: '40px' },
              { offset: 1.00, left: '50px' }],
-    output: [{ offset: 0.00, computedOffset: 0.00, easing: 'linear',
-               left: '10px' },
-             { offset: 0.25, computedOffset: 0.25, easing: 'linear',
-               left: '20px' },
-             { offset: null, computedOffset: 0.50, easing: 'linear',
-               left: '30px' },
-             { offset: null, computedOffset: 0.75, easing: 'linear',
-               left: '40px' },
-             { offset: 1.00, computedOffset: 1.00, easing: 'linear',
-               left: '50px' }],
+    output: [keyframe(offset(0),            { left: '10px' }),
+             keyframe(offset(0.25),         { left: '20px' }),
+             keyframe(computedOffset(0.5),  { left: '30px' }),
+             keyframe(computedOffset(0.75), { left: '40px' }),
+             keyframe(offset(1),            { left: '50px' })],
   },
   {
     desc:   'a two property keyframe sequence with some omitted offsets',
     input:  [{ offset: 0.00, left: '10px', top: '20px' },
              { offset: 0.25, left: '30px' },
              { left: '40px' },
              { left: '50px', top: '60px' },
              { offset: 1.00, left: '70px', top: '80px' }],
-    output: [{ offset: 0.00, computedOffset: 0.00, easing: 'linear',
-               left: '10px', top: '20px' },
-             { offset: 0.25, computedOffset: 0.25, easing: 'linear',
-               left: '30px' },
-             { offset: null, computedOffset: 0.50, easing: 'linear',
-               left: '40px' },
-             { offset: null, computedOffset: 0.75, easing: 'linear',
-               left: '50px', top: '60px' },
-             { offset: 1.00, computedOffset: 1.00, easing: 'linear',
-               left: '70px', top: '80px' }],
+    output: [keyframe(offset(0),            { left: '10px', top: '20px' }),
+             keyframe(offset(0.25),         { left: '30px' }),
+             keyframe(computedOffset(0.5),  { left: '40px' }),
+             keyframe(computedOffset(0.75), { left: '50px', top: '60px' }),
+             keyframe(offset(1),            { left: '70px', top: '80px' })],
   },
   {
     desc:   'a one property keyframe sequence with all omitted offsets',
     input:  [{ left: '10px' },
              { left: '20px' },
              { left: '30px' },
              { left: '40px' },
              { left: '50px' }],
-    output: [{ offset: null, computedOffset: 0.00, easing: 'linear',
-               left: '10px' },
-             { offset: null, computedOffset: 0.25, easing: 'linear',
-               left: '20px' },
-             { offset: null, computedOffset: 0.50, easing: 'linear',
-               left: '30px' },
-             { offset: null, computedOffset: 0.75, easing: 'linear',
-               left: '40px' },
-             { offset: null, computedOffset: 1.00, easing: 'linear',
-               left: '50px' }],
+    output: [keyframe(computedOffset(0),    { left: '10px' }),
+             keyframe(computedOffset(0.25), { left: '20px' }),
+             keyframe(computedOffset(0.5),  { left: '30px' }),
+             keyframe(computedOffset(0.75), { left: '40px' }),
+             keyframe(computedOffset(1),    { left: '50px' })],
   },
   {
     desc:   'a keyframe sequence with different easing values, but the same'
             + ' easing value for a given offset',
     input:  [{ offset: 0.0, easing: 'ease',     left: '10px'},
              { offset: 0.0, easing: 'ease',     top: '20px'},
              { offset: 0.5, easing: 'linear',   left: '30px' },
              { offset: 0.5, easing: 'linear',   top: '40px' },
              { offset: 1.0, easing: 'step-end', left: '50px' },
              { offset: 1.0, easing: 'step-end', top: '60px' }],
-    output: [{ offset: 0.0, computedOffset: 0.0, easing: 'ease',
-               left: '10px' },
-             { offset: 0.0, computedOffset: 0.0, easing: 'ease',
-               top: '20px' },
-             { offset: 0.5, computedOffset: 0.5, easing: 'linear',
-               left: '30px' },
-             { offset: 0.5, computedOffset: 0.5, easing: 'linear',
-               top: '40px' },
-             { offset: 1.0, computedOffset: 1.0, easing: 'steps(1)',
-               left: '50px' },
-             { offset: 1.0, computedOffset: 1.0, easing: 'steps(1)',
-               top: '60px' }],
+    output: [keyframe(offset(0),   { left: '10px' }, 'ease'),
+             keyframe(offset(0),   { top:  '20px' }, 'ease'),
+             keyframe(offset(0.5), { left: '30px' }, 'linear'),
+             keyframe(offset(0.5), { top:  '40px' }, 'linear'),
+             keyframe(offset(1),   { left: '50px' }, 'steps(1)'),
+             keyframe(offset(1),   { top:  '60px' }, 'steps(1)')],
   },
   {
     desc:   'a keyframe sequence with different composite values, but the'
             + ' same composite value for a given offset',
     input:  [{ offset: 0.0, composite: 'replace', left: '10px' },
              { offset: 0.0, composite: 'replace', top: '20px' },
              { offset: 0.5, composite: 'add',     left: '30px' },
              { offset: 0.5, composite: 'add',     top: '40px' },
              { offset: 1.0, composite: 'replace', left: '50px' },
              { offset: 1.0, composite: 'replace', top: '60px' }],
-    output: [{ offset: 0.0, computedOffset: 0.0, easing: 'linear',
-               composite: 'replace', left: '10px' },
-             { offset: 0.0, computedOffset: 0.0, easing: 'linear',
-               composite: 'replace', top: '20px' },
-             { offset: 0.5, computedOffset: 0.5, easing: 'linear',
-               composite: 'add', left: '30px' },
-             { offset: 0.5, computedOffset: 0.5, easing: 'linear',
-               composite: 'add', top: '40px' },
-             { offset: 1.0, computedOffset: 1.0, easing: 'linear',
-               composite: 'replace', left: '50px' },
-             { offset: 1.0, computedOffset: 1.0, easing: 'linear',
-               composite: 'replace', top: '60px' }],
+    output: [keyframe(offset(0),   { left: '10px' }, 'linear', 'replace'),
+             keyframe(offset(0),   { top:  '20px' }, 'linear', 'replace'),
+             keyframe(offset(0.5), { left: '30px' }, 'linear', 'add'),
+             keyframe(offset(0.5), { top:  '40px' }, 'linear', 'add'),
+             keyframe(offset(1),   { left: '50px' }, 'linear', 'replace'),
+             keyframe(offset(1),   { top:  '60px' }, 'linear', 'replace')],
   },
   {
     desc:   'a one property two keyframe sequence that needs to stringify'
             + ' its values',
     input:  [{ offset: 0, opacity: 0 },
              { offset: 1, opacity: 1 }],
-    output: [{ offset: 0, computedOffset: 0, easing: 'linear', opacity: '0' },
-             { offset: 1, computedOffset: 1, easing: 'linear', opacity: '1' }],
+    output: [keyframe(offset(0), { opacity: '0' }),
+             keyframe(offset(1), { opacity: '1' })],
   },
   {
     desc:   'a keyframe sequence with a CSS variable reference',
     input:  [{ left: 'var(--dist)' },
              { left: 'calc(var(--dist) + 100px)' }],
-    output: [{ offset: null, computedOffset: 0.0, easing: 'linear',
-               left: 'var(--dist)' },
-             { offset: null, computedOffset: 1.0, easing: 'linear',
-               left: 'calc(var(--dist) + 100px)' }],
+    output: [keyframe(computedOffset(0), { left: 'var(--dist)' }),
+             keyframe(computedOffset(1), { left: 'calc(var(--dist) + 100px)' })]
   },
   {
     desc:   'a keyframe sequence with a CSS variable reference in a shorthand'
             + ' property',
     input:  [{ margin: 'var(--dist)' },
              { margin: 'calc(var(--dist) + 100px)' }],
-    output: [{ offset: null, computedOffset: 0.0, easing: 'linear',
-               margin: 'var(--dist)' },
-             { offset: null, computedOffset: 1.0, easing: 'linear',
-               margin: 'calc(var(--dist) + 100px)' }],
+    output: [keyframe(computedOffset(0),
+                      { margin: 'var(--dist)' }),
+             keyframe(computedOffset(1),
+                      { margin: 'calc(var(--dist) + 100px)' })],
   },
   {
     desc:   'a keyframe sequence where shorthand precedes longhand',
     input:  [{ offset: 0, margin: '10px', marginRight: '20px' },
              { offset: 1, margin: '30px' }],
-    output: [{ offset: 0, computedOffset: 0, easing: 'linear',
-               margin: '10px', marginRight: '20px' },
-             { offset: 1, computedOffset: 1, easing: 'linear',
-               margin: '30px' }],
+    output: [keyframe(offset(0), { margin: '10px', marginRight: '20px' }),
+             keyframe(offset(1), { margin: '30px' })],
   },
   {
     desc:   'a keyframe sequence where longhand precedes shorthand',
     input:  [{ offset: 0, marginRight: '20px', margin: '10px' },
              { offset: 1, margin: '30px' }],
-    output: [{ offset: 0, computedOffset: 0, easing: 'linear',
-               marginRight: '20px', margin: '10px' },
-             { offset: 1, computedOffset: 1, easing: 'linear',
-               margin: '30px' }],
+    output: [keyframe(offset(0), { marginRight: '20px', margin: '10px' }),
+             keyframe(offset(1), { margin: '30px' })],
   },
   {
     desc:   'a keyframe sequence where lesser shorthand precedes greater'
             + ' shorthand',
     input:  [{ offset: 0,
                borderLeft: '1px solid rgb(1, 2, 3)',
                border: '2px dotted rgb(4, 5, 6)' },
              { offset: 1, border: '3px dashed rgb(7, 8, 9)' }],
-    output: [{ offset: 0, computedOffset: 0, easing: 'linear',
-               borderLeft: '1px solid rgb(1, 2, 3)',
-               border: '2px dotted rgb(4, 5, 6)' },
-             { offset: 1, computedOffset: 1, easing: 'linear',
-               border: '3px dashed rgb(7, 8, 9)' }],
+    output: [keyframe(offset(0), { borderLeft: '1px solid rgb(1, 2, 3)',
+                                   border: '2px dotted rgb(4, 5, 6)' }),
+             keyframe(offset(1), { border: '3px dashed rgb(7, 8, 9)' })],
   },
   {
     desc:   'a keyframe sequence where greater shorthand precedes lesser'
             + ' shorthand',
     input:  [{ offset: 0, border: '2px dotted rgb(4, 5, 6)',
                borderLeft: '1px solid rgb(1, 2, 3)' },
              { offset: 1, border: '3px dashed rgb(7, 8, 9)' }],
-    output: [{ offset: 0, computedOffset: 0, easing: 'linear',
-               border: '2px dotted rgb(4, 5, 6)',
-               borderLeft: '1px solid rgb(1, 2, 3)' },
-             { offset: 1, computedOffset: 1, easing: 'linear',
-               border: '3px dashed rgb(7, 8, 9)' }],
+    output: [keyframe(offset(0), { borderLeft: '1px solid rgb(1, 2, 3)',
+                                   border: '2px dotted rgb(4, 5, 6)' }),
+             keyframe(offset(1), { border: '3px dashed rgb(7, 8, 9)' })],
   },
   {
     desc:   'a two property keyframe sequence where one property is missing'
             + ' from the first keyframe',
     input:  [{ offset: 0, left: '10px' },
              { offset: 1, left: '20px', top: '30px' }],
-    output: [{ offset: 0, computedOffset: 0, easing: 'linear', left: '10px' },
-             { offset: 1, computedOffset: 1, easing: 'linear',
-               left: '20px', top: '30px' }],
+    output: [keyframe(offset(0), { left: '10px' }),
+             keyframe(offset(1), { left: '20px', top: '30px' })],
   },
   {
     desc:   'a two property keyframe sequence where one property is missing'
             + ' from the last keyframe',
     input:  [{ offset: 0, left: '10px', top: '20px' },
              { offset: 1, left: '30px' }],
-    output: [{ offset: 0, computedOffset: 0, easing: 'linear',
-               left: '10px' , top: '20px' },
-             { offset: 1, computedOffset: 1, easing: 'linear',
-               left: '30px' }],
+    output: [keyframe(offset(0), { left: '10px', top: '20px' }),
+             keyframe(offset(1), { left: '30px' })],
   },
   {
     desc:   'a keyframe sequence with repeated values at offset 1 with'
             + ' different easings',
     input:  [{ offset: 0.0, left: '100px', easing: 'ease' },
              { offset: 0.0, left: '200px', easing: 'ease' },
              { offset: 0.5, left: '300px', easing: 'linear' },
              { offset: 1.0, left: '400px', easing: 'ease-out' },
              { offset: 1.0, left: '500px', easing: 'step-end' }],
-    output: [{ offset: 0.0, computedOffset: 0.0, easing: 'ease',
-               left: '100px' },
-             { offset: 0.0, computedOffset: 0.0, easing: 'ease',
-               left: '200px' },
-             { offset: 0.5, computedOffset: 0.5, easing: 'linear',
-               left: '300px' },
-             { offset: 1.0, computedOffset: 1.0, easing: 'ease-out',
-               left: '400px' },
-             { offset: 1.0, computedOffset: 1.0, easing: 'steps(1)',
-               left: '500px' }],
+    output: [keyframe(offset(0),   { left: '100px' }, 'ease'),
+             keyframe(offset(0),   { left: '200px' }, 'ease'),
+             keyframe(offset(0.5), { left: '300px' }, 'linear'),
+             keyframe(offset(1),   { left: '400px' }, 'ease-out'),
+             keyframe(offset(1),   { left: '500px' }, 'steps(1)')],
   },
 ];
 
 const gInvalidKeyframesTests = [
   {
     desc:     'keyframes with an out-of-bounded positive offset',
     input:    [ { opacity: 0 },
                 { opacity: 0.5, offset: 2 },