From 08a2d007e5e4eb0b7d3351e06ecc054b4b53b5a5 Mon Sep 17 00:00:00 2001 From: Yehonatan Daniv Date: Fri, 17 Jul 2026 19:30:30 +0300 Subject: [PATCH] Added tests for animation-delay shorthand, animation-delay-start, and animation-delay-end --- ...ionEffect-getComputedTiming.tentative.html | 48 +++++++++++++ ...nimationEffect-updateTiming.tentative.html | 67 ++++++++++++++++--- .../CSSAnimation-effect.tentative.html | 21 +++++- ...-delay-end-liveness-reverse.tentative.html | 34 ++++++++++ ...ion-delay-list-coordination.tentative.html | 39 +++++++++++ .../animation-delay-start-012.tentative.html | 21 ++++++ ...on-delay-start-liveness-001.tentative.html | 33 +++++++++ ...on-delay-start-liveness-002.tentative.html | 40 +++++++++++ ...on-delay-start-liveness-003.tentative.html | 40 +++++++++++ .../event-dispatch.tentative.html | 40 +++++++++++ css/css-animations/inheritance.html | 2 + .../parsing/animation-computed.html | 4 +- .../parsing/animation-delay-computed.html | 6 +- ...nimation-delay-end-computed.tentative.html | 30 +++++++++ ...animation-delay-end-invalid.tentative.html | 22 ++++++ .../animation-delay-end-valid.tentative.html | 22 ++++++ .../parsing/animation-delay-invalid.html | 4 +- .../animation-delay-shorthand.tentative.html | 55 +++++++++++++++ ...mation-delay-start-computed.tentative.html | 30 +++++++++ ...imation-delay-start-invalid.tentative.html | 22 ++++++ ...animation-delay-start-valid.tentative.html | 24 +++++++ .../parsing/animation-delay-valid.html | 7 +- .../parsing/animation-shorthand.html | 8 +-- .../parsing/animation-valid.html | 2 +- .../parsing/keyframes-allowed-properties.html | 4 ++ 25 files changed, 603 insertions(+), 22 deletions(-) create mode 100644 css/css-animations/animation-delay-end-liveness-reverse.tentative.html create mode 100644 css/css-animations/animation-delay-list-coordination.tentative.html create mode 100644 css/css-animations/animation-delay-start-012.tentative.html create mode 100644 css/css-animations/animation-delay-start-liveness-001.tentative.html create mode 100644 css/css-animations/animation-delay-start-liveness-002.tentative.html create mode 100644 css/css-animations/animation-delay-start-liveness-003.tentative.html create mode 100644 css/css-animations/parsing/animation-delay-end-computed.tentative.html create mode 100644 css/css-animations/parsing/animation-delay-end-invalid.tentative.html create mode 100644 css/css-animations/parsing/animation-delay-end-valid.tentative.html create mode 100644 css/css-animations/parsing/animation-delay-shorthand.tentative.html create mode 100644 css/css-animations/parsing/animation-delay-start-computed.tentative.html create mode 100644 css/css-animations/parsing/animation-delay-start-invalid.tentative.html create mode 100644 css/css-animations/parsing/animation-delay-start-valid.tentative.html diff --git a/css/css-animations/AnimationEffect-getComputedTiming.tentative.html b/css/css-animations/AnimationEffect-getComputedTiming.tentative.html index 46c26fcb99be0f..def5a6e8aa8b2f 100644 --- a/css/css-animations/AnimationEffect-getComputedTiming.tentative.html +++ b/css/css-animations/AnimationEffect-getComputedTiming.tentative.html @@ -54,6 +54,54 @@ 'Initial value of endDelay'); }, 'endDelay of a new animation'); +test(t => { + const div = addDiv(t, { style: 'animation: moveAnimation 100s; animation-delay-start: 10s' }); + const effect = div.getAnimations()[0].effect; + assert_equals(effect.getComputedTiming().delay, 10 * MS_PER_SEC, + 'animation-delay-start maps to delay'); +}, 'animation-delay-start maps to delay'); + +test(t => { + const div = addDiv(t, { style: 'animation: moveAnimation 100s; animation-delay-end: 5s' }); + const effect = div.getAnimations()[0].effect; + assert_equals(effect.getComputedTiming().endDelay, 5 * MS_PER_SEC, + 'animation-delay-end maps to endDelay'); +}, 'animation-delay-end maps to endDelay'); + +test(t => { + const div = addDiv(t, { style: 'animation: moveAnimation 100s; animation-delay: 2s 8s' }); + const effect = div.getAnimations()[0].effect; + assert_equals(effect.getComputedTiming().delay, 2 * MS_PER_SEC, + 'Two-value animation-delay start component'); + assert_equals(effect.getComputedTiming().endDelay, 8 * MS_PER_SEC, + 'Two-value animation-delay end component'); +}, 'Two-value animation-delay maps to delay and endDelay'); + +test(t => { + const div = addDiv(t, { style: 'animation: moveAnimation 100s; animation-delay-end: 5s' }); + div.style.animationDelay = '2s'; + const effect = div.getAnimations()[0].effect; + assert_equals(effect.getComputedTiming().delay, 2 * MS_PER_SEC, + 'Single-value animation-delay updates delay'); + assert_equals(effect.getComputedTiming().endDelay, 5 * MS_PER_SEC, + 'Single-value animation-delay leaves endDelay unchanged'); +}, 'Single-value animation-delay updates start delay only'); + +test(t => { + const div = addDiv(t, { style: 'animation: moveAnimation 100s; animation-delay-end: 20s' }); + const effect = div.getAnimations()[0].effect; + assert_equals(effect.getComputedTiming().endTime, 120 * MS_PER_SEC, + 'endTime includes positive endDelay'); +}, 'endTime includes positive endDelay'); + +test(t => { + const div = addDiv(t, { style: 'animation: moveAnimation 100s; animation-delay-start: -5s' }); + const effect = div.getAnimations()[0].effect; + const answer = (100 - 5) * MS_PER_SEC; + assert_equals(effect.getComputedTiming().endTime, answer, + 'endTime reflects negative start delay'); +}, 'endTime reflects negative animation-delay-start'); + // -------------------- // fill diff --git a/css/css-animations/AnimationEffect-updateTiming.tentative.html b/css/css-animations/AnimationEffect-updateTiming.tentative.html index e6556dac4bde9f..f01c2a37f3db6c 100644 --- a/css/css-animations/AnimationEffect-updateTiming.tentative.html +++ b/css/css-animations/AnimationEffect-updateTiming.tentative.html @@ -42,7 +42,8 @@ // // iterations - animation-iteration-count // direction - animation-direction -// delay - animation-delay +// delay - animation-delay-start +// endDelay - animation-delay-end // fill - animation-fill-mode // // Which we test in two batches, overriding two properties each time and using @@ -117,7 +118,53 @@ 'Direction should be the value set by style' ); }, 'AnimationEffect.updateTiming({ delay, fill }) causes changes to' - + ' the animation-delay and animation-fill-mode to be ignored'); + + ' the animation-delay-start and animation-fill-mode to be ignored'); + +test(t => { + const div = addDiv(t); + div.style.animation = 'anim-empty 100s'; + + const animation = div.getAnimations()[0]; + animation.effect.updateTiming({ endDelay: 2 * MS_PER_SEC }); + + div.style.animationDelayEnd = '4s'; + div.style.animationDelayStart = '6s'; + + assert_equals( + animation.effect.getTiming().endDelay, + 2 * MS_PER_SEC, + 'End delay should be the value set by the API' + ); + assert_equals( + animation.effect.getTiming().delay, + 6 * MS_PER_SEC, + 'Start delay should be the value set by style' + ); +}, 'AnimationEffect.updateTiming({ endDelay }) causes changes to' + + ' the animation-delay-end to be ignored'); + +test(t => { + const div = addDiv(t); + div.style.animation = 'anim-empty 100s'; + + const animation = div.getAnimations()[0]; + animation.effect.updateTiming({ delay: 2 * MS_PER_SEC }); + + div.style.animationDelayStart = '4s'; + div.style.animationDelayEnd = '6s'; + + assert_equals( + animation.effect.getTiming().delay, + 2 * MS_PER_SEC, + 'Start delay should be the value set by the API' + ); + assert_equals( + animation.effect.getTiming().endDelay, + 6 * MS_PER_SEC, + 'End delay should be the value set by style' + ); +}, 'AnimationEffect.updateTiming({ delay }) causes changes to' + + ' the animation-delay-start to be ignored'); test(t => { const div = addDiv(t); @@ -145,27 +192,27 @@ const animation = div.getAnimations()[0]; animation.effect.updateTiming({ easing: 'steps(4)', - endDelay: 2 * MS_PER_SEC, iterationStart: 4, }); div.style.animationDuration = '6s'; div.style.animationTimingFunction = 'ease-in'; + div.style.animationDelayEnd = '8s'; assert_equals( animation.effect.getTiming().easing, 'steps(4)', - 'endDelay should be the value set by the API' - ); - assert_equals( - animation.effect.getTiming().endDelay, - 2 * MS_PER_SEC, - 'endDelay should be the value set by the API' + 'easing should be the value set by the API' ); assert_equals( animation.effect.getTiming().iterationStart, 4, - 'iterationStart should be the value set by style' + 'iterationStart should be the value set by the API' + ); + assert_equals( + animation.effect.getTiming().endDelay, + 8 * MS_PER_SEC, + 'endDelay should be the value set by style' ); }, 'AnimationEffect properties that do not map to animation-* properties' + ' should not be changed when animation-* style is updated'); diff --git a/css/css-animations/CSSAnimation-effect.tentative.html b/css/css-animations/CSSAnimation-effect.tentative.html index 591ffe770b65ed..32728cd9a37eda 100644 --- a/css/css-animations/CSSAnimation-effect.tentative.html +++ b/css/css-animations/CSSAnimation-effect.tentative.html @@ -166,7 +166,8 @@ div.style.animationDuration = '4s'; div.style.animationIterationCount = '6'; div.style.animationDirection = 'reverse'; - div.style.animationDelay = '8s'; + div.style.animationDelayStart = '8s'; + div.style.animationDelayEnd = '12s'; div.style.animationFillMode = 'both'; div.style.animationPlayState = 'paused'; div.style.animationComposition = 'add'; @@ -197,6 +198,11 @@ 0, 'delay should be the value set by the API' ); + assert_equals( + animation.effect.getTiming().endDelay, + 0, + 'endDelay should be the value set by the API' + ); assert_equals( animation.effect.getTiming().fill, 'auto', @@ -225,6 +231,19 @@ null, 'timeline should be the value set by style' ); + + div.style.animationDelayStart = '99s'; + div.style.animationDelayEnd = '99s'; + assert_equals( + animation.effect.getTiming().delay, + 0, + 'delay should remain the value set by the API after style change' + ); + assert_equals( + animation.effect.getTiming().endDelay, + 0, + 'endDelay should remain the value set by the API after style change' + ); }, 'Replacing the effect of a CSSAnimation causes subsequent changes to' + ' corresponding animation-* properties to be ignored'); diff --git a/css/css-animations/animation-delay-end-liveness-reverse.tentative.html b/css/css-animations/animation-delay-end-liveness-reverse.tentative.html new file mode 100644 index 00000000000000..81fa0ea12fbc2f --- /dev/null +++ b/css/css-animations/animation-delay-end-liveness-reverse.tentative.html @@ -0,0 +1,34 @@ + + +CSS Animations: animation-delay-end liveness with reverse playback + + + + + +
+ diff --git a/css/css-animations/animation-delay-list-coordination.tentative.html b/css/css-animations/animation-delay-list-coordination.tentative.html new file mode 100644 index 00000000000000..17e26d17e95773 --- /dev/null +++ b/css/css-animations/animation-delay-list-coordination.tentative.html @@ -0,0 +1,39 @@ + + +CSS Animations: animation-delay list coordination + + + + + + +
+ diff --git a/css/css-animations/animation-delay-start-012.tentative.html b/css/css-animations/animation-delay-start-012.tentative.html new file mode 100644 index 00000000000000..934e139ae85fa2 --- /dev/null +++ b/css/css-animations/animation-delay-start-012.tentative.html @@ -0,0 +1,21 @@ + + +CSS Animations Test: huge negative animation-delay-start + + + + + +

