Bug 1339332 - Part 3: Test for missing keyframes in CSS Animation. r=hiro draft
authorDaisuke Akatsuka <dakatsuka@mozilla.com>
Wed, 08 Mar 2017 10:07:09 +0900
changeset 494895 5b75f1c7ebd5b53425da624a678b73c4cf1c6a97
parent 494894 8815cc9238ea2e1f247efb9035b811e0c57c13af
child 494896 cef8a1a0a1173e8d0a7fdffadca870dcbaf88480
push id48182
push userbmo:dakatsuka@mozilla.com
push dateWed, 08 Mar 2017 03:10:05 +0000
reviewershiro
bugs1339332
milestone55.0a1
Bug 1339332 - Part 3: Test for missing keyframes in CSS Animation. r=hiro MozReview-Commit-ID: 85epAy0Kd0g
dom/animation/test/chrome.ini
dom/animation/test/chrome/test_animation_properties.html
dom/animation/test/chrome/test_cssanimation_missing_keyframes.html
dom/animation/test/testcommon.js
--- a/dom/animation/test/chrome.ini
+++ b/dom/animation/test/chrome.ini
@@ -7,14 +7,15 @@ support-files =
   chrome/file_animation_performance_warning.html
 
 [chrome/test_animate_xrays.html]
 # file_animate_xrays.html needs to go in mochitest.ini since it is served
 # over HTTP
 [chrome/test_animation_observers.html]
 [chrome/test_animation_performance_warning.html]
 [chrome/test_animation_properties.html]
+[chrome/test_cssanimation_missing_keyframes.html]
 [chrome/test_generated_content_getAnimations.html]
 [chrome/test_observers_for_sync_api.html]
 [chrome/test_restyles.html]
 skip-if = os == 'android' && processor == 'x86' # bug 1335986
 [chrome/test_running_on_compositor.html]
 [chrome/test_simulate_compute_values_failure.html]
--- a/dom/animation/test/chrome/test_animation_properties.html
+++ b/dom/animation/test/chrome/test_animation_properties.html
@@ -19,877 +19,851 @@
 }
 div {
   font-size: 10px; /* For calculating em-based units */
 }
 </style>
 <script>
 'use strict';
 
