Bug 1496619 - part 8: Tests r=birtles
authorBoris Chiou <boris.chiou@gmail.com>
Fri, 26 Oct 2018 18:12:31 +0000
changeset 443237 24936aee75434cfe3b1551a1818fd4bc2b40f0aa
parent 443236 77d9e79ed3b9e2a52d635068107d1f2c28369bf9
child 443238 49d47a692ca4b45c4bca5c5335bb41f4dd6c93cd
push id34944
push userncsoregi@mozilla.com
push dateSat, 27 Oct 2018 09:49:55 +0000
treeherdermozilla-central@49d47a692ca4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbirtles
bugs1496619
milestone65.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1496619 - part 8: Tests r=birtles Add new mochitests, and web-platform tests, and devtool tests. Depends on D9314 Differential Revision: https://phabricator.services.mozilla.com/D9315
devtools/client/inspector/animation/test/browser_animation_keyframes-graph_computed-value-path-02.js
devtools/client/inspector/animation/test/browser_animation_keyframes-graph_computed-value-path_easing-hint.js
devtools/client/inspector/animation/test/doc_multi_easings.html
devtools/client/inspector/animation/test/doc_multi_keyframes.html
devtools/client/inspector/animation/test/head.js
layout/style/test/mochitest.ini
layout/style/test/test_transitions_step_functions.html
testing/web-platform/meta/css/css-animations/__dir__.ini
testing/web-platform/meta/css/css-animations/parsing/animation-timing-function-valid.html.ini
testing/web-platform/meta/css/css-easing/__dir__.ini
testing/web-platform/meta/css/css-transitions/__dir__.ini
testing/web-platform/meta/css/css-transitions/parsing/transition-timing-function-valid.html.ini
testing/web-platform/meta/web-animations/__dir__.ini
testing/web-platform/tests/css/css-animations/parsing/animation-timing-function-valid.html
testing/web-platform/tests/css/css-easing/step-timing-functions-output.html
testing/web-platform/tests/css/css-easing/step-timing-functions-syntax.html
testing/web-platform/tests/css/css-transitions/parsing/transition-timing-function-valid.html
testing/web-platform/tests/css/css-transitions/transition-timing-function-001.html
testing/web-platform/tests/web-animations/timing-model/time-transformations/transformed-progress.html
--- a/devtools/client/inspector/animation/test/browser_animation_keyframes-graph_computed-value-path-02.js
+++ b/devtools/client/inspector/animation/test/browser_animation_keyframes-graph_computed-value-path-02.js
@@ -21,16 +21,37 @@ const TEST_DATA = [
           { x: 500, y: 50 },
           { x: 750, y: 75 },
           { x: 1000, y: 100 },
         ],
       },
     ],
   },
   {
+    targetClass: "steps-jump-none-keyframe",
+    properties: [
+      {
+        name: "opacity",
+        computedValuePathClass: "distance-path",
+        expectedPathSegments: [
+          { x: 0, y: 0 },
+          { x: 199, y: 0 },
+          { x: 200, y: 25 },
+          { x: 399, y: 25 },
+          { x: 400, y: 50 },
+          { x: 599, y: 50 },
+          { x: 600, y: 75 },
+          { x: 799, y: 75 },
+          { x: 800, y: 100 },
+          { x: 1000, y: 100 },
+        ],
+      },
+    ],
+  },
+  {
     targetClass: "narrow-offsets",
     properties: [
       {
         name: "opacity",
         computedValuePathClass: "distance-path",
         expectedPathSegments: [
           { x: 0, y: 0 },
           { x: 100, y: 100 },
--- a/devtools/client/inspector/animation/test/browser_animation_keyframes-graph_computed-value-path_easing-hint.js
+++ b/devtools/client/inspector/animation/test/browser_animation_keyframes-graph_computed-value-path_easing-hint.js
@@ -32,17 +32,24 @@ const TEST_DATA = [
     properties: [
       {
         name: "opacity",
         expectedHints: [
           {
             hint: "linear",
             path: [
               { x: 0, y: 100 },
-              { x: 500, y: 50 },
+              { x: 199, y: 81 },
+              { x: 200, y: 80 },
+              { x: 399, y: 61 },
+              { x: 400, y: 60 },
+              { x: 599, y: 41 },
+              { x: 600, y: 40 },
+              { x: 799, y: 21 },
+              { x: 800, y: 20 },
               { x: 1000, y: 0 },
             ],
           },
         ],
       },
     ],
   },
   {
--- a/devtools/client/inspector/animation/test/doc_multi_easings.html
+++ b/devtools/client/inspector/animation/test/doc_multi_easings.html
@@ -39,17 +39,17 @@
     );
 
     createAnimation(
       "effect-easing",
       [
         { opacity: 1 },
         { opacity: 0 },
       ],
-      "steps(5)"
+      "steps(5, jump-none)"
     );
 
     createAnimation(
       "keyframe-easing",
       [
         { opacity: 1, easing: "steps(2)" },
         { opacity: 0 },
       ]
--- a/devtools/client/inspector/animation/test/doc_multi_keyframes.html
+++ b/devtools/client/inspector/animation/test/doc_multi_keyframes.html
@@ -145,16 +145,29 @@
         {
           opacity: 1,
         },
       ],
       "steps(2)"
     );
 
     createAnimation(
+      "steps-jump-none-keyframe",
+      [
+        {
+          easing: "steps(5, jump-none)",
+          opacity: 0,
+        },
+        {
+          opacity: 1,
+        },
+      ]
+    );
+
+    createAnimation(
       "narrow-offsets",
       [
         {
           opacity: 0,
         },
         {
           opacity: 1,
           easing: "steps(2)",
--- a/devtools/client/inspector/animation/test/head.js
+++ b/devtools/client/inspector/animation/test/head.js
@@ -53,16 +53,17 @@ const closeAnimationInspector = async fu
  */
 const enableAnimationFeatures = function() {
   return new Promise(resolve => {
     SpecialPowers.pushPrefEnv({"set": [
       ["dom.animations-api.core.enabled", true],
       ["dom.animations-api.getAnimations.enabled", true],
       ["dom.animations-api.implicit-keyframes.enabled", true],
       ["dom.animations-api.timelines.enabled", true],
+      ["layout.css.step-position-jump.enabled", true],
     ]}, resolve);
   });
 };
 
 /**
  * Add a new test tab in the browser and load the given url.
  *
  * @param {String} url
--- a/layout/style/test/mochitest.ini
+++ b/layout/style/test/mochitest.ini
@@ -1,15 +1,16 @@
 [DEFAULT]
 prefs =
   dom.animations-api.compositing.enabled=true
   dom.animations-api.core.enabled=true
   dom.animations-api.getAnimations.enabled=true
   dom.animations-api.implicit-keyframes.enabled=true
   dom.animations-api.timelines.enabled=true
+  layout.css.step-position-jump.enabled=true
 support-files =
   animation_utils.js
   ccd-quirks.html
   ccd.sjs
   ccd-standards.html
   chrome/bug418986-2.js
   chrome/match.png
   chrome/mismatch.png
--- a/layout/style/test/test_transitions_step_functions.html
+++ b/layout/style/test/test_transitions_step_functions.html
@@ -82,12 +82,50 @@ run_test("steps(8,end)", 0.40, 0.375);
 run_test("steps(8,end)", 0.49, 0.375);
 run_test("steps(8,end)", 0.50, 0.5);
 run_test("steps(8,end)", 0.60, 0.5);
 run_test("steps(8,end)", 0.70, 0.625);
 run_test("steps(8,end)", 0.80, 0.75);
 run_test("steps(8,end)", 0.90, 0.875);
 run_test("steps(8,end)", 1.00, 1.0);
 
+// steps(_, jump-*)
+run_test("steps(2, jump-start)", 0.00, 0.5);
+run_test("steps(2, jump-start)", 0.49, 0.5);
+run_test("steps(2, jump-start)", 0.50, 1.0);
+run_test("steps(2, jump-start)", 0.99, 1.0);
+run_test("steps(2, jump-start)", 1.00, 1.0);
+
+run_test("steps(2, jump-end)", 0.00, 0.0);
+run_test("steps(2, jump-end)", 0.49, 0.0);
+run_test("steps(2, jump-end)", 0.50, 0.5);
+run_test("steps(2, jump-end)", 0.99, 0.5);
+run_test("steps(2, jump-end)", 1.00, 1.0);
+
+run_test("steps(1, jump-both)", 0.00, 0.5);
+run_test("steps(1, jump-both)", 0.10, 0.5);
+run_test("steps(1, jump-both)", 0.99, 0.5);
+run_test("steps(1, jump-both)", 1.00, 1.0);
+
+run_test("steps(3, jump-both)", 0.00, 0.25);
+run_test("steps(3, jump-both)", 0.33, 0.25);
+run_test("steps(3, jump-both)", 0.34, 0.5);
+run_test("steps(3, jump-both)", 0.66, 0.5);
+run_test("steps(3, jump-both)", 0.67, 0.75);
+run_test("steps(3, jump-both)", 0.99, 0.75);
+run_test("steps(3, jump-both)", 1.00, 1.0);
+
+run_test("steps(2, jump-none)", 0.00, 0.0);
+run_test("steps(2, jump-none)", 0.49, 0.0);
+run_test("steps(2, jump-none)", 0.50, 1.0);
+run_test("steps(2, jump-none)", 1.00, 1.0);
+
+run_test("steps(3, jump-none)", 0.00, 0.0);
+run_test("steps(3, jump-none)", 0.33, 0.0);
+run_test("steps(3, jump-none)", 0.34, 0.5);
+run_test("steps(3, jump-none)", 0.66, 0.5);
+run_test("steps(3, jump-none)", 0.67, 1.0);
+run_test("steps(3, jump-none)", 1.00, 1.0);
+
 </script>
 </pre>
 </body>
 </html>
--- a/testing/web-platform/meta/css/css-animations/__dir__.ini
+++ b/testing/web-platform/meta/css/css-animations/__dir__.ini
@@ -1,1 +1,1 @@
-prefs: [dom.animations-api.compositing.enabled:true, dom.animations-api.core.enabled:true, dom.animations-api.getAnimations.enabled:true, dom.animations-api.implicit-keyframes.enabled:true, dom.animations-api.timelines.enabled:true]
+prefs: [dom.animations-api.compositing.enabled:true, dom.animations-api.core.enabled:true, dom.animations-api.getAnimations.enabled:true, dom.animations-api.implicit-keyframes.enabled:true, dom.animations-api.timelines.enabled:true, layout.css.step-position-jump.enabled:true]
deleted file mode 100644
--- a/testing/web-platform/meta/css/css-animations/parsing/animation-timing-function-valid.html.ini
+++ /dev/null
@@ -1,10 +0,0 @@
-[animation-timing-function-valid.html]
-  [CSS Animations Level 1: parsing animation-timing-function with valid values]
-    expected: FAIL
-
-  [CSS Animations: parsing animation-timing-function with valid values]
-    expected: FAIL
-
-  [e.style['animation-timing-function'\] = "steps(2, end)" should set the property value]
-    expected: FAIL
-
--- a/testing/web-platform/meta/css/css-easing/__dir__.ini
+++ b/testing/web-platform/meta/css/css-easing/__dir__.ini
@@ -1,1 +1,1 @@
-prefs: [dom.animations-api.core.enabled:true]
+prefs: [dom.animations-api.core.enabled:true, layout.css.step-position-jump.enabled:true]
--- a/testing/web-platform/meta/css/css-transitions/__dir__.ini
+++ b/testing/web-platform/meta/css/css-transitions/__dir__.ini
@@ -1,1 +1,1 @@
-prefs: [dom.animations-api.compositing.enabled:true, dom.animations-api.core.enabled:true, dom.animations-api.getAnimations.enabled:true, dom.animations-api.implicit-keyframes.enabled:true, dom.animations-api.timelines.enabled:true]
+prefs: [dom.animations-api.compositing.enabled:true, dom.animations-api.core.enabled:true, dom.animations-api.getAnimations.enabled:true, dom.animations-api.implicit-keyframes.enabled:true, dom.animations-api.timelines.enabled:true, layout.css.step-position-jump.enabled:true]
deleted file mode 100644
--- a/testing/web-platform/meta/css/css-transitions/parsing/transition-timing-function-valid.html.ini
+++ /dev/null
@@ -1,7 +0,0 @@
-[transition-timing-function-valid.html]
-  [CSS Transitions: parsing transition-timing-function with valid values]
-    expected: FAIL
-
-  [e.style['transition-timing-function'\] = "steps(2, end)" should set the property value]
-    expected: FAIL
-
--- a/testing/web-platform/meta/web-animations/__dir__.ini
+++ b/testing/web-platform/meta/web-animations/__dir__.ini
@@ -1,1 +1,1 @@
-prefs: [dom.animations-api.compositing.enabled:true, dom.animations-api.core.enabled:true, dom.animations-api.getAnimations.enabled:true, dom.animations-api.implicit-keyframes.enabled:true, dom.animations-api.timelines.enabled:true]
+prefs: [dom.animations-api.compositing.enabled:true, dom.animations-api.core.enabled:true, dom.animations-api.getAnimations.enabled:true, dom.animations-api.implicit-keyframes.enabled:true, dom.animations-api.timelines.enabled:true, layout.css.step-position-jump.enabled:true]
--- a/testing/web-platform/tests/css/css-animations/parsing/animation-timing-function-valid.html
+++ b/testing/web-platform/tests/css/css-animations/parsing/animation-timing-function-valid.html
@@ -18,14 +18,18 @@ test_valid_value("animation-timing-funct
 test_valid_value("animation-timing-function", "ease-out");
 test_valid_value("animation-timing-function", "ease-in-out");
 test_valid_value("animation-timing-function", "cubic-bezier(0.1, 0.2, 0.8, 0.9)");
 test_valid_value("animation-timing-function", "cubic-bezier(0, -2, 1, 3)");
 test_valid_value("animation-timing-function", "cubic-bezier(0, 0.7, 1, 1.3)");
 
 
 test_valid_value("animation-timing-function", "steps(4, start)");
-test_valid_value("animation-timing-function", "steps(2, end)");
+test_valid_value("animation-timing-function", "steps(2, end)", "steps(2)");
+test_valid_value("animation-timing-function", "steps(2, jump-start)");
+test_valid_value("animation-timing-function", "steps(2, jump-end)", "steps(2)");
+test_valid_value("animation-timing-function", "steps(2, jump-both)");
+test_valid_value("animation-timing-function", "steps(2, jump-none)");
 
 test_valid_value("animation-timing-function", "linear, ease, linear");
 </script>
 </body>
 </html>
--- a/testing/web-platform/tests/css/css-easing/step-timing-functions-output.html
+++ b/testing/web-platform/tests/css/css-easing/step-timing-functions-output.html
@@ -32,52 +32,39 @@ test(function(t) {
   assert_equals(getComputedStyle(target).left, '200px');
   anim.currentTime = 1000;
   assert_equals(getComputedStyle(target).left, '100px');
 }, 'step-start easing with input progress greater than 1');
 
 test(function(t) {
   var target = createDiv(t);
   target.style.position = 'absolute';
-  var anim = target.animate([ { left: '0px', easing: 'step-end' },
-                              { left: '100px' } ],
-                            { duration: 1000,
-                              fill: 'forwards',
-                              easing: 'cubic-bezier(0, 1.5, 1, 1.5)' });
-
-  // The bezier function produces values greater than 1 (but always less than 2)
-  // in (0.23368794, 1)
-  anim.currentTime = 0;
-  assert_equals(getComputedStyle(target).left, '0px');
-  anim.currentTime = 230;
-  assert_equals(getComputedStyle(target).left, '0px');
-  anim.currentTime = 250;
-  assert_equals(getComputedStyle(target).left, '100px');
-  anim.currentTime = 1000;
-  assert_equals(getComputedStyle(target).left, '100px');
-}, 'step-end easing with input progress greater than 1');
-
-test(function(t) {
-  var target = createDiv(t);
-  target.style.position = 'absolute';
-  var anim = target.animate([ { left: '0px', easing: 'step-end' },
+  var anim = target.animate([ { left: '0px', easing: 'step-start' },
                               { left: '100px' } ],
                             { duration: 1000,
                               fill: 'forwards',
                               easing: 'cubic-bezier(0, 3, 1, 3)' });
 
-  // The bezier function produces values greater than 2 (but always less than 3)
-  // in the range (~0.245, ~0.882)
+  // The bezier function produces values:
+  // Input           ->  Output
+  // 0.0                 0.0
+  // 0.114 ~ 0.245       1.5~2.0, so current step is 2, jumps is 1 => 2.0
+  // 0.245 ~ 0.6         2.0~2.4, so current step is 3, jumps is 1 => 3.0
+  // 0.6   ~ 0.882       2.4~2.0, so current step is 3, jumps is 1 => 3.0
+  // 0.882 ~ 0.976       2.0~1.5, so current step is 2, jumps is 1 => 2.0
+  // 1.0                 1.0
   anim.currentTime = 0;
-  assert_equals(getComputedStyle(target).left, '0px');
+  assert_equals(getComputedStyle(target).left, '100px');
+  anim.currentTime = 114;
+  assert_equals(getComputedStyle(target).left, '200px');
   anim.currentTime = 500;
-  assert_equals(getComputedStyle(target).left, '200px');
+  assert_equals(getComputedStyle(target).left, '300px');
   anim.currentTime = 900;
-  assert_equals(getComputedStyle(target).left, '100px');
-}, 'step-end easing with input progress greater than 2');
+  assert_equals(getComputedStyle(target).left, '200px');
+}, 'step-start easing with input progress greater than 2');
 
 test(function(t) {
   var target = createDiv(t);
   target.style.position = 'absolute';
   var anim = target.animate([ { left: '0px', easing: 'step-start' },
                               { left: '100px' } ],
                             { duration: 1000,
                               fill: 'forwards',
@@ -118,24 +105,214 @@ test(function(t) {
 
 test(function(t) {
   var target = createDiv(t);
   target.style.position = 'absolute';
   var anim = target.animate([ { left: '0px', easing: 'step-end' },
                               { left: '100px' } ],
                             { duration: 1000,
                               fill: 'forwards',
+                              easing: 'cubic-bezier(0, 1.5, 1, 1.5)' });
+
+  // The bezier function produces values greater than 1 (but always less than 2)
+  // in (0.23368794, 1)
+  anim.currentTime = 0;
+  assert_equals(getComputedStyle(target).left, '0px');
+  anim.currentTime = 230;
+  assert_equals(getComputedStyle(target).left, '0px');
+  anim.currentTime = 250;
+  assert_equals(getComputedStyle(target).left, '100px');
+  anim.currentTime = 1000;
+  assert_equals(getComputedStyle(target).left, '100px');
+}, 'step-end easing with input progress greater than 1');
+
+test(function(t) {
+  var target = createDiv(t);
+  target.style.position = 'absolute';
+  var anim = target.animate([ { left: '0px', easing: 'step-end' },
+                              { left: '100px' } ],
+                            { duration: 1000,
+                              fill: 'forwards',
+                              easing: 'cubic-bezier(0, 3, 1, 3)' });
+
+  // The bezier function produces values:
+  // Input           ->  Output
+  // 0.0                 0.0
+  // 0.114 ~ 0.245       1.5~2.0, so current step is 1, jumps is 1 => 1.0
+  // 0.245 ~ 0.6         2.0~2.4, so current step is 2, jumps is 1 => 2.0
+  // 0.6   ~ 0.882       2.4~2.0, so current step is 2, jumps is 1 => 2.0
+  // 0.882 ~ 0.976       2.0~1.5, so current step is 1, jumps is 1 => 1.0
+  // 1.0                 1.0
+  anim.currentTime = 0;
+  assert_equals(getComputedStyle(target).left, '0px');
+  anim.currentTime = 114;
+  assert_equals(getComputedStyle(target).left, '100px');
+  anim.currentTime = 500;
+  assert_equals(getComputedStyle(target).left, '200px');
+  anim.currentTime = 900;
+  assert_equals(getComputedStyle(target).left, '100px');
+}, 'step-end easing with input progress greater than 2');
+
+test(function(t) {
+  var target = createDiv(t);
+  target.style.position = 'absolute';
+  var anim = target.animate([ { left: '0px', easing: 'step-end' },
+                              { left: '100px' } ],
+                            { duration: 1000,
+                              fill: 'forwards',
                               easing: 'cubic-bezier(0, -0.5, 1, -0.5)' });
 
   // The bezier function produces negative values (but always greater than -1)
   // in (0, 0.766312060)
   anim.currentTime = 0;
   assert_equals(getComputedStyle(target).left, '0px');
   anim.currentTime = 750;
   assert_equals(getComputedStyle(target).left, '-100px');
   anim.currentTime = 800;
   assert_equals(getComputedStyle(target).left, '0px');
   anim.currentTime = 1000;
   assert_equals(getComputedStyle(target).left, '100px');
 }, 'step-end easing with input progress less than 0');
 
+test(function(t) {
+  var target = createDiv(t);
+  target.style.position = 'absolute';
+  var anim = target.animate([ { left: '0px', easing: 'steps(1, jump-both)' },
+                              { left: '100px' } ],
+                            { duration: 1000,
+                              fill: 'forwards',
+                              easing: 'cubic-bezier(0, 1.5, 1, 1.5)' });
+
+  // The bezier function produces values greater than 1 (but always less than 2)
+  // in (0.23368794, 1)
+  anim.currentTime = 0;
+  assert_equals(getComputedStyle(target).left, '50px');
+  anim.currentTime = 230;
+  assert_equals(getComputedStyle(target).left, '50px');
+  anim.currentTime = 250;
+  assert_equals(getComputedStyle(target).left, '100px');
+  anim.currentTime = 1000;
+  assert_equals(getComputedStyle(target).left, '100px');
+}, 'steps(1, jump-both) easing with input progress greater than 1');
+
+test(function(t) {
+  var target = createDiv(t);
+  target.style.position = 'absolute';
+  var anim = target.animate([ { left: '0px', easing: 'steps(1, jump-both)' },
+                              { left: '100px' } ],
+                            { duration: 1000,
+                              fill: 'forwards',
+                              easing: 'cubic-bezier(0, 3, 1, 3)' });
+
+  // The bezier function produces values:
+  // Input           ->  Output
+  // 0.0                 0.0,     so current step is 1, jumps is 2 => 0.5
+  // 0.114 ~ 0.245       1.5~2.0, so current step is 2, jumps is 2 => 1.0
+  // 0.245 ~ 0.6         2.0~2.4, so current step is 3, jumps is 2 => 1.5
+  // 0.6   ~ 0.882       2.4~2.0, so current step is 3, jumps is 2 => 1.5
+  // 0.882 ~ 0.976       2.0~1.5, so current step is 2, jumps is 2 => 1.0
+  // 1.0                 1.0
+  anim.currentTime = 0;
+  assert_equals(getComputedStyle(target).left, '50px');
+  anim.currentTime = 114;
+  assert_equals(getComputedStyle(target).left, '100px');
+  anim.currentTime = 500;
+  assert_equals(getComputedStyle(target).left, '150px');
+  anim.currentTime = 900;
+  assert_equals(getComputedStyle(target).left, '100px');
+}, 'steps(1, jump-both) easing with input progress greater than 2');
+
+test(function(t) {
+  var target = createDiv(t);
+  target.style.position = 'absolute';
+  var anim = target.animate([ { left: '0px', easing: 'steps(1, jump-both)' },
+                              { left: '100px' } ],
+                            { duration: 1000,
+                              fill: 'forwards',
+                              easing: 'cubic-bezier(0, -0.5, 1, -0.5)' });
+
+  // The bezier function produces negative values (but always greater than -0.5)
+  // in (0, 0.766312060).
+  anim.currentTime = 0;
+  assert_equals(getComputedStyle(target).left, '50px');
+  anim.currentTime = 750;
+  // current step is 0, jumps is 2.
+  assert_equals(getComputedStyle(target).left, '0px');
+  anim.currentTime = 800;
+  assert_equals(getComputedStyle(target).left, '50px');
+  anim.currentTime = 1000;
+  assert_equals(getComputedStyle(target).left, '100px');
+}, 'steps(1, jump-both) easing with input progress less than 0');
+
+test(function(t) {
+  var target = createDiv(t);
+  target.style.position = 'absolute';
+  var anim = target.animate([ { left: '0px', easing: 'steps(2, jump-none)' },
+                              { left: '100px' } ],
+                            { duration: 1000,
+                              fill: 'forwards',
+                              easing: 'cubic-bezier(0, 1.5, 1, 1.5)' });
+
+  // The bezier function produces values between 0.5 and 1 in
+  // (~0.0442, 0.23368), and values between 1 and 2 in (0.23368794, 1).
+  anim.currentTime = 0;
+  assert_equals(getComputedStyle(target).left, '0px');
+  anim.currentTime = 45;
+  assert_equals(getComputedStyle(target).left, '100px');
+  anim.currentTime = 230;
+  assert_equals(getComputedStyle(target).left, '100px');
+  anim.currentTime = 250;
+  assert_equals(getComputedStyle(target).left, '200px');
+  anim.currentTime = 1000;
+  assert_equals(getComputedStyle(target).left, '100px');
+}, 'steps(2, jump-none) easing with input progress greater than 1');
+
+test(function(t) {
+  var target = createDiv(t);
+  target.style.position = 'absolute';
+  var anim = target.animate([ { left: '0px', easing: 'steps(2, jump-none)' },
+                              { left: '100px' } ],
+                            { duration: 1000,
+                              fill: 'forwards',
+                              easing: 'cubic-bezier(0, 3, 1, 3)' });
+
+  // The bezier function produces values:
+  // Input           ->  Output
+  // 0.0                 0.0,     so current step is 0, jumps is 1 => 0.0
+  // 0.114 ~ 0.245       1.5~2.0, so current step is 3, jumps is 1 => 3.0
+  // 0.245 ~ 0.6         2.0~2.4, so current step is 4, jumps is 1 => 4.0
+  // 0.6   ~ 0.882       2.4~2.0, so current step is 4, jumps is 1 => 4.0
+  // 0.882 ~ 0.976       2.0~1.5, so current step is 3, jumps is 1 => 3.0
+  // 1.0                 1.0
+  anim.currentTime = 0;
+  assert_equals(getComputedStyle(target).left, '0px');
+  anim.currentTime = 114;
+  assert_equals(getComputedStyle(target).left, '300px');
+  anim.currentTime = 500;
+  assert_equals(getComputedStyle(target).left, '400px');
+  anim.currentTime = 900;
+  assert_equals(getComputedStyle(target).left, '300px');
+}, 'steps(2, jump-none) easing with input progress greater than 2');
+
+test(function(t) {
+  var target = createDiv(t);
+  target.style.position = 'absolute';
+  var anim = target.animate([ { left: '0px', easing: 'steps(2, jump-none)' },
+                              { left: '100px' } ],
+                            { duration: 1000,
+                              fill: 'forwards',
+                              easing: 'cubic-bezier(0, -0.5, 1, -0.5)' });
+
+  // The bezier function produces negative values (but always greater than -0.5)
+  // in (0, 0.766312060).
+  anim.currentTime = 0;
+  assert_equals(getComputedStyle(target).left, '0px');
+  anim.currentTime = 750;
+  // current step is -1, jumps is 1.
+  assert_equals(getComputedStyle(target).left, '-100px');
+  anim.currentTime = 800;
+  assert_equals(getComputedStyle(target).left, '0px');
+  anim.currentTime = 1000;
+  assert_equals(getComputedStyle(target).left, '100px');
+}, 'steps(2, jump-none) easing with input progress less than 0');
+
 </script>
 </body>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/css/css-easing/step-timing-functions-syntax.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<meta name="assert"
+content="This test checks the syntax output of step timing functions" />
+<title>Step timing function syntax tests</title>
+<link rel="help"
+      href="https://drafts.csswg.org/css-easing-1/#step-timing-functions">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="testcommon.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+<body>
+<div id="log"></div>
+<script>
+"use strict";
+
+test_valid_value("animation-timing-function", "step-start", "steps(1, start)");
+test_valid_value("animation-timing-function", "step-end", "steps(1)");
+test_valid_value("animation-timing-function", "steps(1, start)");
+test_valid_value("animation-timing-function", "steps(1, end)", "steps(1)");
+test_valid_value("animation-timing-function", "steps(1, jump-start)");
+test_valid_value("animation-timing-function", "steps(1, jump-end)", "steps(1)");
+test_valid_value("animation-timing-function", "steps(1, jump-both)");
+test_valid_value("animation-timing-function", "steps(2, jump-none)");
+
+test_invalid_value("animation-timing-function", "steps(0, start)");
+test_invalid_value("animation-timing-function", "steps(0, end)");
+test_invalid_value("animation-timing-function", "steps(0, jump-start)");
+test_invalid_value("animation-timing-function", "steps(0, jump-end)");
+test_invalid_value("animation-timing-function", "steps(0, jump-both)");
+test_invalid_value("animation-timing-function", "steps(1, jump-none)");
+
+</script>
+</body>
--- a/testing/web-platform/tests/css/css-transitions/parsing/transition-timing-function-valid.html
+++ b/testing/web-platform/tests/css/css-transitions/parsing/transition-timing-function-valid.html
@@ -18,14 +18,18 @@ test_valid_value("transition-timing-func
 test_valid_value("transition-timing-function", "ease-in");
 test_valid_value("transition-timing-function", "ease-out");
 test_valid_value("transition-timing-function", "ease-in-out");
 test_valid_value("transition-timing-function", "cubic-bezier(0.1, 0.2, 0.8, 0.9)");
 test_valid_value("transition-timing-function", "cubic-bezier(0, -2, 1, 3)");
 test_valid_value("transition-timing-function", "cubic-bezier(0, 0.7, 1, 1.3)");
 
 test_valid_value("transition-timing-function", "steps(4, start)");
-test_valid_value("transition-timing-function", "steps(2, end)");
+test_valid_value("transition-timing-function", "steps(2, end)", "steps(2)");
+test_valid_value("transition-timing-function", "steps(2, jump-start)");
+test_valid_value("transition-timing-function", "steps(2, jump-end)", "steps(2)");
+test_valid_value("transition-timing-function", "steps(2, jump-both)");
+test_valid_value("transition-timing-function", "steps(2, jump-none)");
 
 test_valid_value("transition-timing-function", "linear, ease, linear");
 </script>
 </body>
 </html>
--- a/testing/web-platform/tests/css/css-transitions/transition-timing-function-001.html
+++ b/testing/web-platform/tests/css/css-transitions/transition-timing-function-001.html
@@ -37,22 +37,30 @@
                 // cubic bezier
                 'cubic-bezier(0.1, 0.2, 0.3, 0.4)': 'cubic-bezier(0.1, 0.2, 0.3, 0.4)',
                 'cubic-bezier(0.1, -0.2, 0.3, -0.4)': 'cubic-bezier(0.1, -0.2, 0.3, -0.4)',
                 'cubic-bezier(0.1, 1.2, 0.3, 1.4)': 'cubic-bezier(0.1, 1.2, 0.3, 1.4)',
                 // steps
                 'steps(3, start)': 'steps(3, start)',
                 'steps(3, end)': 'steps(3)',
                 'steps(3)': 'steps(3)',
+                'steps(3, jump-start)': 'steps(3, jump-start)',
+                'steps(3, jump-end)': 'steps(3)',
+                'steps(3, jump-both)': 'steps(3, jump-both)',
+                'steps(3, jump-none)': 'steps(3, jump-none)',
                 // invalid
                 'cubic-bezier(foobar)': defaultValue,
                 'steps(foobar)': defaultValue,
                 'steps(3.3, end)': defaultValue,
                 'steps(3, top)': defaultValue,
                 'steps(-3, top)': defaultValue,
+                'steps(0, jump-start)': defaultValue,
+                'steps(0, jump-end)': defaultValue,
+                'steps(0, jump-both)': defaultValue,
+                'steps(1, jump-none)': defaultValue,
                 // Both x values must be in the range [0, 1]
                 'cubic-bezier(-0.1, -0.2, -0.3, -0.4)': defaultValue,
                 'cubic-bezier(1.1, 1.2, 1.3, 1.4)': defaultValue
             };
 
             // these tests are supposed to fail and
             // possibly make the engine issue a parser warning
             var invalidTests = {
--- a/testing/web-platform/tests/web-animations/timing-model/time-transformations/transformed-progress.html
+++ b/testing/web-platform/tests/web-animations/timing-model/time-transformations/transformed-progress.html
@@ -248,16 +248,135 @@ const gStepTimingFunctionTests = [
                   { currentTime: 1249, progress: 0.5 },
                   { currentTime: 1250, progress: 0 },
                   { currentTime: 1749, progress: 0 },
                   { currentTime: 1750, progress: 0.5 },
                   { currentTime: 2000, progress: 0.5 },
                   { currentTime: 2500, progress: 0.5 },
                 ]
   },
+  {
+    description: 'Test bounds point of steps(jump-both) easing',
+    effect:     {
+                  delay: 1000,
+                  duration: 1000,
+                  fill: 'both',
+                  easing: 'steps(2, jump-both)'
+                },
+    conditions: [
+                  { currentTime: 0,    progress: 0 },
+                  { currentTime: 999,  progress: 0 },
+                  { currentTime: 1000, progress: 1/3 },
+                  { currentTime: 1499, progress: 1/3 },
+                  { currentTime: 1500, progress: 2/3 },
+                  { currentTime: 2000, progress: 1 }
+                ]
+  },
+  {
+    description: 'Test bounds point of steps(jump-both) easing ' +
+                 'with iterationStart and delay',
+    effect:     {
+                  duration: 1000,
+                  fill: 'both',
+                  delay: 1000,
+                  iterationStart: 0.5,
+                  easing: 'steps(2, jump-both)'
+                },
+    conditions: [
+                  { currentTime: 0,    progress: 1/3 },
+                  { currentTime: 999,  progress: 1/3 },
+                  { currentTime: 1000, progress: 2/3 },
+                  { currentTime: 1499, progress: 2/3 },
+                  { currentTime: 1500, progress: 1/3 },
+                  { currentTime: 1999, progress: 1/3 },
+                  { currentTime: 2000, progress: 2/3 },
+                  { currentTime: 2500, progress: 2/3 }
+                ]
+  },
+  {
+    description: 'Test bounds point of steps(jump-both) easing ' +
+                 'with iterationStart not at a transition point',
+    effect:     {
+                  delay: 1000,
+                  duration: 1000,
+                  fill: 'both',
+                  iterationStart: 0.75,
+                  easing: 'steps(2, jump-both)'
+                },
+    conditions: [
+                  { currentTime: 0,    progress: 2/3 },
+                  { currentTime: 999,  progress: 2/3 },
+                  { currentTime: 1000, progress: 2/3 },
+                  { currentTime: 1249, progress: 2/3 },
+                  { currentTime: 1250, progress: 1/3 },
+                  { currentTime: 1749, progress: 1/3 },
+                  { currentTime: 1750, progress: 2/3 },
+                  { currentTime: 2000, progress: 2/3 },
+                  { currentTime: 2500, progress: 2/3 }
+                ]
+  },
+  {
+    description: 'Test bounds point of steps(jump-none) easing',
+    effect:     {
+                  delay: 1000,
+                  duration: 1000,
+                  fill: 'both',
+                  easing: 'steps(2, jump-none)'
+                },
+    conditions: [
+                  { currentTime: 0,    progress: 0 },
+                  { currentTime: 1000, progress: 0 },
+                  { currentTime: 1499, progress: 0 },
+                  { currentTime: 1500, progress: 1 },
+                  { currentTime: 2000, progress: 1 }
+                ]
+  },
+  {
+    description: 'Test bounds point of steps(jump-none) easing ' +
+                 'with iterationStart and delay',
+    effect:     {
+                  duration: 1000,
+                  fill: 'both',
+                  delay: 1000,
+                  iterationStart: 0.5,
+                  easing: 'steps(2, jump-none)'
+                },
+    conditions: [
+                  { currentTime: 0,    progress: 0 },
+                  { currentTime: 999,  progress: 0 },
+                  { currentTime: 1000, progress: 1 },
+                  { currentTime: 1499, progress: 1 },
+                  { currentTime: 1500, progress: 0 },
+                  { currentTime: 1999, progress: 0 },
+                  { currentTime: 2000, progress: 1 },
+                  { currentTime: 2500, progress: 1 }
+                ]
+  },
+  {
+    description: 'Test bounds point of steps(jump-none) easing ' +
+                 'with iterationStart not at a transition point',
+    effect:     {
+                  delay: 1000,
+                  duration: 1000,
+                  fill: 'both',
+                  iterationStart: 0.75,
+                  easing: 'steps(2, jump-none)'
+                },
+    conditions: [
+                  { currentTime: 0,    progress: 1 },
+                  { currentTime: 999,  progress: 1 },
+                  { currentTime: 1000, progress: 1 },
+                  { currentTime: 1249, progress: 1 },
+                  { currentTime: 1250, progress: 0 },
+                  { currentTime: 1749, progress: 0 },
+                  { currentTime: 1750, progress: 1 },
+                  { currentTime: 2000, progress: 1 },
+                  { currentTime: 2500, progress: 1 }
+                ]
+  },
 ];
 
 for (const options of gStepTimingFunctionTests) {
   test(t => {
     const target = createDiv(t);
     const animation = target.animate(null, options.effect);
     for (const condition of options.conditions) {
       animation.currentTime = condition.currentTime;