Test passes if there is a filled green square and no red.

+
diff --git a/css/css-animations/animation-delay-start-liveness-001.tentative.html b/css/css-animations/animation-delay-start-liveness-001.tentative.html new file mode 100644 index 00000000000000..53059cb3d92fa0 --- /dev/null +++ b/css/css-animations/animation-delay-start-liveness-001.tentative.html @@ -0,0 +1,33 @@ + + + +CSS Animations Test: animation-delay-start - liveness + + + + + +
+ + diff --git a/css/css-animations/animation-delay-start-liveness-002.tentative.html b/css/css-animations/animation-delay-start-liveness-002.tentative.html new file mode 100644 index 00000000000000..3320087f8f21ad --- /dev/null +++ b/css/css-animations/animation-delay-start-liveness-002.tentative.html @@ -0,0 +1,40 @@ + + + +CSS Animations Test: animation-delay-start - liveness with animationend + + + + + +
+ + diff --git a/css/css-animations/animation-delay-start-liveness-003.tentative.html b/css/css-animations/animation-delay-start-liveness-003.tentative.html new file mode 100644 index 00000000000000..a15c82514e0f26 --- /dev/null +++ b/css/css-animations/animation-delay-start-liveness-003.tentative.html @@ -0,0 +1,40 @@ + + + +CSS Animations Test: animation-delay-start - liveness with animationstart + + + + + +
+ + diff --git a/css/css-animations/event-dispatch.tentative.html b/css/css-animations/event-dispatch.tentative.html index 8c5b7e3ae15e2a..765493caaea5f3 100644 --- a/css/css-animations/event-dispatch.tentative.html +++ b/css/css-animations/event-dispatch.tentative.html @@ -281,6 +281,46 @@ assert_equals(animation.playState, 'running'); // delay }, 'Negative playbackRate sanity test(Before -> Active -> Before)'); +promise_test(async t => { + const div = addDiv(t, { + style: 'animation: anim 100s paused; animation-delay-end: 50s' + }); + const animation = div.getAnimations()[0]; + const timeoutPromise = armTimeoutWhenReady(animation, fastEventsTimeout); + const watcher = new EventWatcher(t, div, ['animationstart', 'animationend'], + timeoutPromise); + + await animation.ready; + animation.finish(); + + const events = await watcher.wait_for(['animationstart', 'animationend'], { + record: 'all', + }); + assert_equals(events[1].elapsedTime, 100.0, + 'animationend elapsedTime is active duration, not including end delay'); + + await waitForAnimationFrames(2); +}, 'animationend fires at active duration regardless of end delay'); + +promise_test(async t => { + const div = addDiv(t, { + style: 'animation: anim 100s reverse 100s paused; animation-delay-end: 50s' + }); + const animation = div.getAnimations()[0]; + const timeoutPromise = armTimeoutWhenReady(animation, fastEventsTimeout); + const watcher = new EventWatcher(t, div, ['animationstart', 'animationend'], + timeoutPromise); + + await animation.ready; + animation.finish(); + await watcher.wait_for(['animationstart', 'animationend']); + + animation.playbackRate = -1; + + const evt = await watcher.wait_for('animationstart'); + assert_equals(evt.elapsedTime, 100.0); +}, 'Reverse playback with end delay dispatches animationstart when entering active phase'); + promise_test(async t => { const { animation, watcher } = setupAnimation(t, 'anim 100s 100s'); diff --git a/css/css-animations/inheritance.html b/css/css-animations/inheritance.html index 6e7697b9d81db6..42c9dd74b8877c 100644 --- a/css/css-animations/inheritance.html +++ b/css/css-animations/inheritance.html @@ -16,6 +16,8 @@ diff --git a/css/css-animations/parsing/animation-delay-computed.html b/css/css-animations/parsing/animation-delay-computed.html index ba544232abdcba..edee92f3b7df7c 100644 --- a/css/css-animations/parsing/animation-delay-computed.html +++ b/css/css-animations/parsing/animation-delay-computed.html @@ -3,7 +3,7 @@ CSS Animations: getComputedStyle().animationDelay - + @@ -24,6 +24,10 @@ test_computed_value("animation-delay", "calc(2 * 3s)", "6s"); test_computed_value("animation-delay", "20s, 10s"); test_computed_value("animation-delay", 'calc(10s + (sign(2cqw - 10px) * 5s))', '5s'); +test_computed_value("animation-delay", "1s 2s"); +test_computed_value("animation-delay", "1s 2s, 3s 4s"); +test_computed_value("animation-delay-start", "-500ms", "-0.5s"); +test_computed_value("animation-delay-end", "500ms", "0.5s"); diff --git a/css/css-animations/parsing/animation-delay-end-computed.tentative.html b/css/css-animations/parsing/animation-delay-end-computed.tentative.html new file mode 100644 index 00000000000000..d9f25bc60718eb --- /dev/null +++ b/css/css-animations/parsing/animation-delay-end-computed.tentative.html @@ -0,0 +1,30 @@ + + + + +CSS Animations: getComputedStyle().animationDelayEnd + + + + + + + + +
+
+
+ + + diff --git a/css/css-animations/parsing/animation-delay-end-invalid.tentative.html b/css/css-animations/parsing/animation-delay-end-invalid.tentative.html new file mode 100644 index 00000000000000..e46d717efc592f --- /dev/null +++ b/css/css-animations/parsing/animation-delay-end-invalid.tentative.html @@ -0,0 +1,22 @@ + + + + +CSS Animations: parsing animation-delay-end with invalid values + + + + + + + + + + diff --git a/css/css-animations/parsing/animation-delay-end-valid.tentative.html b/css/css-animations/parsing/animation-delay-end-valid.tentative.html new file mode 100644 index 00000000000000..ddd9ddc89d4429 --- /dev/null +++ b/css/css-animations/parsing/animation-delay-end-valid.tentative.html @@ -0,0 +1,22 @@ + + + + +CSS Animations: parsing animation-delay-end with valid values + + + + + + + + + + diff --git a/css/css-animations/parsing/animation-delay-invalid.html b/css/css-animations/parsing/animation-delay-invalid.html index 1569497bb6a452..4aaed10760f1a9 100644 --- a/css/css-animations/parsing/animation-delay-invalid.html +++ b/css/css-animations/parsing/animation-delay-invalid.html @@ -3,8 +3,8 @@ CSS Animations: parsing animation-delay with invalid values - - + + diff --git a/css/css-animations/parsing/animation-delay-shorthand.tentative.html b/css/css-animations/parsing/animation-delay-shorthand.tentative.html new file mode 100644 index 00000000000000..2fdaf317bcb27e --- /dev/null +++ b/css/css-animations/parsing/animation-delay-shorthand.tentative.html @@ -0,0 +1,55 @@ + + + + +CSS Animations: animation-delay shorthand + + + + + + + + +
+ + + diff --git a/css/css-animations/parsing/animation-delay-start-computed.tentative.html b/css/css-animations/parsing/animation-delay-start-computed.tentative.html new file mode 100644 index 00000000000000..47ce2edcb79881 --- /dev/null +++ b/css/css-animations/parsing/animation-delay-start-computed.tentative.html @@ -0,0 +1,30 @@ + + + + +CSS Animations: getComputedStyle().animationDelayStart + + + + + + + + +
+
+
+ + + diff --git a/css/css-animations/parsing/animation-delay-start-invalid.tentative.html b/css/css-animations/parsing/animation-delay-start-invalid.tentative.html new file mode 100644 index 00000000000000..7f1a70282fdf14 --- /dev/null +++ b/css/css-animations/parsing/animation-delay-start-invalid.tentative.html @@ -0,0 +1,22 @@ + + + + +CSS Animations: parsing animation-delay-start with invalid values + + + + + + + + + + diff --git a/css/css-animations/parsing/animation-delay-start-valid.tentative.html b/css/css-animations/parsing/animation-delay-start-valid.tentative.html new file mode 100644 index 00000000000000..51396a7dec9ca8 --- /dev/null +++ b/css/css-animations/parsing/animation-delay-start-valid.tentative.html @@ -0,0 +1,24 @@ + + + + +CSS Animations: parsing animation-delay-start with valid values + + + + + + + + + + diff --git a/css/css-animations/parsing/animation-delay-valid.html b/css/css-animations/parsing/animation-delay-valid.html index 5ff0416cc64241..d9d2b465ed398e 100644 --- a/css/css-animations/parsing/animation-delay-valid.html +++ b/css/css-animations/parsing/animation-delay-valid.html @@ -3,8 +3,8 @@ CSS Animations: parsing animation-delay with valid values - - + + @@ -15,6 +15,9 @@ test_valid_value("animation-delay", "0s"); test_valid_value("animation-delay", "10s"); test_valid_value("animation-delay", "20s, 10s"); +test_valid_value("animation-delay", "1s 2s"); +test_valid_value("animation-delay", "1s 2s, 3s 4s"); +test_valid_value("animation-delay", "-50ms 2s, -300ms 4s"); diff --git a/css/css-animations/parsing/animation-shorthand.html b/css/css-animations/parsing/animation-shorthand.html index 0856ab24a04634..5381964d2cde09 100644 --- a/css/css-animations/parsing/animation-shorthand.html +++ b/css/css-animations/parsing/animation-shorthand.html @@ -3,7 +3,7 @@ CSS Animations: animation sets longhands - + @@ -14,7 +14,7 @@ test_shorthand_value('animation', 'anim paused both reverse 4 1s -3s cubic-bezier(0, -2, 1, 3)', { 'animation-duration': '1s', 'animation-timing-function': 'cubic-bezier(0, -2, 1, 3)', - 'animation-delay': '-3s', + 'animation-delay-start': '-3s', 'animation-iteration-count': '4', 'animation-direction': 'reverse', 'animation-fill-mode': 'both', @@ -28,7 +28,7 @@ test_shorthand_value('animation', 'anim paused both reverse, 4 1s -3s cubic-bezier(0, -2, 1, 3)', { 'animation-duration': 'auto, 1s', 'animation-timing-function': 'ease, cubic-bezier(0, -2, 1, 3)', - 'animation-delay': '0s, -3s', + 'animation-delay-start': '0s, -3s', 'animation-iteration-count': '1, 4', 'animation-direction': 'reverse, normal', 'animation-fill-mode': 'both, none', @@ -42,7 +42,7 @@ test_shorthand_value('animation', '4 1s -3s cubic-bezier(0, -2, 1, 3), anim paused both reverse', { 'animation-duration': '1s, auto', 'animation-timing-function': 'cubic-bezier(0, -2, 1, 3), ease', - 'animation-delay': '-3s, 0s', + 'animation-delay-start': '-3s, 0s', 'animation-iteration-count': '4, 1', 'animation-direction': 'normal, reverse', 'animation-fill-mode': 'none, both', diff --git a/css/css-animations/parsing/animation-valid.html b/css/css-animations/parsing/animation-valid.html index e0b54dca2f2655..df3332780ce417 100644 --- a/css/css-animations/parsing/animation-valid.html +++ b/css/css-animations/parsing/animation-valid.html @@ -11,7 +11,7 @@