-function assert_properties_equal(actual, expected) {
-  assert_equals(actual.length, expected.length);
-
-  var compareProperties = (a, b) =>
-    a.property == b.property ? 0 : (a.property < b.property ? -1 : 1);
-
-  var sortedActual   = actual.sort(compareProperties);
-  var sortedExpected = expected.sort(compareProperties);
-
-  var serializeValues = values =>
-    values.map(value =>
-      '{ ' +
-        [ 'offset', 'value', 'easing', 'composite' ].map(
-          member => `${member}: ${value[member]}`
-        ).join(', ') +
-      ' }')
-    .join(', ');
-
-  for (var i = 0; i < sortedActual.length; i++) {
-    assert_equals(sortedActual[i].property,
-                  sortedExpected[i].property,
-                  'CSS property name should match');
-    assert_equals(serializeValues(sortedActual[i].values),
-                  serializeValues(sortedExpected[i].values),
-                  `Values arrays do not match for `
-                  + `${sortedActual[i].property} property`);
-  }
-}
-
-// Shorthand for constructing a value object
-function value(offset, value, composite, easing) {
-  return { offset: offset, value: value, easing: easing, composite: composite };
-}
-
 var gTests = [
 
   // ---------------------------------------------------------------------
   //
   // Tests for property-indexed specifications
   //
   // ---------------------------------------------------------------------
 
   { desc:     'a one-property two-value property-indexed specification',
     frames:   { left: ['10px', '20px'] },
     expected: [ { property: 'left',
-                  values: [ value(0, '10px', 'replace', 'linear'),
-                            value(1, '20px', 'replace') ] } ]
+                  values: [ valueFormat(0, '10px', 'replace', 'linear'),
+                            valueFormat(1, '20px', 'replace') ] } ]
   },
   { desc:     'a one-shorthand-property two-value property-indexed'
               + ' specification',
     frames:   { margin: ['10px', '10px 20px 30px 40px'] },
     expected: [ { property: 'margin-top',
-                  values: [ value(0, '10px', 'replace', 'linear'),
-                            value(1, '10px', 'replace') ] },
+                  values: [ valueFormat(0, '10px', 'replace', 'linear'),
+                            valueFormat(1, '10px', 'replace') ] },
                 { property: 'margin-right',
-                  values: [ value(0, '10px', 'replace', 'linear'),
-                            value(1, '20px', 'replace') ] },
+                  values: [ valueFormat(0, '10px', 'replace', 'linear'),
+                            valueFormat(1, '20px', 'replace') ] },
                 { property: 'margin-bottom',
-                  values: [ value(0, '10px', 'replace', 'linear'),
-                            value(1, '30px', 'replace') ] },
+                  values: [ valueFormat(0, '10px', 'replace', 'linear'),
+                            valueFormat(1, '30px', 'replace') ] },
                 { property: 'margin-left',
-                  values: [ value(0, '10px', 'replace', 'linear'),
-                            value(1, '40px', 'replace') ] } ]
+                  values: [ valueFormat(0, '10px', 'replace', 'linear'),
+                            valueFormat(1, '40px', 'replace') ] } ]
   },
   { desc:     'a two-property (one shorthand and one of its longhand'
               + ' components) two-value property-indexed specification',
     frames:   { marginTop: ['50px', '60px'],
                 margin: ['10px', '10px 20px 30px 40px'] },
     expected: [ { property: 'margin-top',
-                  values: [ value(0, '50px', 'replace', 'linear'),
-                            value(1, '60px', 'replace') ] },
+                  values: [ valueFormat(0, '50px', 'replace', 'linear'),
+                            valueFormat(1, '60px', 'replace') ] },
                 { property: 'margin-right',
-                  values: [ value(0, '10px', 'replace', 'linear'),
-                            value(1, '20px', 'replace') ] },
+                  values: [ valueFormat(0, '10px', 'replace', 'linear'),
+                            valueFormat(1, '20px', 'replace') ] },
                 { property: 'margin-bottom',
-                  values: [ value(0, '10px', 'replace', 'linear'),
-                            value(1, '30px', 'replace') ] },
+                  values: [ valueFormat(0, '10px', 'replace', 'linear'),
+                            valueFormat(1, '30px', 'replace') ] },
                 { property: 'margin-left',
-                  values: [ value(0, '10px', 'replace', 'linear'),
-                            value(1, '40px', 'replace') ] } ]
+                  values: [ valueFormat(0, '10px', 'replace', 'linear'),
+                            valueFormat(1, '40px', 'replace') ] } ]
   },
   { desc:     'a two-property property-indexed specification with different'
               + ' numbers of values',
     frames:   { left: ['10px', '20px', '30px'],
                 top: ['40px', '50px'] },
     expected: [ { property: 'left',
-                  values: [ value(0, '10px', 'replace', 'linear'),
-                            value(0.5, '20px', 'replace', 'linear'),
-                            value(1, '30px', 'replace') ] },
+                  values: [ valueFormat(0, '10px', 'replace', 'linear'),
+                            valueFormat(0.5, '20px', 'replace', 'linear'),
+                            valueFormat(1, '30px', 'replace') ] },
                 { property: 'top',
-                  values: [ value(0, '40px', 'replace', 'linear'),
-                            value(1, '50px', 'replace') ] } ]
+                  values: [ valueFormat(0, '40px', 'replace', 'linear'),
+                            valueFormat(1, '50px', 'replace') ] } ]
   },
   { desc:     'a property-indexed specification with an invalid value',
     frames:   { left: ['10px', '20px', '30px', '40px', '50px'],
                 top:  ['15px', '25px', 'invalid', '45px', '55px'] },
     expected: [ { property: 'left',
-                  values: [ value(0, '10px', 'replace', 'linear'),
-                            value(0.25, '20px', 'replace', 'linear'),
-                            value(0.5, '30px', 'replace', 'linear'),
-                            value(0.75, '40px', 'replace', 'linear'),
-                            value(1, '50px', 'replace') ] },
+                  values: [ valueFormat(0, '10px', 'replace', 'linear'),
+                            valueFormat(0.25, '20px', 'replace', 'linear'),
+                            valueFormat(0.5, '30px', 'replace', 'linear'),
+                            valueFormat(0.75, '40px', 'replace', 'linear'),
+                            valueFormat(1, '50px', 'replace') ] },
                 { property: 'top',
-                  values: [ value(0, '15px', 'replace', 'linear'),
-                            value(0.25, '25px', 'replace', 'linear'),
-                            value(0.75, '45px', 'replace', 'linear'),
-                            value(1, '55px', 'replace') ] } ]
+                  values: [ valueFormat(0, '15px', 'replace', 'linear'),
+                            valueFormat(0.25, '25px', 'replace', 'linear'),
+                            valueFormat(0.75, '45px', 'replace', 'linear'),
+                            valueFormat(1, '55px', 'replace') ] } ]
   },
   { desc:     'a one-property two-value property-indexed specification that'
               + ' needs to stringify its values',
     frames:   { opacity: [0, 1] },
     expected: [ { property: 'opacity',
-                  values: [ value(0, '0', 'replace', 'linear'),
-                            value(1, '1', 'replace') ] } ]
+                  values: [ valueFormat(0, '0', 'replace', 'linear'),
+                            valueFormat(1, '1', 'replace') ] } ]
   },
   { desc:     'a property-indexed keyframe where a lesser shorthand precedes'
               + ' a greater shorthand',
     frames:   { borderLeft: [ '1px solid rgb(1, 2, 3)',
                               '2px solid rgb(4, 5, 6)' ],
                 border:     [ '3px dotted rgb(7, 8, 9)',
                               '4px dashed rgb(10, 11, 12)' ] },
     expected: [ { property: 'border-bottom-color',
-                  values: [ value(0, 'rgb(7, 8, 9)', 'replace', 'linear'),
-                            value(1, 'rgb(10, 11, 12)', 'replace') ] },
+                  values: [ valueFormat(0, 'rgb(7, 8, 9)', 'replace', 'linear'),
+                            valueFormat(1, 'rgb(10, 11, 12)', 'replace') ] },
                 { property: 'border-left-color',
-                  values: [ value(0, 'rgb(1, 2, 3)', 'replace', 'linear'),
-                            value(1, 'rgb(4, 5, 6)', 'replace') ] },
+                  values: [ valueFormat(0, 'rgb(1, 2, 3)', 'replace', 'linear'),
+                            valueFormat(1, 'rgb(4, 5, 6)', 'replace') ] },
                 { property: 'border-right-color',
-                  values: [ value(0, 'rgb(7, 8, 9)', 'replace', 'linear'),
-                            value(1, 'rgb(10, 11, 12)', 'replace') ] },
+                  values: [ valueFormat(0, 'rgb(7, 8, 9)', 'replace', 'linear'),
+                            valueFormat(1, 'rgb(10, 11, 12)', 'replace') ] },
                 { property: 'border-top-color',
-                  values: [ value(0, 'rgb(7, 8, 9)', 'replace', 'linear'),
-                            value(1, 'rgb(10, 11, 12)', 'replace') ] },
+                  values: [ valueFormat(0, 'rgb(7, 8, 9)', 'replace', 'linear'),
+                            valueFormat(1, 'rgb(10, 11, 12)', 'replace') ] },
                 { property: 'border-bottom-width',
-                  values: [ value(0, '3px', 'replace', 'linear'),
-                            value(1, '4px', 'replace') ] },
+                  values: [ valueFormat(0, '3px', 'replace', 'linear'),
+                            valueFormat(1, '4px', 'replace') ] },
                 { property: 'border-left-width',
-                  values: [ value(0, '1px', 'replace', 'linear'),
-                            value(1, '2px', 'replace') ] },
+                  values: [ valueFormat(0, '1px', 'replace', 'linear'),
+                            valueFormat(1, '2px', 'replace') ] },
                 { property: 'border-right-width',
-                  values: [ value(0, '3px', 'replace', 'linear'),
-                            value(1, '4px', 'replace') ] },
+                  values: [ valueFormat(0, '3px', 'replace', 'linear'),
+                            valueFormat(1, '4px', 'replace') ] },
                 { property: 'border-top-width',
-                  values: [ value(0, '3px', 'replace', 'linear'),
-                            value(1, '4px', 'replace') ] },
+                  values: [ valueFormat(0, '3px', 'replace', 'linear'),
+                            valueFormat(1, '4px', 'replace') ] },
                 { property: 'border-bottom-style',
-                  values: [ value(0, 'dotted', 'replace', 'linear'),
-                            value(1, 'dashed', 'replace') ] },
+                  values: [ valueFormat(0, 'dotted', 'replace', 'linear'),
+                            valueFormat(1, 'dashed', 'replace') ] },
                 { property: 'border-left-style',
-                  values: [ value(0, 'solid', 'replace', 'linear'),
-                            value(1, 'solid', 'replace') ] },
+                  values: [ valueFormat(0, 'solid', 'replace', 'linear'),
+                            valueFormat(1, 'solid', 'replace') ] },
                 { property: 'border-right-style',
-                  values: [ value(0, 'dotted', 'replace', 'linear'),
-                            value(1, 'dashed', 'replace') ] },
+                  values: [ valueFormat(0, 'dotted', 'replace', 'linear'),
+                            valueFormat(1, 'dashed', 'replace') ] },
                 { property: 'border-top-style',
-                  values: [ value(0, 'dotted', 'replace', 'linear'),
-                            value(1, 'dashed', 'replace') ] },
+                  values: [ valueFormat(0, 'dotted', 'replace', 'linear'),
+                            valueFormat(1, 'dashed', 'replace') ] },
                 { property: 'border-image-outset',
-                  values: [ value(0, '0 0 0 0', 'replace', 'linear'),
-                            value(1, '0 0 0 0', 'replace') ] },
+                  values: [ valueFormat(0, '0 0 0 0', 'replace', 'linear'),
+                            valueFormat(1, '0 0 0 0', 'replace') ] },
                 { property: 'border-image-repeat',
-                  values: [ value(0, 'stretch stretch', 'replace', 'linear'),
-                            value(1, 'stretch stretch', 'replace') ] },
+                  values: [ valueFormat(0,
+                                        'stretch stretch', 'replace', 'linear'),
+                            valueFormat(1, 'stretch stretch', 'replace') ] },
                 { property: 'border-image-slice',
-                  values: [ value(0, '100% 100% 100% 100%',
+                  values: [ valueFormat(0, '100% 100% 100% 100%',
                                   'replace', 'linear'),
-                            value(1, '100% 100% 100% 100%', 'replace') ] },
+                            valueFormat(1,
+                                        '100% 100% 100% 100%', 'replace') ] },
                 { property: 'border-image-source',
-                  values: [ value(0, 'none', 'replace', 'linear'),
-                            value(1, 'none', 'replace') ] },
+                  values: [ valueFormat(0, 'none', 'replace', 'linear'),
+                            valueFormat(1, 'none', 'replace') ] },
                 { property: 'border-image-width',
-                  values: [ value(0, '1 1 1 1', 'replace', 'linear'),
-                            value(1, '1 1 1 1', 'replace') ] },
+                  values: [ valueFormat(0, '1 1 1 1', 'replace', 'linear'),
+                            valueFormat(1, '1 1 1 1', 'replace') ] },
                 { property: '-moz-border-bottom-colors',
-                  values: [ value(0, 'none', 'replace', 'linear'),
-                            value(1, 'none', 'replace') ] },
+                  values: [ valueFormat(0, 'none', 'replace', 'linear'),
+                            valueFormat(1, 'none', 'replace') ] },
                 { property: '-moz-border-left-colors',
-                  values: [ value(0, 'none', 'replace', 'linear'),
-                            value(1, 'none', 'replace') ] },
+                  values: [ valueFormat(0, 'none', 'replace', 'linear'),
+                            valueFormat(1, 'none', 'replace') ] },
                 { property: '-moz-border-right-colors',
-                  values: [ value(0, 'none', 'replace', 'linear'),
-                            value(1, 'none', 'replace') ] },
+                  values: [ valueFormat(0, 'none', 'replace', 'linear'),
+                            valueFormat(1, 'none', 'replace') ] },
                 { property: '-moz-border-top-colors',
-                  values: [ value(0, 'none', 'replace', 'linear'),
-                            value(1, 'none', 'replace') ] } ]
+                  values: [ valueFormat(0, 'none', 'replace', 'linear'),
+                            valueFormat(1, 'none', 'replace') ] } ]
   },
   { desc:     'a property-indexed keyframe where a greater shorthand precedes'
               + ' a lesser shorthand',
     frames:   { border:     [ '3px dotted rgb(7, 8, 9)',
                               '4px dashed rgb(10, 11, 12)' ],
                 borderLeft: [ '1px solid rgb(1, 2, 3)',
                               '2px solid rgb(4, 5, 6)' ] },
     expected: [ { property: 'border-bottom-color',
-                  values: [ value(0, 'rgb(7, 8, 9)', 'replace', 'linear'),
-                            value(1, 'rgb(10, 11, 12)', 'replace') ] },
+                  values: [ valueFormat(0, 'rgb(7, 8, 9)', 'replace', 'linear'),
+                            valueFormat(1, 'rgb(10, 11, 12)', 'replace') ] },
                 { property: 'border-left-color',
-                  values: [ value(0, 'rgb(1, 2, 3)', 'replace', 'linear'),
-                            value(1, 'rgb(4, 5, 6)', 'replace') ] },
+                  values: [ valueFormat(0, 'rgb(1, 2, 3)', 'replace', 'linear'),
+                            valueFormat(1, 'rgb(4, 5, 6)', 'replace') ] },
                 { property: 'border-right-color',
-                  values: [ value(0, 'rgb(7, 8, 9)', 'replace', 'linear'),
-                            value(1, 'rgb(10, 11, 12)', 'replace') ] },
+                  values: [ valueFormat(0, 'rgb(7, 8, 9)', 'replace', 'linear'),
+                            valueFormat(1, 'rgb(10, 11, 12)', 'replace') ] },
                 { property: 'border-top-color',
-                  values: [ value(0, 'rgb(7, 8, 9)', 'replace', 'linear'),
-                            value(1, 'rgb(10, 11, 12)', 'replace') ] },
+                  values: [ valueFormat(0, 'rgb(7, 8, 9)', 'replace', 'linear'),
+                            valueFormat(1, 'rgb(10, 11, 12)', 'replace') ] },
                 { property: 'border-bottom-width',
-                  values: [ value(0, '3px', 'replace', 'linear'),
-                            value(1, '4px', 'replace') ] },
+                  values: [ valueFormat(0, '3px', 'replace', 'linear'),
+                            valueFormat(1, '4px', 'replace') ] },
                 { property: 'border-left-width',
-                  values: [ value(0, '1px', 'replace', 'linear'),
-                            value(1, '2px', 'replace') ] },
+                  values: [ valueFormat(0, '1px', 'replace', 'linear'),
+                            valueFormat(1, '2px', 'replace') ] },
                 { property: 'border-right-width',
-                  values: [ value(0, '3px', 'replace', 'linear'),
-                            value(1, '4px', 'replace') ] },
+                  values: [ valueFormat(0, '3px', 'replace', 'linear'),
+                            valueFormat(1, '4px', 'replace') ] },
                 { property: 'border-top-width',
-                  values: [ value(0, '3px', 'replace', 'linear'),
-                            value(1, '4px', 'replace') ] },
+                  values: [ valueFormat(0, '3px', 'replace', 'linear'),
+                            valueFormat(1, '4px', 'replace') ] },
                 { property: 'border-bottom-style',
-                  values: [ value(0, 'dotted', 'replace', 'linear'),
-                            value(1, 'dashed', 'replace') ] },
+                  values: [ valueFormat(0, 'dotted', 'replace', 'linear'),
+                            valueFormat(1, 'dashed', 'replace') ] },
                 { property: 'border-left-style',
-                  values: [ value(0, 'solid', 'replace', 'linear'),
-                            value(1, 'solid', 'replace') ] },
+                  values: [ valueFormat(0, 'solid', 'replace', 'linear'),
+                            valueFormat(1, 'solid', 'replace') ] },
                 { property: 'border-right-style',
-                  values: [ value(0, 'dotted', 'replace', 'linear'),
-                            value(1, 'dashed', 'replace') ] },
+                  values: [ valueFormat(0, 'dotted', 'replace', 'linear'),
+                            valueFormat(1, 'dashed', 'replace') ] },
                 { property: 'border-top-style',
-                  values: [ value(0, 'dotted', 'replace', 'linear'),
-                            value(1, 'dashed', 'replace') ] },
+                  values: [ valueFormat(0, 'dotted', 'replace', 'linear'),
+                            valueFormat(1, 'dashed', 'replace') ] },
                 { property: 'border-image-outset',
-                  values: [ value(0, '0 0 0 0', 'replace', 'linear'),
-                            value(1, '0 0 0 0', 'replace') ] },
+                  values: [ valueFormat(0, '0 0 0 0', 'replace', 'linear'),
+                            valueFormat(1, '0 0 0 0', 'replace') ] },
                 { property: 'border-image-repeat',
-                  values: [ value(0, 'stretch stretch', 'replace', 'linear'),
-                            value(1, 'stretch stretch', 'replace') ] },
+                  values: [ valueFormat(0,
+                                        'stretch stretch', 'replace', 'linear'),
+                            valueFormat(1, 'stretch stretch', 'replace') ] },
                 { property: 'border-image-slice',
-                  values: [ value(0, '100% 100% 100% 100%',
+                  values: [ valueFormat(0, '100% 100% 100% 100%',
                                   'replace', 'linear'),
-                            value(1, '100% 100% 100% 100%', 'replace') ] },
+                            valueFormat(1,
+                                        '100% 100% 100% 100%', 'replace') ] },
                 { property: 'border-image-source',
-                  values: [ value(0, 'none', 'replace', 'linear'),
-                            value(1, 'none', 'replace') ] },
+                  values: [ valueFormat(0, 'none', 'replace', 'linear'),
+                            valueFormat(1, 'none', 'replace') ] },
                 { property: 'border-image-width',
-                  values: [ value(0, '1 1 1 1', 'replace', 'linear'),
-                            value(1, '1 1 1 1', 'replace') ] },
+                  values: [ valueFormat(0, '1 1 1 1', 'replace', 'linear'),
+                            valueFormat(1, '1 1 1 1', 'replace') ] },
                 { property: '-moz-border-bottom-colors',
-                  values: [ value(0, 'none', 'replace', 'linear'),
-                            value(1, 'none', 'replace') ] },
+                  values: [ valueFormat(0, 'none', 'replace', 'linear'),
+                            valueFormat(1, 'none', 'replace') ] },
                 { property: '-moz-border-left-colors',
-                  values: [ value(0, 'none', 'replace', 'linear'),
-                            value(1, 'none', 'replace') ] },
+                  values: [ valueFormat(0, 'none', 'replace', 'linear'),
+                            valueFormat(1, 'none', 'replace') ] },
                 { property: '-moz-border-right-colors',
-                  values: [ value(0, 'none', 'replace', 'linear'),
-                            value(1, 'none', 'replace') ] },
+                  values: [ valueFormat(0, 'none', 'replace', 'linear'),
+                            valueFormat(1, 'none', 'replace') ] },
                 { property: '-moz-border-top-colors',
-                  values: [ value(0, 'none', 'replace', 'linear'),
-                            value(1, 'none', 'replace') ] } ]
+                  values: [ valueFormat(0, 'none', 'replace', 'linear'),
+                            valueFormat(1, 'none', 'replace') ] } ]
   },
 
   // ---------------------------------------------------------------------
   //
   // Tests for keyframe sequences
   //
   // ---------------------------------------------------------------------
 
   { desc:     'a keyframe sequence specification with repeated values at'
               + ' offset 0/1 with different easings',
     frames:   [ { 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' } ],
     expected: [ { property: 'left',
-                  values: [ value(0, '100px', 'replace'),
-                            value(0, '200px', 'replace', 'ease'),
-                            value(0.5, '300px', 'replace', 'linear'),
-                            value(1, '400px', 'replace'),
-                            value(1, '500px', 'replace') ] } ]
+                  values: [ valueFormat(0, '100px', 'replace'),
+                            valueFormat(0, '200px', 'replace', 'ease'),
+                            valueFormat(0.5, '300px', 'replace', 'linear'),
+                            valueFormat(1, '400px', 'replace'),
+                            valueFormat(1, '500px', 'replace') ] } ]
   },
   { desc:     'a one-property two-keyframe sequence',
     frames:   [ { offset: 0, left: '10px' },
                 { offset: 1, left: '20px' } ],
     expected: [ { property: 'left',
-                  values: [ value(0, '10px', 'replace', 'linear'),
-                            value(1, '20px', 'replace') ] } ]
+                  values: [ valueFormat(0, '10px', 'replace', 'linear'),
+                            valueFormat(1, '20px', 'replace') ] } ]
   },
   { desc:     'a two-property two-keyframe sequence',
     frames:   [ { offset: 0, left: '10px', top: '30px' },
                 { offset: 1, left: '20px', top: '40px' } ],
     expected: [ { property: 'left',
-                  values: [ value(0, '10px', 'replace', 'linear'),
-                            value(1, '20px', 'replace') ] },
+                  values: [ valueFormat(0, '10px', 'replace', 'linear'),
+                            valueFormat(1, '20px', 'replace') ] },
                 { property: 'top',
-                  values: [ value(0, '30px', 'replace', 'linear'),
-                            value(1, '40px', 'replace') ] } ]
+                  values: [ valueFormat(0, '30px', 'replace', 'linear'),
+                            valueFormat(1, '40px', 'replace') ] } ]
   },
   { desc:     'a one shorthand property two-keyframe sequence',
     frames:   [ { offset: 0, margin: '10px' },
                 { offset: 1, margin: '20px 30px 40px 50px' } ],
     expected: [ { property: 'margin-top',
-                  values: [ value(0, '10px', 'replace', 'linear'),
-                            value(1, '20px', 'replace') ] },
+                  values: [ valueFormat(0, '10px', 'replace', 'linear'),
+                            valueFormat(1, '20px', 'replace') ] },
                 { property: 'margin-right',
-                  values: [ value(0, '10px', 'replace', 'linear'),
-                            value(1, '30px', 'replace') ] },
+                  values: [ valueFormat(0, '10px', 'replace', 'linear'),
+                            valueFormat(1, '30px', 'replace') ] },
                 { property: 'margin-bottom',
-                  values: [ value(0, '10px', 'replace', 'linear'),
-                            value(1, '40px', 'replace') ] },
+                  values: [ valueFormat(0, '10px', 'replace', 'linear'),
+                            valueFormat(1, '40px', 'replace') ] },
                 { property: 'margin-left',
-                  values: [ value(0, '10px', 'replace', 'linear'),
-                            value(1, '50px', 'replace') ] } ]
+                  values: [ valueFormat(0, '10px', 'replace', 'linear'),
+                            valueFormat(1, '50px', 'replace') ] } ]
   },
   { desc:     'a two-property (a shorthand and one of its component longhands)'
               + ' two-keyframe sequence',
     frames:   [ { offset: 0, margin: '10px', marginTop: '20px' },
                 { offset: 1, marginTop: '70px',
                              margin: '30px 40px 50px 60px' } ],
     expected: [ { property: 'margin-top',
-                  values: [ value(0, '20px', 'replace', 'linear'),
-                            value(1, '70px', 'replace') ] },
+                  values: [ valueFormat(0, '20px', 'replace', 'linear'),
+                            valueFormat(1, '70px', 'replace') ] },
                 { property: 'margin-right',
-                  values: [ value(0, '10px', 'replace', 'linear'),
-                            value(1, '40px', 'replace') ] },
+                  values: [ valueFormat(0, '10px', 'replace', 'linear'),
+                            valueFormat(1, '40px', 'replace') ] },
                 { property: 'margin-bottom',
-                  values: [ value(0, '10px', 'replace', 'linear'),
-                            value(1, '50px', 'replace') ] },
+                  values: [ valueFormat(0, '10px', 'replace', 'linear'),
+                            valueFormat(1, '50px', 'replace') ] },
                 { property: 'margin-left',
-                  values: [ value(0, '10px', 'replace', 'linear'),
-                            value(1, '60px', 'replace') ] } ]
+                  values: [ valueFormat(0, '10px', 'replace', 'linear'),
+                            valueFormat(1, '60px', 'replace') ] } ]
   },
   { desc:     'a keyframe sequence with duplicate values for a given interior'
               + ' offset',
     frames:   [ { 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' } ],
     expected: [ { property: 'left',
-                  values: [ value(0, '10px', 'replace', 'linear'),
-                            value(0.5, '20px', 'replace'),
-                            value(0.5, '40px', 'replace', 'linear'),
-                            value(1, '50px', 'replace') ] } ]
+                  values: [ valueFormat(0, '10px', 'replace', 'linear'),
+                            valueFormat(0.5, '20px', 'replace'),
+                            valueFormat(0.5, '40px', 'replace', 'linear'),
+                            valueFormat(1, '50px', 'replace') ] } ]
   },
   { desc:     'a keyframe sequence with duplicate values for offsets 0 and 1',
     frames:   [ { offset: 0, left: '10px' },
                 { offset: 0, left: '20px' },
                 { offset: 0, left: '30px' },
                 { offset: 1, left: '40px' },
                 { offset: 1, left: '50px' },
                 { offset: 1, left: '60px' } ],
     expected: [ { property: 'left',
-                  values: [ value(0, '10px', 'replace'),
-                            value(0, '30px', 'replace', 'linear'),
-                            value(1, '40px', 'replace'),
-                            value(1, '60px', 'replace') ] } ]
+                  values: [ valueFormat(0, '10px', 'replace'),
+                            valueFormat(0, '30px', 'replace', 'linear'),
+                            valueFormat(1, '40px', 'replace'),
+                            valueFormat(1, '60px', 'replace') ] } ]
   },
   { desc:     'a two-property four-keyframe sequence',
     frames:   [ { offset: 0, left: '10px' },
                 { offset: 0, top: '20px' },
                 { offset: 1, top: '30px' },
                 { offset: 1, left: '40px' } ],
     expected: [ { property: 'left',
-                  values: [ value(0, '10px', 'replace', 'linear'),
-                            value(1, '40px', 'replace') ] },
+                  values: [ valueFormat(0, '10px', 'replace', 'linear'),
+                            valueFormat(1, '40px', 'replace') ] },
                 { property: 'top',
-                  values: [ value(0, '20px', 'replace', 'linear'),
-                            value(1, '30px', 'replace') ] } ]
+                  values: [ valueFormat(0, '20px', 'replace', 'linear'),
+                            valueFormat(1, '30px', 'replace') ] } ]
   },
   { desc:     'a one-property keyframe sequence with some omitted offsets',
     frames:   [ { offset: 0.00, left: '10px' },
                 { offset: 0.25, left: '20px' },
                 { left: '30px' },
                 { left: '40px' },
                 { offset: 1.00, left: '50px' } ],
     expected: [ { property: 'left',
-                  values: [ value(0, '10px', 'replace', 'linear'),
-                            value(0.25, '20px', 'replace', 'linear'),
-                            value(0.5, '30px', 'replace', 'linear'),
-                            value(0.75, '40px', 'replace', 'linear'),
-                            value(1, '50px', 'replace') ] } ]
+                  values: [ valueFormat(0, '10px', 'replace', 'linear'),
+                            valueFormat(0.25, '20px', 'replace', 'linear'),
+                            valueFormat(0.5, '30px', 'replace', 'linear'),
+                            valueFormat(0.75, '40px', 'replace', 'linear'),
+                            valueFormat(1, '50px', 'replace') ] } ]
   },
   { desc:     'a two-property keyframe sequence with some omitted offsets',
     frames:   [ { 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' } ],
     expected: [ { property: 'left',
-                  values: [ value(0, '10px', 'replace', 'linear'),
-                            value(0.25, '30px', 'replace', 'linear'),
-                            value(0.5, '40px', 'replace', 'linear'),
-                            value(0.75, '50px', 'replace', 'linear'),
-                            value(1, '70px', 'replace') ] },
+                  values: [ valueFormat(0, '10px', 'replace', 'linear'),
+                            valueFormat(0.25, '30px', 'replace', 'linear'),
+                            valueFormat(0.5, '40px', 'replace', 'linear'),
+                            valueFormat(0.75, '50px', 'replace', 'linear'),
+                            valueFormat(1, '70px', 'replace') ] },
                 { property: 'top',
-                  values: [ value(0, '20px', 'replace', 'linear'),
-                            value(0.75, '60px', 'replace', 'linear'),
-                            value(1, '80px', 'replace') ] } ]
+                  values: [ valueFormat(0, '20px', 'replace', 'linear'),
+                            valueFormat(0.75, '60px', 'replace', 'linear'),
+                            valueFormat(1, '80px', 'replace') ] } ]
   },
   { desc:     'a one-property keyframe sequence with all omitted offsets',
     frames:   [ { left: '10px' },
                 { left: '20px' },
                 { left: '30px' },
                 { left: '40px' },
                 { left: '50px' } ],
     expected: [ { property: 'left',
-                  values: [ value(0, '10px', 'replace', 'linear'),
-                            value(0.25, '20px', 'replace', 'linear'),
-                            value(0.5, '30px', 'replace', 'linear'),
-                            value(0.75, '40px', 'replace', 'linear'),
-                            value(1, '50px', 'replace') ] } ]
+                  values: [ valueFormat(0, '10px', 'replace', 'linear'),
+                            valueFormat(0.25, '20px', 'replace', 'linear'),
+                            valueFormat(0.5, '30px', 'replace', 'linear'),
+                            valueFormat(0.75, '40px', 'replace', 'linear'),
+                            valueFormat(1, '50px', 'replace') ] } ]
   },
   { desc:     'a keyframe sequence with different easing values, but the'
               + ' same easing value for a given offset',
     frames:   [ { 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' } ],
     expected: [ { property: 'left',
-                  values: [ value(0, '10px', 'replace', 'ease'),
-                            value(0.5, '30px', 'replace', 'linear'),
-                            value(1, '50px', 'replace') ] },
+                  values: [ valueFormat(0, '10px', 'replace', 'ease'),
+                            valueFormat(0.5, '30px', 'replace', 'linear'),
+                            valueFormat(1, '50px', 'replace') ] },
                 { property: 'top',
-                  values: [ value(0, '20px', 'replace', 'ease'),
-                            value(0.5, '40px', 'replace', 'linear'),
-                            value(1, '60px', 'replace') ] } ]
+                  values: [ valueFormat(0, '20px', 'replace', 'ease'),
+                            valueFormat(0.5, '40px', 'replace', 'linear'),
+                            valueFormat(1, '60px', 'replace') ] } ]
   },
   { desc:     'a one-property two-keyframe sequence that needs to'
               + ' stringify its values',
     frames:   [ { offset: 0, opacity: 0 },
                 { offset: 1, opacity: 1 } ],
     expected: [ { property: 'opacity',
-                  values: [ value(0, '0', 'replace', 'linear'),
-                            value(1, '1', 'replace') ] } ]
+                  values: [ valueFormat(0, '0', 'replace', 'linear'),
+                            valueFormat(1, '1', 'replace') ] } ]
   },
   { desc:     'a keyframe sequence where shorthand precedes longhand',
     frames:   [ { offset: 0, margin: '10px', marginRight: '20px' },
                 { offset: 1, margin: '30px' } ],
     expected: [ { property: 'margin-top',
-                  values: [ value(0, '10px', 'replace', 'linear'),
-                            value(1, '30px', 'replace') ] },
+                  values: [ valueFormat(0, '10px', 'replace', 'linear'),
+                            valueFormat(1, '30px', 'replace') ] },
                 { property: 'margin-right',
-                  values: [ value(0, '20px', 'replace', 'linear'),
-                            value(1, '30px', 'replace') ] },
+                  values: [ valueFormat(0, '20px', 'replace', 'linear'),
+                            valueFormat(1, '30px', 'replace') ] },
                 { property: 'margin-bottom',
-                  values: [ value(0, '10px', 'replace', 'linear'),
-                            value(1, '30px', 'replace') ] },
+                  values: [ valueFormat(0, '10px', 'replace', 'linear'),
+                            valueFormat(1, '30px', 'replace') ] },
                 { property: 'margin-left',
-                  values: [ value(0, '10px', 'replace', 'linear'),
-                            value(1, '30px', 'replace') ] } ]
+                  values: [ valueFormat(0, '10px', 'replace', 'linear'),
+                            valueFormat(1, '30px', 'replace') ] } ]
   },
   { desc:     'a keyframe sequence where longhand precedes shorthand',
     frames:   [ { offset: 0, marginRight: '20px', margin: '10px' },
                 { offset: 1, margin: '30px' } ],
     expected: [ { property: 'margin-top',
-                  values: [ value(0, '10px', 'replace', 'linear'),
-                            value(1, '30px', 'replace') ] },
+                  values: [ valueFormat(0, '10px', 'replace', 'linear'),
+                            valueFormat(1, '30px', 'replace') ] },
                 { property: 'margin-right',
-                  values: [ value(0, '20px', 'replace', 'linear'),
-                            value(1, '30px', 'replace') ] },
+                  values: [ valueFormat(0, '20px', 'replace', 'linear'),
+                            valueFormat(1, '30px', 'replace') ] },
                 { property: 'margin-bottom',
-                  values: [ value(0, '10px', 'replace', 'linear'),
-                            value(1, '30px', 'replace') ] },
+                  values: [ valueFormat(0, '10px', 'replace', 'linear'),
+                            valueFormat(1, '30px', 'replace') ] },
                 { property: 'margin-left',
-                  values: [ value(0, '10px', 'replace', 'linear'),
-                            value(1, '30px', 'replace') ] } ]
+                  values: [ valueFormat(0, '10px', 'replace', 'linear'),
+                            valueFormat(1, '30px', 'replace') ] } ]
   },
   { desc:     'a keyframe sequence where lesser shorthand precedes greater'
               + ' shorthand',
     frames:   [ { 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)' } ],
     expected: [ { property: 'border-bottom-color',
-                  values: [ value(0, 'rgb(4, 5, 6)', 'replace', 'linear'),
-                            value(1, 'rgb(7, 8, 9)', 'replace') ] },
+                  values: [ valueFormat(0, 'rgb(4, 5, 6)', 'replace', 'linear'),
+                            valueFormat(1, 'rgb(7, 8, 9)', 'replace') ] },
                 { property: 'border-left-color',
-                  values: [ value(0, 'rgb(1, 2, 3)', 'replace', 'linear'),
-                            value(1, 'rgb(7, 8, 9)', 'replace') ] },
+                  values: [ valueFormat(0, 'rgb(1, 2, 3)', 'replace', 'linear'),
+                            valueFormat(1, 'rgb(7, 8, 9)', 'replace') ] },
                 { property: 'border-right-color',
-                  values: [ value(0, 'rgb(4, 5, 6)', 'replace', 'linear'),
-                            value(1, 'rgb(7, 8, 9)', 'replace') ] },
+                  values: [ valueFormat(0, 'rgb(4, 5, 6)', 'replace', 'linear'),
+                            valueFormat(1, 'rgb(7, 8, 9)', 'replace') ] },
                 { property: 'border-top-color',
-                  values: [ value(0, 'rgb(4, 5, 6)', 'replace', 'linear'),
-                            value(1, 'rgb(7, 8, 9)', 'replace') ] },
+                  values: [ valueFormat(0, 'rgb(4, 5, 6)', 'replace', 'linear'),
+                            valueFormat(1, 'rgb(7, 8, 9)', 'replace') ] },
                 { property: 'border-bottom-width',
-                  values: [ value(0, '2px', 'replace', 'linear'),
-                            value(1, '3px', 'replace') ] },
+                  values: [ valueFormat(0, '2px', 'replace', 'linear'),
+                            valueFormat(1, '3px', 'replace') ] },
                 { property: 'border-left-width',
-                  values: [ value(0, '1px', 'replace', 'linear'),
-                            value(1, '3px', 'replace') ] },
+                  values: [ valueFormat(0, '1px', 'replace', 'linear'),
+                            valueFormat(1, '3px', 'replace') ] },
                 { property: 'border-right-width',
-                  values: [ value(0, '2px', 'replace', 'linear'),
-                            value(1, '3px', 'replace') ] },
+                  values: [ valueFormat(0, '2px', 'replace', 'linear'),
+                            valueFormat(1, '3px', 'replace') ] },
                 { property: 'border-top-width',
-                  values: [ value(0, '2px', 'replace', 'linear'),
-                            value(1, '3px', 'replace') ] },
+                  values: [ valueFormat(0, '2px', 'replace', 'linear'),
+                            valueFormat(1, '3px', 'replace') ] },
                 { property: 'border-bottom-style',
-                  values: [ value(0, 'dotted', 'replace', 'linear'),
-                            value(1, 'dashed', 'replace') ] },
+                  values: [ valueFormat(0, 'dotted', 'replace', 'linear'),
+                            valueFormat(1, 'dashed', 'replace') ] },
                 { property: 'border-left-style',
-                  values: [ value(0, 'solid', 'replace', 'linear'),
-                            value(1, 'dashed', 'replace') ] },
+                  values: [ valueFormat(0, 'solid', 'replace', 'linear'),
+                            valueFormat(1, 'dashed', 'replace') ] },
                 { property: 'border-right-style',
-                  values: [ value(0, 'dotted', 'replace', 'linear'),
-                            value(1, 'dashed', 'replace') ] },
+                  values: [ valueFormat(0, 'dotted', 'replace', 'linear'),
+                            valueFormat(1, 'dashed', 'replace') ] },
                 { property: 'border-top-style',
-                  values: [ value(0, 'dotted', 'replace', 'linear'),
-                            value(1, 'dashed', 'replace') ] },
+                  values: [ valueFormat(0, 'dotted', 'replace', 'linear'),
+                            valueFormat(1, 'dashed', 'replace') ] },
                 { property: 'border-image-outset',
-                  values: [ value(0, '0 0 0 0', 'replace', 'linear'),
-                            value(1, '0 0 0 0', 'replace') ] },
+                  values: [ valueFormat(0, '0 0 0 0', 'replace', 'linear'),
+                            valueFormat(1, '0 0 0 0', 'replace') ] },
                 { property: 'border-image-repeat',
-                  values: [ value(0, 'stretch stretch', 'replace', 'linear'),
-                            value(1, 'stretch stretch', 'replace') ] },
+                  values: [ valueFormat(0,
+                                        'stretch stretch', 'replace', 'linear'),
+                            valueFormat(1, 'stretch stretch', 'replace') ] },
                 { property: 'border-image-slice',
-                  values: [ value(0, '100% 100% 100% 100%',
+                  values: [ valueFormat(0, '100% 100% 100% 100%',
                                   'replace', 'linear'),
-                            value(1, '100% 100% 100% 100%', 'replace') ] },
+                            valueFormat(1,
+                                        '100% 100% 100% 100%', 'replace') ] },
                 { property: 'border-image-source',
-                  values: [ value(0, 'none', 'replace', 'linear'),
-                            value(1, 'none', 'replace') ] },
+                  values: [ valueFormat(0, 'none', 'replace', 'linear'),
+                            valueFormat(1, 'none', 'replace') ] },
                 { property: 'border-image-width',
-                  values: [ value(0, '1 1 1 1', 'replace', 'linear'),
-                            value(1, '1 1 1 1', 'replace') ] },
+                  values: [ valueFormat(0, '1 1 1 1', 'replace', 'linear'),
+                            valueFormat(1, '1 1 1 1', 'replace') ] },
                 { property: '-moz-border-bottom-colors',
-                  values: [ value(0, 'none', 'replace', 'linear'),
-                            value(1, 'none', 'replace') ] },
+                  values: [ valueFormat(0, 'none', 'replace', 'linear'),
+                            valueFormat(1, 'none', 'replace') ] },
                 { property: '-moz-border-left-colors',
-                  values: [ value(0, 'none', 'replace', 'linear'),
-                            value(1, 'none', 'replace') ] },
+                  values: [ valueFormat(0, 'none', 'replace', 'linear'),
+                            valueFormat(1, 'none', 'replace') ] },
                 { property: '-moz-border-right-colors',
-                  values: [ value(0, 'none', 'replace', 'linear'),
-                            value(1, 'none', 'replace') ] },
+                  values: [ valueFormat(0, 'none', 'replace', 'linear'),
+                            valueFormat(1, 'none', 'replace') ] },
                 { property: '-moz-border-top-colors',
-                  values: [ value(0, 'none', 'replace', 'linear'),
-                            value(1, 'none', 'replace') ] } ]
+                  values: [ valueFormat(0, 'none', 'replace', 'linear'),
+                            valueFormat(1, 'none', 'replace') ] } ]
   },
   { desc:     'a keyframe sequence where greater shorthand precedes'
               + ' lesser shorthand',
     frames:   [ { 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)' } ],
     expected: [ { property: 'border-bottom-color',
-                  values: [ value(0, 'rgb(4, 5, 6)', 'replace', 'linear'),
-                            value(1, 'rgb(7, 8, 9)', 'replace') ] },
+                  values: [ valueFormat(0, 'rgb(4, 5, 6)', 'replace', 'linear'),
+                            valueFormat(1, 'rgb(7, 8, 9)', 'replace') ] },
                 { property: 'border-left-color',
-                  values: [ value(0, 'rgb(1, 2, 3)', 'replace', 'linear'),
-                            value(1, 'rgb(7, 8, 9)', 'replace') ] },
+                  values: [ valueFormat(0, 'rgb(1, 2, 3)', 'replace', 'linear'),
+                            valueFormat(1, 'rgb(7, 8, 9)', 'replace') ] },
                 { property: 'border-right-color',
-                  values: [ value(0, 'rgb(4, 5, 6)', 'replace', 'linear'),
-                            value(1, 'rgb(7, 8, 9)', 'replace') ] },
+                  values: [ valueFormat(0, 'rgb(4, 5, 6)', 'replace', 'linear'),
+                            valueFormat(1, 'rgb(7, 8, 9)', 'replace') ] },
                 { property: 'border-top-color',
-                  values: [ value(0, 'rgb(4, 5, 6)', 'replace', 'linear'),
-                            value(1, 'rgb(7, 8, 9)', 'replace') ] },
+                  values: [ valueFormat(0, 'rgb(4, 5, 6)', 'replace', 'linear'),
+                            valueFormat(1, 'rgb(7, 8, 9)', 'replace') ] },
                 { property: 'border-bottom-width',
-                  values: [ value(0, '2px', 'replace', 'linear'),
-                            value(1, '3px', 'replace') ] },
+                  values: [ valueFormat(0, '2px', 'replace', 'linear'),
+                            valueFormat(1, '3px', 'replace') ] },
                 { property: 'border-left-width',
-                  values: [ value(0, '1px', 'replace', 'linear'),
-                            value(1, '3px', 'replace') ] },
+                  values: [ valueFormat(0, '1px', 'replace', 'linear'),
+                            valueFormat(1, '3px', 'replace') ] },
                 { property: 'border-right-width',
-                  values: [ value(0, '2px', 'replace', 'linear'),
-                            value(1, '3px', 'replace') ] },
+                  values: [ valueFormat(0, '2px', 'replace', 'linear'),
+                            valueFormat(1, '3px', 'replace') ] },
                 { property: 'border-top-width',
-                  values: [ value(0, '2px', 'replace', 'linear'),
-                            value(1, '3px', 'replace') ] },
+                  values: [ valueFormat(0, '2px', 'replace', 'linear'),
+                            valueFormat(1, '3px', 'replace') ] },
                 { property: 'border-bottom-style',
-                  values: [ value(0, 'dotted', 'replace', 'linear'),
-                            value(1, 'dashed', 'replace') ] },
+                  values: [ valueFormat(0, 'dotted', 'replace', 'linear'),
+                            valueFormat(1, 'dashed', 'replace') ] },
                 { property: 'border-left-style',
-                  values: [ value(0, 'solid', 'replace', 'linear'),
-                            value(1, 'dashed', 'replace') ] },
+                  values: [ valueFormat(0, 'solid', 'replace', 'linear'),
+                            valueFormat(1, 'dashed', 'replace') ] },
                 { property: 'border-right-style',
-                  values: [ value(0, 'dotted', 'replace', 'linear'),
-                            value(1, 'dashed', 'replace') ] },
+                  values: [ valueFormat(0, 'dotted', 'replace', 'linear'),
+                            valueFormat(1, 'dashed', 'replace') ] },
                 { property: 'border-top-style',
-                  values: [ value(0, 'dotted', 'replace', 'linear'),
-                            value(1, 'dashed', 'replace') ] },
+                  values: [ valueFormat(0, 'dotted', 'replace', 'linear'),
+                            valueFormat(1, 'dashed', 'replace') ] },
                 { property: 'border-image-outset',
-                  values: [ value(0, '0 0 0 0', 'replace', 'linear'),
-                            value(1, '0 0 0 0', 'replace') ] },
+                  values: [ valueFormat(0, '0 0 0 0', 'replace', 'linear'),
+                            valueFormat(1, '0 0 0 0', 'replace') ] },
                 { property: 'border-image-repeat',
-                  values: [ value(0, 'stretch stretch', 'replace', 'linear'),
-                            value(1, 'stretch stretch', 'replace') ] },
+                  values: [ valueFormat(0,
+                                        'stretch stretch', 'replace', 'linear'),
+                            valueFormat(1, 'stretch stretch', 'replace') ] },
                 { property: 'border-image-slice',
-                  values: [ value(0, '100% 100% 100% 100%',
+                  values: [ valueFormat(0, '100% 100% 100% 100%',
                                   'replace', 'linear'),
-                            value(1, '100% 100% 100% 100%', 'replace') ] },
+                            valueFormat(1,
+                                        '100% 100% 100% 100%', 'replace') ] },
                 { property: 'border-image-source',
-                  values: [ value(0, 'none', 'replace', 'linear'),
-                            value(1, 'none', 'replace') ] },
+                  values: [ valueFormat(0, 'none', 'replace', 'linear'),
+                            valueFormat(1, 'none', 'replace') ] },
                 { property: 'border-image-width',
-                  values: [ value(0, '1 1 1 1', 'replace', 'linear'),
-                            value(1, '1 1 1 1', 'replace') ] },
+                  values: [ valueFormat(0, '1 1 1 1', 'replace', 'linear'),
+                            valueFormat(1, '1 1 1 1', 'replace') ] },
                 { property: '-moz-border-bottom-colors',
-                  values: [ value(0, 'none', 'replace', 'linear'),
-                            value(1, 'none', 'replace') ] },
+                  values: [ valueFormat(0, 'none', 'replace', 'linear'),
+                            valueFormat(1, 'none', 'replace') ] },
                 { property: '-moz-border-left-colors',
-                  values: [ value(0, 'none', 'replace', 'linear'),
-                            value(1, 'none', 'replace') ] },
+                  values: [ valueFormat(0, 'none', 'replace', 'linear'),
+                            valueFormat(1, 'none', 'replace') ] },
                 { property: '-moz-border-right-colors',
-                  values: [ value(0, 'none', 'replace', 'linear'),
-                            value(1, 'none', 'replace') ] },
+                  values: [ valueFormat(0, 'none', 'replace', 'linear'),
+                            valueFormat(1, 'none', 'replace') ] },
                 { property: '-moz-border-top-colors',
-                  values: [ value(0, 'none', 'replace', 'linear'),
-                            value(1, 'none', 'replace') ] } ]
+                  values: [ valueFormat(0, 'none', 'replace', 'linear'),
+                            valueFormat(1, 'none', 'replace') ] } ]
   },
 
   // ---------------------------------------------------------------------
   //
   // Tests for unit conversion
   //
   // ---------------------------------------------------------------------
 
   { desc:     'em units are resolved to px values',
     frames:   { left: ['10em', '20em'] },
     expected: [ { property: 'left',
-                  values: [ value(0, '100px', 'replace', 'linear'),
-                            value(1, '200px', 'replace') ] } ]
+                  values: [ valueFormat(0, '100px', 'replace', 'linear'),
+                            valueFormat(1, '200px', 'replace') ] } ]
   },
   { desc:     'calc() expressions are resolved to the equivalent units',
     frames:   { left: ['calc(10em + 10px)', 'calc(10em + 10%)'] },
     expected: [ { property: 'left',
-                  values: [ value(0, 'calc(110px)', 'replace', 'linear'),
-                            value(1, 'calc(100px + 10%)', 'replace') ] } ]
+                  values: [ valueFormat(0, 'calc(110px)', 'replace', 'linear'),
+                            valueFormat(1, 'calc(100px + 10%)', 'replace') ] } ]
   },
 
   // ---------------------------------------------------------------------
   //
   // Tests for CSS variable handling conversion
   //
   // ---------------------------------------------------------------------
 
   { desc:     'CSS variables are resolved to their corresponding values',
     frames:   { left: ['10px', 'var(--var-100px)'] },
     expected: [ { property: 'left',
-                  values: [ value(0, '10px', 'replace', 'linear'),
-                            value(1, '100px', 'replace') ] } ]
+                  values: [ valueFormat(0, '10px', 'replace', 'linear'),
+                            valueFormat(1, '100px', 'replace') ] } ]
   },
   { desc:     'CSS variables in calc() expressions are resolved',
     frames:   { left: ['10px', 'calc(var(--var-100px) / 2 - 10%)'] },
     expected: [ { property: 'left',
-                  values: [ value(0, '10px', 'replace', 'linear'),
-                            value(1, 'calc(50px + -10%)', 'replace') ] } ]
+                  values: [ valueFormat(0, '10px', 'replace', 'linear'),
+                            valueFormat(1, 'calc(50px + -10%)', 'replace') ] } ]
   },
   { desc:     'CSS variables in shorthands are resolved to their corresponding'
               + ' values',
     frames:   { margin: ['10px', 'var(--var-100px-200px)'] },
     expected: [ { property: 'margin-top',
-                  values: [ value(0, '10px', 'replace', 'linear'),
-                            value(1, '100px', 'replace') ] },
+                  values: [ valueFormat(0, '10px', 'replace', 'linear'),
+                            valueFormat(1, '100px', 'replace') ] },
                 { property: 'margin-right',
-                  values: [ value(0, '10px', 'replace', 'linear'),
-                            value(1, '200px', 'replace') ] },
+                  values: [ valueFormat(0, '10px', 'replace', 'linear'),
+                            valueFormat(1, '200px', 'replace') ] },
                 { property: 'margin-bottom',
-                  values: [ value(0, '10px', 'replace', 'linear'),
-                            value(1, '100px', 'replace') ] },
+                  values: [ valueFormat(0, '10px', 'replace', 'linear'),
+                            valueFormat(1, '100px', 'replace') ] },
                 { property: 'margin-left',
-                  values: [ value(0, '10px', 'replace', 'linear'),
-                            value(1, '200px', 'replace') ] } ]
+                  values: [ valueFormat(0, '10px', 'replace', 'linear'),
+                            valueFormat(1, '200px', 'replace') ] } ]
   },
 
   // ---------------------------------------------------------------------
   //
   // Tests for properties that parse correctly but which we fail to
   // convert to computed values.
   //
   // ---------------------------------------------------------------------
 
   { desc:     'a missing property in initial keyframe',
     frames:   [ { },
                 { margin: '5px' } ],
     expected: [ { property: 'margin-top',
-                  values: [ value(0, undefined, 'add', 'linear'),
-                            value(1, '5px', 'replace') ] },
+                  values: [ valueFormat(0, undefined, 'add', 'linear'),
+                            valueFormat(1, '5px', 'replace') ] },
                 { property: 'margin-right',
-                  values: [ value(0, undefined, 'add', 'linear'),
-                            value(1, '5px', 'replace') ] },
+                  values: [ valueFormat(0, undefined, 'add', 'linear'),
+                            valueFormat(1, '5px', 'replace') ] },
                 { property: 'margin-bottom',
-                  values: [ value(0, undefined, 'add', 'linear'),
-                            value(1, '5px', 'replace') ] },
+                  values: [ valueFormat(0, undefined, 'add', 'linear'),
+                            valueFormat(1, '5px', 'replace') ] },
                 { property: 'margin-left',
-                  values: [ value(0, undefined, 'add', 'linear'),
-                            value(1, '5px', 'replace') ] } ]
+                  values: [ valueFormat(0, undefined, 'add', 'linear'),
+                            valueFormat(1, '5px', 'replace') ] } ]
   },
   { desc:     'a missing property in initial keyframe and there are some ' +
               'keyframes with the same offset',
     frames:   [ { },
                 { margin: '10px', offset: 0.5 },
                 { margin: '20px', offset: 0.5 },
                 { margin: '30px'} ],
     expected: [ { property: 'margin-top',
-                  values: [ value(0, undefined, 'add', 'linear'),
-                            value(0.5, '10px', 'replace'),
-                            value(0.5, '20px', 'replace', 'linear'),
-                            value(1,   '30px', 'replace') ] },
+                  values: [ valueFormat(0, undefined, 'add', 'linear'),
+                            valueFormat(0.5, '10px', 'replace'),
+                            valueFormat(0.5, '20px', 'replace', 'linear'),
+                            valueFormat(1,   '30px', 'replace') ] },
                 { property: 'margin-right',
-                  values: [ value(0, undefined, 'add', 'linear'),
-                            value(0.5, '10px', 'replace'),
-                            value(0.5, '20px', 'replace', 'linear'),
-                            value(1,   '30px', 'replace') ] },
+                  values: [ valueFormat(0, undefined, 'add', 'linear'),
+                            valueFormat(0.5, '10px', 'replace'),
+                            valueFormat(0.5, '20px', 'replace', 'linear'),
+                            valueFormat(1,   '30px', 'replace') ] },
                 { property: 'margin-bottom',
-                  values: [ value(0, undefined, 'add', 'linear'),
-                            value(0.5, '10px', 'replace'),
-                            value(0.5, '20px', 'replace', 'linear'),
-                            value(1,   '30px', 'replace') ] },
+                  values: [ valueFormat(0, undefined, 'add', 'linear'),
+                            valueFormat(0.5, '10px', 'replace'),
+                            valueFormat(0.5, '20px', 'replace', 'linear'),
+                            valueFormat(1,   '30px', 'replace') ] },
                 { property: 'margin-left',
-                  values: [ value(0, undefined, 'add', 'linear'),
-                            value(0.5, '10px', 'replace'),
-                            value(0.5, '20px', 'replace', 'linear'),
-                            value(1,   '30px', 'replace') ] } ]
+                  values: [ valueFormat(0, undefined, 'add', 'linear'),
+                            valueFormat(0.5, '10px', 'replace'),
+                            valueFormat(0.5, '20px', 'replace', 'linear'),
+                            valueFormat(1,   '30px', 'replace') ] } ]
   },
   { desc:     'a missing property in final keyframe',
     frames:   [ { margin: '5px' },
                 { } ],
     expected: [ { property: 'margin-top',
-                  values: [ value(0, '5px', 'replace', 'linear'),
-                            value(1, undefined, 'add') ] },
+                  values: [ valueFormat(0, '5px', 'replace', 'linear'),
+                            valueFormat(1, undefined, 'add') ] },
                 { property: 'margin-right',
-                  values: [ value(0, '5px', 'replace', 'linear'),
-                            value(1, undefined, 'add') ] },
+                  values: [ valueFormat(0, '5px', 'replace', 'linear'),
+                            valueFormat(1, undefined, 'add') ] },
                 { property: 'margin-bottom',
-                  values: [ value(0, '5px', 'replace', 'linear'),
-                            value(1, undefined, 'add') ] },
+                  values: [ valueFormat(0, '5px', 'replace', 'linear'),
+                            valueFormat(1, undefined, 'add') ] },
                 { property: 'margin-left',
-                  values: [ value(0, '5px', 'replace', 'linear'),
-                            value(1, undefined, 'add') ] } ]
+                  values: [ valueFormat(0, '5px', 'replace', 'linear'),
+                            valueFormat(1, undefined, 'add') ] } ]
   },
   { desc:     'a missing property in final keyframe and there are some ' +
               'keyframes with the same offsets',
     frames:   [ { margin: '5px' },
                 { margin: '10px', offset: 0.5 },
                 { margin: '20px', offset: 0.5 },
                 { } ],
     expected: [ { property: 'margin-top',
-                  values: [ value(0,   '5px', 'replace', 'linear'),
-                            value(0.5, '10px', 'replace'),
-                            value(0.5, '20px', 'replace', 'linear'),
-                            value(1,   undefined, 'add') ] },
+                  values: [ valueFormat(0,   '5px', 'replace', 'linear'),
+                            valueFormat(0.5, '10px', 'replace'),
+                            valueFormat(0.5, '20px', 'replace', 'linear'),
+                            valueFormat(1,   undefined, 'add') ] },
                 { property: 'margin-right',
-                  values: [ value(0, '5px', 'replace', 'linear'),
-                            value(0.5, '10px', 'replace'),
-                            value(0.5, '20px', 'replace', 'linear'),
-                            value(1, undefined, 'add') ] },
+                  values: [ valueFormat(0, '5px', 'replace', 'linear'),
+                            valueFormat(0.5, '10px', 'replace'),
+                            valueFormat(0.5, '20px', 'replace', 'linear'),
+                            valueFormat(1, undefined, 'add') ] },
                 { property: 'margin-bottom',
-                  values: [ value(0, '5px', 'replace', 'linear'),
-                            value(0.5, '10px', 'replace'),
-                            value(0.5, '20px', 'replace', 'linear'),
-                            value(1, undefined, 'add') ] },
+                  values: [ valueFormat(0, '5px', 'replace', 'linear'),
+                            valueFormat(0.5, '10px', 'replace'),
+                            valueFormat(0.5, '20px', 'replace', 'linear'),
+                            valueFormat(1, undefined, 'add') ] },
                 { property: 'margin-left',
-                  values: [ value(0, '5px', 'replace', 'linear'),
-                            value(0.5, '10px', 'replace'),
-                            value(0.5, '20px', 'replace', 'linear'),
-                            value(1, undefined, 'add') ] } ]
+                  values: [ valueFormat(0, '5px', 'replace', 'linear'),
+                            valueFormat(0.5, '10px', 'replace'),
+                            valueFormat(0.5, '20px', 'replace', 'linear'),
+                            valueFormat(1, undefined, 'add') ] } ]
   },
   { desc:     'a missing property in final keyframe where it forms the last'
               + ' segment in the series',
     frames:   [ { margin: '5px' },
                 { marginLeft: '5px',
                   marginRight: '5px',
                   marginBottom: '5px' } ],
     expected: [ { property: 'margin-bottom',
-                  values: [ value(0, '5px', 'replace', 'linear'),
-                            value(1, '5px', 'replace') ] },
+                  values: [ valueFormat(0, '5px', 'replace', 'linear'),
+                            valueFormat(1, '5px', 'replace') ] },
                 { property: 'margin-left',
-                  values: [ value(0, '5px', 'replace', 'linear'),
-                            value(1, '5px', 'replace') ] },
+                  values: [ valueFormat(0, '5px', 'replace', 'linear'),
+                            valueFormat(1, '5px', 'replace') ] },
                 { property: 'margin-right',
-                  values: [ value(0, '5px', 'replace', 'linear'),
-                            value(1, '5px', 'replace') ] },
+                  values: [ valueFormat(0, '5px', 'replace', 'linear'),
+                            valueFormat(1, '5px', 'replace') ] },
                 { property: 'margin-top',
-                  values: [ value(0, '5px', 'replace', 'linear'),
-                            value(1, undefined, 'add') ] } ]
+                  values: [ valueFormat(0, '5px', 'replace', 'linear'),
+                            valueFormat(1, undefined, 'add') ] } ]
   },
   { desc:     'a missing property in initial keyframe along with other values',
     frames:   [ {                left: '10px' },
                 { margin: '5px', left: '20px' } ],
     expected: [ { property: 'left',
-                  values: [ value(0, '10px', 'replace', 'linear'),
-                            value(1, '20px', 'replace') ] },
+                  values: [ valueFormat(0, '10px', 'replace', 'linear'),
+                            valueFormat(1, '20px', 'replace') ] },
                 { property: 'margin-top',
-                  values: [ value(0, undefined, 'add', 'linear'),
-                            value(1, '5px', 'replace') ] },
+                  values: [ valueFormat(0, undefined, 'add', 'linear'),
+                            valueFormat(1, '5px', 'replace') ] },
                 { property: 'margin-right',
-                  values: [ value(0, undefined, 'add', 'linear'),
-                            value(1, '5px', 'replace') ] },
+                  values: [ valueFormat(0, undefined, 'add', 'linear'),
+                            valueFormat(1, '5px', 'replace') ] },
                 { property: 'margin-bottom',
-                  values: [ value(0, undefined, 'add', 'linear'),
-                            value(1, '5px', 'replace') ] },
+                  values: [ valueFormat(0, undefined, 'add', 'linear'),
+                            valueFormat(1, '5px', 'replace') ] },
                 { property: 'margin-left',
-                  values: [ value(0, undefined, 'add', 'linear'),
-                            value(1, '5px', 'replace') ] } ]
+                  values: [ valueFormat(0, undefined, 'add', 'linear'),
+                            valueFormat(1, '5px', 'replace') ] } ]
   },
   { desc:     'a missing property in final keyframe along with other values',
     frames:   [ { margin: '5px', left: '10px' },
                 {                left: '20px' } ],
     expected: [ { property: 'left',
-                  values: [ value(0, '10px', 'replace', 'linear'),
-                            value(1, '20px', 'replace') ] },
+                  values: [ valueFormat(0, '10px', 'replace', 'linear'),
+                            valueFormat(1, '20px', 'replace') ] },
                 { property: 'margin-top',
-                  values: [ value(0, '5px', 'replace', 'linear'),
-                            value(1, undefined, 'add') ] },
+                  values: [ valueFormat(0, '5px', 'replace', 'linear'),
+                            valueFormat(1, undefined, 'add') ] },
                 { property: 'margin-right',
-                  values: [ value(0, '5px', 'replace', 'linear'),
-                            value(1, undefined, 'add') ] },
+                  values: [ valueFormat(0, '5px', 'replace', 'linear'),
+                            valueFormat(1, undefined, 'add') ] },
                 { property: 'margin-bottom',
-                  values: [ value(0, '5px', 'replace', 'linear'),
-                            value(1, undefined, 'add') ] },
+                  values: [ valueFormat(0, '5px', 'replace', 'linear'),
+                            valueFormat(1, undefined, 'add') ] },
                 { property: 'margin-left',
-                  values: [ value(0, '5px', 'replace', 'linear'),
-                            value(1, undefined, 'add') ] } ]
+                  values: [ valueFormat(0, '5px', 'replace', 'linear'),
+                            valueFormat(1, undefined, 'add') ] } ]
   },
   { desc:     'missing properties in both of initial and final keyframe',
     frames:   [ { left: '5px', offset: 0.5 } ],
     expected: [ { property: 'left',
-                  values: [ value(0,   undefined, 'add',     'linear'),
-                            value(0.5, '5px',       'replace', 'linear'),
-                            value(1,   undefined, 'add') ] } ]
+                  values: [ valueFormat(0,   undefined, 'add',     'linear'),
+                            valueFormat(0.5, '5px',       'replace', 'linear'),
+                            valueFormat(1,   undefined, 'add') ] } ]
   },
   { desc:     'missing propertes in both of initial and final keyframe along '
               + 'with other values',
     frames:   [ { left:  '5px',  offset: 0 },
                 { right: '5px',  offset: 0.5 },
                 { left:  '10px', offset: 1 } ],
     expected: [ { property: 'left',
-                  values: [ value(0, '5px',  'replace', 'linear'),
-                            value(1, '10px', 'replace') ] },
+                  values: [ valueFormat(0, '5px',  'replace', 'linear'),
+                            valueFormat(1, '10px', 'replace') ] },
                 { property: 'right',
-                  values: [ value(0,   undefined, 'add',     'linear'),
-                            value(0.5, '5px',     'replace', 'linear'),
-                            value(1,   undefined, 'add') ] } ]
+                  values: [ valueFormat(0,   undefined, 'add',     'linear'),
+                            valueFormat(0.5, '5px',     'replace', 'linear'),
+                            valueFormat(1,   undefined, 'add') ] } ]
   },
 
   { desc:     'a missing property in final keyframe with duplicate offset ' +
               + 'along with other values',
     frames:   [ { left: '5px',  right: '5px', offset: 0 },
                 { left: '8px',  right: '8px', offset: 0 },
                 { left: '10px',               offset: 1 } ],
     expected: [ { property: 'left',
-                  values: [ value(0, '5px',  'replace'),
-                            value(0, '8px',  'replace', 'linear'),
-                            value(1, '10px', 'replace') ] },
+                  values: [ valueFormat(0, '5px',  'replace'),
+                            valueFormat(0, '8px',  'replace', 'linear'),
+                            valueFormat(1, '10px', 'replace') ] },
                 { property: 'right',
-                  values: [ value(0, '5px',     'replace'),
-                            value(0, '8px',     'replace', 'linear'),
-                            value(1, undefined, 'add') ] } ]
+                  values: [ valueFormat(0, '5px',     'replace'),
+                            valueFormat(0, '8px',     'replace', 'linear'),
+                            valueFormat(1, undefined, 'add') ] } ]
   },
 
   { desc:     'a missing property in initial keyframe with duplicate offset '
               + 'along with other values',
     frames:   [ { left: '10px',              offset: 0 },
                 { left: '8px', right: '8px', offset: 1 },
                 { left: '5px', right: '5px', offset: 1 } ],
     expected: [ { property: 'left',
-                  values: [ value(0, '10px', 'replace', 'linear'),
-                            value(1, '8px',  'replace'),
-                            value(1, '5px',  'replace') ] },
+                  values: [ valueFormat(0, '10px', 'replace', 'linear'),
+                            valueFormat(1, '8px',  'replace'),
+                            valueFormat(1, '5px',  'replace') ] },
                 { property: 'right',
-                  values: [ value(0, undefined, 'add', 'linear'),
-                            value(1, '8px',     'replace'),
-                            value(1, '5px',     'replace') ] } ]
+                  values: [ valueFormat(0, undefined, 'add', 'linear'),
+                            valueFormat(1, '8px',     'replace'),
+                            valueFormat(1, '5px',     'replace') ] } ]
   },
 ];
 
 SpecialPowers.pushPrefEnv(
   { set: [["dom.animations-api.core.enabled", true]] },
   function() {
     gTests.forEach(function(subtest) {
       test(function(t) {
new file mode 100644
--- /dev/null
+++ b/dom/animation/test/chrome/test_cssanimation_missing_keyframes.html
@@ -0,0 +1,73 @@
+<!doctype html>
+<head>
+<meta charset=utf-8>
+<title>Bug 1339332 - Test for missing keyframes in CSS Animation</title>
+<script type="application/javascript" src="../testharness.js"></script>
+<script type="application/javascript" src="../testharnessreport.js"></script>
+<script type="application/javascript" src="../testcommon.js"></script>
+</head>
+<body>
+<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1339332"
+   target="_blank">Mozilla Bug 1339332</a>
+<div id="log"></div>
+<style>
+@keyframes missingFrom {
+  to {
+    text-align: right;
+  }
+}
+@keyframes missingBoth {
+  50% {
+    text-align: right;
+  }
+}
+@keyframes missingTo {
+  from {
+    text-align: right;
+  }
+}
+</style>
+<script>
+'use strict';
+
+const gTests = [
+  { desc: 'missing "from" keyframe',
+    animationName: 'missingFrom',
+    expected: [{ property: 'text-align',
+                 values: [valueFormat(0, undefined, 'replace', 'ease'),
+                          valueFormat(1, 'right',   'replace')] } ]
+  },
+  { desc: 'missing "to" keyframe',
+    animationName: 'missingTo',
+    expected: [{ property: 'text-align',
+                 values: [valueFormat(0, 'right',   'replace', 'ease'),
+                          valueFormat(1, undefined, 'replace')] } ]
+  },
+  { desc: 'missing "from" and "to" keyframes',
+    animationName: 'missingBoth',
+    expected: [{ property: 'text-align',
+                 values: [valueFormat(0,  undefined, 'replace', 'ease'),
+                          valueFormat(.5, 'right',   'replace', 'ease'),
+                          valueFormat(1,  undefined, 'replace')] } ]
+  },
+];
+
+SpecialPowers.pushPrefEnv(
+  { set: [["dom.animations-api.core.enabled", true]] },
+  function() {
+    gTests.forEach(function(subtest) {
+      test(function(t) {
+        const div = addDiv(t);
+        div.style.animation = `${ subtest.animationName } 1000s`;
+        const animation = div.getAnimations()[0];
+        assert_properties_equal(animation.effect.getProperties(),
+                                subtest.expected);
+      }, subtest.desc);
+    });
+
+    done();
+  }
+);
+
+</script>
+</body>
--- a/dom/animation/test/testcommon.js
+++ b/dom/animation/test/testcommon.js
@@ -50,16 +50,65 @@ function assert_matrix_equals(actual, ex
   for (var i = 0; i < actualMatrixArray.length; i++) {
     assert_approx_equals(actualMatrixArray[i], expectedMatrixArray[i], 0.01,
       'Matrix array should be equal (got \'' + expected + '\' and \'' + actual +
       '\'): ' + description);
   }
 }
 
 /**
+ * Compare given values which are same format of
+ * KeyframeEffectReadonly::GetProperties.
+ */
+function assert_properties_equal(actual, expected) {
+  assert_equals(actual.length, expected.length);
+
+  const compareProperties = (a, b) =>
+    a.property == b.property ? 0 : (a.property < b.property ? -1 : 1);
+
+  const sortedActual   = actual.sort(compareProperties);
+  const sortedExpected = expected.sort(compareProperties);
+
+  const serializeValues = values =>
+    values.map(value =>
+      '{ ' +
+          [ 'offset', 'value', 'easing', 'composite' ].map(
+            member => `${member}: ${value[member]}`
+          ).join(', ') +
+                      ' }')
+          .join(', ');
+
+  for (let i = 0; i < sortedActual.length; i++) {
+    assert_equals(sortedActual[i].property,
+                  sortedExpected[i].property,
+                  'CSS property name should match');
+    assert_equals(serializeValues(sortedActual[i].values),
+                  serializeValues(sortedExpected[i].values),
+                  `Values arrays do not match for `
+                  + `${sortedActual[i].property} property`);
+  }
+}
+
+/**
+ * Construct a object which is same to a value of
+ * KeyframeEffectReadonly::GetProperties().
+ * The method returns undefined as a value in case of missing keyframe.
+ * Therefor, we can use undefined for |value| and |easing| parameter.
+ * @param offset - keyframe offset. e.g. 0.1
+ * @param value - any keyframe value. e.g. undefined '1px', 'center', 0.5
+ * @param composite - 'replace', 'add', 'accumulate'
+ * @param easing - e.g. undefined, 'linear', 'ease' and so on
+ * @return Object -
+ *   e.g. { offset: 0.1, value: '1px', composite: 'replace', easing: 'ease'}
+ */
+function valueFormat(offset, value, composite, easing) {
+  return { offset: offset, value: value, easing: easing, composite: composite };
+}
+
+/**
  * Appends a div to the document body and creates an animation on the div.
  * NOTE: This function asserts when trying to create animations with durations
  * shorter than 100s because the shorter duration may cause intermittent
  * failures.  If you are not sure how long it is suitable, use 100s; it's
  * long enough but shorter than our test framework timeout (330s).
  * If you really need to use shorter durations, use animate() function directly.
  *
  * @param t  The testharness.js Test object. If provided, this will be used