summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/css/css-transitions
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /testing/web-platform/tests/css/css-transitions
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/css/css-transitions')
-rw-r--r--testing/web-platform/tests/css/css-transitions/AnimationEffect-getComputedTiming.tentative.html344
-rw-r--r--testing/web-platform/tests/css/css-transitions/CSSTransition-canceling.tentative.html252
-rw-r--r--testing/web-platform/tests/css/css-transitions/CSSTransition-currentTime.tentative.html145
-rw-r--r--testing/web-platform/tests/css/css-transitions/CSSTransition-effect.tentative.html239
-rw-r--r--testing/web-platform/tests/css/css-transitions/CSSTransition-finished.tentative.html40
-rw-r--r--testing/web-platform/tests/css/css-transitions/CSSTransition-ready.tentative.html73
-rw-r--r--testing/web-platform/tests/css/css-transitions/CSSTransition-startTime.tentative.html124
-rw-r--r--testing/web-platform/tests/css/css-transitions/CSSTransition-transitionProperty.tentative.html28
-rw-r--r--testing/web-platform/tests/css/css-transitions/Document-getAnimations.tentative.html196
-rw-r--r--testing/web-platform/tests/css/css-transitions/Element-getAnimations.tentative.html117
-rw-r--r--testing/web-platform/tests/css/css-transitions/KeyframeEffect-getKeyframes-width-and-height-transition.tentative.html43
-rw-r--r--testing/web-platform/tests/css/css-transitions/KeyframeEffect-getKeyframes.tentative.html169
-rw-r--r--testing/web-platform/tests/css/css-transitions/KeyframeEffect-setKeyframes.tentative.html177
-rw-r--r--testing/web-platform/tests/css/css-transitions/KeyframeEffect-target.tentative.html69
-rw-r--r--testing/web-platform/tests/css/css-transitions/META.yml3
-rw-r--r--testing/web-platform/tests/css/css-transitions/README.md75
-rw-r--r--testing/web-platform/tests/css/css-transitions/all-with-discrete.tentative.html41
-rw-r--r--testing/web-platform/tests/css/css-transitions/animations/animate-with-color-mix.html146
-rw-r--r--testing/web-platform/tests/css/css-transitions/animations/change-duration-during-transition.html61
-rw-r--r--testing/web-platform/tests/css/css-transitions/animations/color-transition-premultiplied.html69
-rw-r--r--testing/web-platform/tests/css/css-transitions/animations/move-after-transition.html62
-rw-r--r--testing/web-platform/tests/css/css-transitions/animations/text-shadow-composition.html101
-rw-r--r--testing/web-platform/tests/css/css-transitions/animations/text-shadow-interpolation.html123
-rw-r--r--testing/web-platform/tests/css/css-transitions/animations/transition-end-event-shorthands.html65
-rw-r--r--testing/web-platform/tests/css/css-transitions/animations/transition-timing-function.html87
-rw-r--r--testing/web-platform/tests/css/css-transitions/animations/vertical-align-composition.html65
-rw-r--r--testing/web-platform/tests/css/css-transitions/animations/vertical-align-interpolation.html98
-rw-r--r--testing/web-platform/tests/css/css-transitions/animations/z-index-interpolation.html130
-rw-r--r--testing/web-platform/tests/css/css-transitions/before-load-001.html46
-rw-r--r--testing/web-platform/tests/css/css-transitions/changing-while-transition-001.html56
-rw-r--r--testing/web-platform/tests/css/css-transitions/changing-while-transition-002.html56
-rw-r--r--testing/web-platform/tests/css/css-transitions/changing-while-transition-003.html56
-rw-r--r--testing/web-platform/tests/css/css-transitions/changing-while-transition-004.html57
-rw-r--r--testing/web-platform/tests/css/css-transitions/crashtests/transition-during-style-attr-mutation.html12
-rw-r--r--testing/web-platform/tests/css/css-transitions/crashtests/transition-large-word-spacing-001.html15
-rw-r--r--testing/web-platform/tests/css/css-transitions/currentcolor-animation-001.html53
-rw-r--r--testing/web-platform/tests/css/css-transitions/disconnected-element-001.html190
-rw-r--r--testing/web-platform/tests/css/css-transitions/display-none-no-animations.html28
-rw-r--r--testing/web-platform/tests/css/css-transitions/dynamic-root-element.html34
-rw-r--r--testing/web-platform/tests/css/css-transitions/event-dispatch.tentative.html435
-rw-r--r--testing/web-platform/tests/css/css-transitions/events-001.html150
-rw-r--r--testing/web-platform/tests/css/css-transitions/events-002.html49
-rw-r--r--testing/web-platform/tests/css/css-transitions/events-003.html34
-rw-r--r--testing/web-platform/tests/css/css-transitions/events-004.html61
-rw-r--r--testing/web-platform/tests/css/css-transitions/events-005.html67
-rw-r--r--testing/web-platform/tests/css/css-transitions/events-006.html58
-rw-r--r--testing/web-platform/tests/css/css-transitions/events-007.html50
-rw-r--r--testing/web-platform/tests/css/css-transitions/historical.html18
-rw-r--r--testing/web-platform/tests/css/css-transitions/idlharness-2.html28
-rw-r--r--testing/web-platform/tests/css/css-transitions/idlharness.html24
-rw-r--r--testing/web-platform/tests/css/css-transitions/inert-while-transitioning-to-display-none.html32
-rw-r--r--testing/web-platform/tests/css/css-transitions/infinite-duration-crash.html16
-rw-r--r--testing/web-platform/tests/css/css-transitions/inherit-background-color-transition-ref.html6
-rw-r--r--testing/web-platform/tests/css/css-transitions/inherit-background-color-transition.html41
-rw-r--r--testing/web-platform/tests/css/css-transitions/inherit-height-transition.html26
-rw-r--r--testing/web-platform/tests/css/css-transitions/inheritance.html24
-rw-r--r--testing/web-platform/tests/css/css-transitions/non-rendered-element-001.html127
-rw-r--r--testing/web-platform/tests/css/css-transitions/non-rendered-element-002.html57
-rw-r--r--testing/web-platform/tests/css/css-transitions/non-rendered-element-004.tentative.html51
-rw-r--r--testing/web-platform/tests/css/css-transitions/parsing/transition-behavior.html57
-rw-r--r--testing/web-platform/tests/css/css-transitions/parsing/transition-computed.html43
-rw-r--r--testing/web-platform/tests/css/css-transitions/parsing/transition-delay-computed.html18
-rw-r--r--testing/web-platform/tests/css/css-transitions/parsing/transition-delay-invalid.html22
-rw-r--r--testing/web-platform/tests/css/css-transitions/parsing/transition-delay-valid.html20
-rw-r--r--testing/web-platform/tests/css/css-transitions/parsing/transition-duration-computed.html20
-rw-r--r--testing/web-platform/tests/css/css-transitions/parsing/transition-duration-invalid.html22
-rw-r--r--testing/web-platform/tests/css/css-transitions/parsing/transition-duration-valid.html19
-rw-r--r--testing/web-platform/tests/css/css-transitions/parsing/transition-invalid.html27
-rw-r--r--testing/web-platform/tests/css/css-transitions/parsing/transition-property-computed.html19
-rw-r--r--testing/web-platform/tests/css/css-transitions/parsing/transition-property-invalid.html32
-rw-r--r--testing/web-platform/tests/css/css-transitions/parsing/transition-property-valid.html22
-rw-r--r--testing/web-platform/tests/css/css-transitions/parsing/transition-shorthand.html39
-rw-r--r--testing/web-platform/tests/css/css-transitions/parsing/transition-timing-function-computed.html38
-rw-r--r--testing/web-platform/tests/css/css-transitions/parsing/transition-timing-function-invalid.html38
-rw-r--r--testing/web-platform/tests/css/css-transitions/parsing/transition-timing-function-valid.html41
-rw-r--r--testing/web-platform/tests/css/css-transitions/parsing/transition-valid.html34
-rw-r--r--testing/web-platform/tests/css/css-transitions/properties-value-001.html133
-rw-r--r--testing/web-platform/tests/css/css-transitions/properties-value-002.html135
-rw-r--r--testing/web-platform/tests/css/css-transitions/properties-value-003.html137
-rw-r--r--testing/web-platform/tests/css/css-transitions/properties-value-implicit-001.html142
-rw-r--r--testing/web-platform/tests/css/css-transitions/properties-value-inherit-001.html143
-rw-r--r--testing/web-platform/tests/css/css-transitions/properties-value-inherit-002.html144
-rw-r--r--testing/web-platform/tests/css/css-transitions/properties-value-inherit-003.html143
-rw-r--r--testing/web-platform/tests/css/css-transitions/pseudo-elements-001.html148
-rw-r--r--testing/web-platform/tests/css/css-transitions/pseudo-elements-002.html28
-rw-r--r--testing/web-platform/tests/css/css-transitions/reference/transition-test-ref.html40
-rw-r--r--testing/web-platform/tests/css/css-transitions/render-blocking/no-transition-from-ua-to-blocking-stylesheet-ref.html3
-rw-r--r--testing/web-platform/tests/css/css-transitions/render-blocking/no-transition-from-ua-to-blocking-stylesheet.html6
-rw-r--r--testing/web-platform/tests/css/css-transitions/retargetted-transition-with-box-sizing.html24
-rw-r--r--testing/web-platform/tests/css/css-transitions/root-color-transition-ref.html4
-rw-r--r--testing/web-platform/tests/css/css-transitions/root-color-transition.html40
-rw-r--r--testing/web-platform/tests/css/css-transitions/starting-of-transitions-001.html45
-rw-r--r--testing/web-platform/tests/css/css-transitions/starting-style-cascade.html101
-rw-r--r--testing/web-platform/tests/css/css-transitions/starting-style-name-defining-rules.html58
-rw-r--r--testing/web-platform/tests/css/css-transitions/starting-style-rule-basic.html58
-rw-r--r--testing/web-platform/tests/css/css-transitions/starting-style-rule-none.html32
-rw-r--r--testing/web-platform/tests/css/css-transitions/starting-style-rule-pseudo-elements.html59
-rw-r--r--testing/web-platform/tests/css/css-transitions/starting-style-size-container.html43
-rw-r--r--testing/web-platform/tests/css/css-transitions/support/1x1-green.pngbin0 -> 135 bytes
-rw-r--r--testing/web-platform/tests/css/css-transitions/support/1x1-lime.pngbin0 -> 135 bytes
-rw-r--r--testing/web-platform/tests/css/css-transitions/support/1x1-maroon.pngbin0 -> 109 bytes
-rw-r--r--testing/web-platform/tests/css/css-transitions/support/1x1-navy.pngbin0 -> 109 bytes
-rw-r--r--testing/web-platform/tests/css/css-transitions/support/1x1-red.pngbin0 -> 135 bytes
-rw-r--r--testing/web-platform/tests/css/css-transitions/support/1x1-white.pngbin0 -> 109 bytes
-rw-r--r--testing/web-platform/tests/css/css-transitions/support/60x60-gg-rr.pngbin0 -> 224 bytes
-rw-r--r--testing/web-platform/tests/css/css-transitions/support/60x60-green.pngbin0 -> 218 bytes
-rw-r--r--testing/web-platform/tests/css/css-transitions/support/README28
-rw-r--r--testing/web-platform/tests/css/css-transitions/support/a-green-transition.css1
-rw-r--r--testing/web-platform/tests/css/css-transitions/support/a-green.css1
-rw-r--r--testing/web-platform/tests/css/css-transitions/support/b-green.css1
-rw-r--r--testing/web-platform/tests/css/css-transitions/support/c-red.css1
-rw-r--r--testing/web-platform/tests/css/css-transitions/support/cat.pngbin0 -> 1883 bytes
-rw-r--r--testing/web-platform/tests/css/css-transitions/support/generalParallelTest.js231
-rw-r--r--testing/web-platform/tests/css/css-transitions/support/helper.js326
-rw-r--r--testing/web-platform/tests/css/css-transitions/support/import-green.css1
-rw-r--r--testing/web-platform/tests/css/css-transitions/support/import-red.css1
-rw-r--r--testing/web-platform/tests/css/css-transitions/support/one.gifbin0 -> 184 bytes
-rw-r--r--testing/web-platform/tests/css/css-transitions/support/pattern-grg-rgr-grg.pngbin0 -> 222 bytes
-rw-r--r--testing/web-platform/tests/css/css-transitions/support/pattern-grg-rrg-rgg.pngbin0 -> 231 bytes
-rw-r--r--testing/web-platform/tests/css/css-transitions/support/pattern-rgr-grg-rgr.pngbin0 -> 223 bytes
-rw-r--r--testing/web-platform/tests/css/css-transitions/support/pattern-tr.pngbin0 -> 137 bytes
-rw-r--r--testing/web-platform/tests/css/css-transitions/support/properties.js410
-rw-r--r--testing/web-platform/tests/css/css-transitions/support/ruler-h-50%.pngbin0 -> 691 bytes
-rw-r--r--testing/web-platform/tests/css/css-transitions/support/ruler-h-50px.pngbin0 -> 671 bytes
-rw-r--r--testing/web-platform/tests/css/css-transitions/support/ruler-v-100px.pngbin0 -> 760 bytes
-rw-r--r--testing/web-platform/tests/css/css-transitions/support/ruler-v-50px.pngbin0 -> 757 bytes
-rw-r--r--testing/web-platform/tests/css/css-transitions/support/runParallelAsyncHarness.js148
-rw-r--r--testing/web-platform/tests/css/css-transitions/support/square-purple.pngbin0 -> 92 bytes
-rw-r--r--testing/web-platform/tests/css/css-transitions/support/square-teal.pngbin0 -> 92 bytes
-rw-r--r--testing/web-platform/tests/css/css-transitions/support/square-white.pngbin0 -> 78 bytes
-rw-r--r--testing/web-platform/tests/css/css-transitions/support/support/README4
-rw-r--r--testing/web-platform/tests/css/css-transitions/support/support/swatch-green.pngbin0 -> 84 bytes
-rw-r--r--testing/web-platform/tests/css/css-transitions/support/support/swatch-red.pngbin0 -> 84 bytes
-rw-r--r--testing/web-platform/tests/css/css-transitions/support/swatch-blue.pngbin0 -> 84 bytes
-rw-r--r--testing/web-platform/tests/css/css-transitions/support/swatch-green.pngbin0 -> 84 bytes
-rw-r--r--testing/web-platform/tests/css/css-transitions/support/swatch-lime.pngbin0 -> 84 bytes
-rw-r--r--testing/web-platform/tests/css/css-transitions/support/swatch-orange.pngbin0 -> 84 bytes
-rw-r--r--testing/web-platform/tests/css/css-transitions/support/swatch-red.pngbin0 -> 84 bytes
-rw-r--r--testing/web-platform/tests/css/css-transitions/support/swatch-teal.pngbin0 -> 156 bytes
-rw-r--r--testing/web-platform/tests/css/css-transitions/support/swatch-white.pngbin0 -> 85 bytes
-rw-r--r--testing/web-platform/tests/css/css-transitions/support/swatch-yellow.pngbin0 -> 84 bytes
-rw-r--r--testing/web-platform/tests/css/css-transitions/support/test-bl.pngbin0 -> 1368 bytes
-rw-r--r--testing/web-platform/tests/css/css-transitions/support/test-br.pngbin0 -> 1045 bytes
-rw-r--r--testing/web-platform/tests/css/css-transitions/support/test-inner-half-size.pngbin0 -> 180 bytes
-rw-r--r--testing/web-platform/tests/css/css-transitions/support/test-outer.pngbin0 -> 2412 bytes
-rw-r--r--testing/web-platform/tests/css/css-transitions/support/test-tl.pngbin0 -> 1025 bytes
-rw-r--r--testing/web-platform/tests/css/css-transitions/support/test-tr.pngbin0 -> 1235 bytes
-rw-r--r--testing/web-platform/tests/css/css-transitions/support/two.gifbin0 -> 184 bytes
-rw-r--r--testing/web-platform/tests/css/css-transitions/support/vendorPrefix.js86
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-001.html63
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-after-animation-001.html47
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-background-position-with-edge-offset.html49
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-base-response-001.html74
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-base-response-002.html27
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-base-response-003.html28
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-delay-000-manual.html34
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-delay-001.html77
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-delay-002-manual.html45
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-delay-003-manual.html45
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-duration-001.html78
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-duration-002-manual.html34
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-duration-003-manual.html46
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-duration-004-manual.html40
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-duration-shorthand.html39
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-events-with-document-change.html34
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-important.html24
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-property-001.html44
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-property-002.html51
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-property-003-manual.html40
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-property-004-manual.html29
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-property-005-manual.html30
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-property-006-manual.html32
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-property-007-manual.html30
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-property-008-manual.html30
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-property-009-manual.html30
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-property-010-manual.html30
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-property-011-manual.html30
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-property-012-manual.html30
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-property-013-manual.html30
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-property-014-manual.html30
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-property-015-manual.html30
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-property-016-manual.html32
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-property-017-manual.html29
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-property-018-manual.html30
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-property-019-manual.html30
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-property-020-manual.html30
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-property-021-manual.html32
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-property-022-manual.html31
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-property-023-manual.html28
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-property-024-manual.html33
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-property-025-manual.html31
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-property-026-manual.html39
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-property-027-manual.html31
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-property-028-manual.html31
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-property-029-manual.html31
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-property-030-manual.html31
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-property-031-manual.html31
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-property-032-manual.html32
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-property-033-manual.html32
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-property-034-manual.html31
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-property-035-manual.html35
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-property-036-manual.html36
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-property-037-manual.html35
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-property-038-manual.html31
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-property-039-manual.html27
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-property-040-manual.html27
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-property-041-manual.html31
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-property-042-manual.html30
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-property-043-manual.html31
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-property-044-manual.html30
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-property-045-manual.html41
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-reparented.html39
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-test.html43
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-timing-function-002-manual.html39
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-timing-function-003-manual.html39
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-timing-function-004-manual.html39
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-timing-function-005-manual.html39
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-timing-function-006-manual.html39
-rw-r--r--testing/web-platform/tests/css/css-transitions/transition-timing-function-010-manual.html29
-rw-r--r--testing/web-platform/tests/css/css-transitions/transitioncancel-001.html65
-rw-r--r--testing/web-platform/tests/css/css-transitions/transitioncancel-002.html46
-rw-r--r--testing/web-platform/tests/css/css-transitions/transitionevent-interface.html229
-rw-r--r--testing/web-platform/tests/css/css-transitions/zero-duration-multiple-transition.html30
223 files changed, 11420 insertions, 0 deletions
diff --git a/testing/web-platform/tests/css/css-transitions/AnimationEffect-getComputedTiming.tentative.html b/testing/web-platform/tests/css/css-transitions/AnimationEffect-getComputedTiming.tentative.html
new file mode 100644
index 0000000000..3be69e8ee1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/AnimationEffect-getComputedTiming.tentative.html
@@ -0,0 +1,344 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>AnimationEffect.getComputedTiming() for CSS transitions</title>
+<!-- TODO: Add a more specific link for this once it is specified. -->
+<link rel="help" href="https://drafts.csswg.org/css-transitions-2/#csstransition">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/helper.js"></script>
+<script src="/web-animations/testcommon.js"></script>
+<style>
+
+.animated-div {
+ margin-left: 100px;
+}
+
+</style>
+<div id="log"></div>
+<script>
+
+'use strict';
+
+
+// --------------------
+// delay
+// --------------------
+
+test(t => {
+ const div = addDiv(t, { class: 'animated-div' });
+ div.style.transition = 'margin-left 10s';
+ getComputedStyle(div).marginLeft;
+ div.style.marginLeft = '10px';
+
+ const effect = div.getAnimations()[0].effect;
+ assert_equals(effect.getComputedTiming().delay, 0, 'Initial value of delay');
+}, 'delay of a new tranisition');
+
+test(t => {
+ const div = addDiv(t, { class: 'animated-div' });
+ div.style.transition = 'margin-left 10s 10s';
+ getComputedStyle(div).marginLeft;
+ div.style.marginLeft = '10px';
+
+ const effect = div.getAnimations()[0].effect;
+ assert_equals(effect.getComputedTiming().delay, 10000,
+ 'Initial value of delay');
+}, 'Positive delay of a new transition');
+
+test(t => {
+ const div = addDiv(t, { class: 'animated-div' });
+ div.style.transition = 'margin-left 10s -5s';
+ getComputedStyle(div).marginLeft;
+ div.style.marginLeft = '10px';
+
+ const effect = div.getAnimations()[0].effect;
+ assert_equals(effect.getComputedTiming().delay, -5000,
+ 'Initial value of delay');
+}, 'Negative delay of a new transition');
+
+
+// --------------------
+// endDelay
+// --------------------
+
+test(t => {
+ const div = addDiv(t, { class: 'animated-div' });
+ div.style.transition = 'margin-left 10s';
+ getComputedStyle(div).marginLeft;
+ div.style.marginLeft = '10px';
+
+ const effect = div.getAnimations()[0].effect;
+ assert_equals(effect.getComputedTiming().endDelay, 0,
+ 'Initial value of endDelay');
+}, 'endDelay of a new transition');
+
+
+// --------------------
+// fill
+// --------------------
+
+test(t => {
+ const div = addDiv(t, { class: 'animated-div' });
+ div.style.transition = 'margin-left 10s';
+ getComputedStyle(div).marginLeft;
+ div.style.marginLeft = '10px';
+
+ const effect = div.getAnimations()[0].effect;
+ assert_equals(effect.getComputedTiming().fill, 'backwards', 'Fill backwards');
+}, 'fill of a new transition');
+
+
+// --------------------
+// iterationStart
+// --------------------
+
+test(t => {
+ const div = addDiv(t, { class: 'animated-div' });
+ div.style.transition = 'margin-left 10s';
+ getComputedStyle(div).marginLeft;
+ div.style.marginLeft = '10px';
+
+ const effect = div.getAnimations()[0].effect;
+ assert_equals(effect.getComputedTiming().iterationStart, 0,
+ 'Initial value of iterationStart');
+}, 'iterationStart of a new transition');
+
+
+// --------------------
+// iterations
+// --------------------
+
+test(t => {
+ const div = addDiv(t, { class: 'animated-div' });
+ div.style.transition = 'margin-left 10s';
+ getComputedStyle(div).marginLeft;
+ div.style.marginLeft = '10px';
+
+ const effect = div.getAnimations()[0].effect;
+ assert_equals(effect.getComputedTiming().iterations, 1,
+ 'Initial value of iterations');
+}, 'iterations of a new transition');
+
+
+// --------------------
+// duration
+// --------------------
+
+test(t => {
+ const div = addDiv(t, { class: 'animated-div' });
+ div.style.transition = 'margin-left 10s';
+ getComputedStyle(div).marginLeft;
+ div.style.marginLeft = '10px';
+
+ const effect = div.getAnimations()[0].effect;
+ assert_equals(effect.getComputedTiming().duration, 10000,
+ 'Initial value of duration');
+}, 'duration of a new transition');
+
+
+// --------------------
+// direction
+// --------------------
+
+test(t => {
+ const div = addDiv(t, { class : 'animated-div' });
+ div.style.transition = 'margin-left 10s';
+ getComputedStyle(div).marginLeft;
+ div.style.marginLeft = '10px';
+
+ const effect = div.getAnimations()[0].effect;
+ assert_equals(effect.getComputedTiming().direction, 'normal',
+ 'Initial value of direction');
+}, 'direction of a new transition');
+
+
+// --------------------
+// easing
+// --------------------
+
+test(t => {
+ const div = addDiv(t, { class: 'animated-div' });
+ div.style.transition = 'margin-left 10s';
+ getComputedStyle(div).marginLeft;
+ div.style.marginLeft = '10px';
+
+ const effect = div.getAnimations()[0].effect;
+ assert_equals(effect.getComputedTiming().easing, 'ease',
+ 'Initial value of easing');
+}, 'easing of a new transition');
+
+test(t => {
+ const div = addDiv(t, { class: 'animated-div' });
+ div.style.transition = 'margin-left 10s steps(4)';
+ getComputedStyle(div).marginLeft;
+ div.style.marginLeft = '10px';
+
+ const effect = div.getAnimations()[0].effect;
+ assert_equals(effect.getComputedTiming().easing, 'steps(4)',
+ 'Initial value of easing');
+}, 'non-default easing of a new transition');
+
+
+// ------------------------------
+// endTime
+// = max(start delay + active duration + end delay, 0)
+// --------------------
+
+test(t => {
+ const div = addDiv(t, { class: 'animated-div' });
+ div.style.transition = 'margin-left 100s -5s';
+ getComputedStyle(div).marginLeft;
+ div.style.marginLeft = '10px';
+
+ const effect = div.getAnimations()[0].effect;
+ const answer = 100000 - 5000; // ms
+ assert_equals(effect.getComputedTiming().endTime, answer,
+ 'Initial value of endTime');
+}, 'endTime of a new transition');
+
+
+// --------------------
+// activeDuration
+// = iteration duration * iteration count(==1)
+// --------------------
+
+test(t => {
+ const div = addDiv(t, { class: 'animated-div' });
+ div.style.transition = 'margin-left 100s -5s';
+ getComputedStyle(div).marginLeft;
+ div.style.marginLeft = '10px';
+
+ const effect = div.getAnimations()[0].effect;
+ assert_equals(effect.getComputedTiming().activeDuration, 100000,
+ 'Initial value of activeDuration');
+}, 'activeDuration of a new transition');
+
+
+// --------------------
+// localTime
+// --------------------
+
+test(t => {
+ const div = addDiv(t, { class: 'animated-div' });
+ div.style.transition = 'margin-left 100s';
+ getComputedStyle(div).marginLeft;
+ div.style.marginLeft = '10px';
+
+ const effect = div.getAnimations()[0].effect;
+ assert_equals(effect.getComputedTiming().localTime, 0,
+ 'Initial value of localTime');
+}, 'localTime of a new transition');
+
+test(t => {
+ const div = addDiv(t, { class: 'animated-div' });
+ div.style.transition = 'margin-left 100s';
+ getComputedStyle(div).marginLeft;
+ div.style.marginLeft = '10px';
+
+ const anim = div.getAnimations()[0];
+ anim.currentTime = 5000;
+ assert_times_equal(anim.effect.getComputedTiming().localTime,
+ anim.currentTime,
+ 'current localTime after setting currentTime');
+}, 'localTime is always equal to currentTime');
+
+promise_test(async t => {
+ const div = addDiv(t, { class: 'animated-div' });
+ div.style.transition = 'margin-left 100s';
+ getComputedStyle(div).marginLeft;
+ div.style.marginLeft = '10px';
+
+ const anim = div.getAnimations()[0];
+ anim.playbackRate = 2; // 2 times faster
+
+ await anim.ready;
+
+ assert_times_equal(anim.effect.getComputedTiming().localTime,
+ anim.currentTime,
+ 'localTime is equal to currentTime');
+ await waitForFrame();
+
+ assert_times_equal(anim.effect.getComputedTiming().localTime,
+ anim.currentTime,
+ 'localTime is equal to currentTime');
+}, 'localTime reflects playbackRate immediately');
+
+
+// --------------------
+// progress
+// --------------------
+
+test(t => {
+ const div = addDiv(t, { class: 'animated-div' });
+ div.style.transition = 'margin-left 10.5s';
+ getComputedStyle(div).marginLeft;
+ div.style.marginLeft = '10px';
+
+ const effect = div.getAnimations()[0].effect;
+ assert_equals(effect.getComputedTiming().progress, 0.0,
+ 'Initial value of progress');
+}, 'progress of a new transition');
+
+test(t => {
+ const div = addDiv(t, { class: 'animated-div' });
+ div.style.transition = 'margin-left 10.5s 2s';
+ getComputedStyle(div).marginLeft;
+ div.style.marginLeft = '10px';
+
+ const effect = div.getAnimations()[0].effect;
+ assert_equals(effect.getComputedTiming().progress, 0.0,
+ 'Initial value of progress');
+}, 'progress of a new transition with positive delay in before phase');
+
+test(t => {
+ const div = addDiv(t, { class: 'animated-div' });
+ div.style.transition = 'margin-left 10.5s';
+ getComputedStyle(div).marginLeft;
+ div.style.marginLeft = '10px';
+
+ const anim = div.getAnimations()[0];
+ anim.finish();
+ assert_equals(anim.effect.getComputedTiming().progress, null,
+ 'finished progress');
+}, 'progress of a finished transition');
+
+
+// --------------------
+// currentIteration
+// --------------------
+
+test(t => {
+ const div = addDiv(t, { class: 'animated-div' });
+ div.style.transition = 'margin-left 10s';
+ getComputedStyle(div).marginLeft;
+ div.style.marginLeft = '10px';
+
+ const effect = div.getAnimations()[0].effect;
+ assert_equals(effect.getComputedTiming().currentIteration, 0,
+ 'Initial value of currentIteration');
+}, 'currentIteration of a new transition');
+
+test(t => {
+ const div = addDiv(t, { class: 'animated-div' });
+ div.style.transition = 'margin-left 10s 2s';
+ getComputedStyle(div).marginLeft;
+ div.style.marginLeft = '10px';
+
+ const effect = div.getAnimations()[0].effect;
+ assert_equals(effect.getComputedTiming().currentIteration, 0,
+ 'Initial value of currentIteration');
+}, 'currentIteration of a new transition with positive delay in before phase');
+
+test(t => {
+ const div = addDiv(t, { class: 'animated-div' });
+ div.style.transition = 'margin-left 10s';
+ getComputedStyle(div).marginLeft;
+ div.style.marginLeft = '10px';
+
+ const anim = div.getAnimations()[0];
+ anim.finish();
+ assert_equals(anim.effect.getComputedTiming().currentIteration, null,
+ 'finished currentIteration');
+}, 'currentIteration of a finished transition');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-transitions/CSSTransition-canceling.tentative.html b/testing/web-platform/tests/css/css-transitions/CSSTransition-canceling.tentative.html
new file mode 100644
index 0000000000..72b1dbff43
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/CSSTransition-canceling.tentative.html
@@ -0,0 +1,252 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>Canceling a CSS transition</title>
+<link rel="help" href="https://drafts.csswg.org/css-transitions/#starting">
+<!-- TODO: Add a more specific link for this once it is specified. -->
+<link rel="help" href="https://drafts.csswg.org/css-transitions-2/#csstransition">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/helper.js"></script>
+<div id="log"></div>
+<script>
+'use strict';
+
+promise_test(async t => {
+ const div = addDiv(t, { style: 'margin-left: 0px' });
+ getComputedStyle(div).marginLeft;
+
+ div.style.transition = 'margin-left 100s';
+ div.style.marginLeft = '1000px';
+
+ const transition = div.getAnimations()[0];
+ await transition.ready;
+ await waitForFrame();
+
+ assert_not_equals(getComputedStyle(div).marginLeft, '1000px',
+ 'transform style is animated before canceling');
+ transition.cancel();
+ assert_equals(getComputedStyle(div).marginLeft, div.style.marginLeft,
+ 'transform style is no longer animated after canceling');
+}, 'Animated style is cleared after canceling a running CSS transition');
+
+promise_test(async t => {
+ const div = addDiv(t, { style: 'margin-left: 0px' });
+ getComputedStyle(div).marginLeft;
+
+ div.style.transition = 'margin-left 100s';
+ div.style.marginLeft = '1000px';
+
+ const transition = div.getAnimations()[0];
+ await transition.ready;
+
+ transition.cancel();
+ assert_equals(getComputedStyle(div).marginLeft, '1000px',
+ 'margin-left style is not animated after canceling');
+ transition.play();
+ assert_equals(getComputedStyle(div).marginLeft, '0px',
+ 'margin-left style is animated after re-starting transition');
+
+ await transition.ready;
+
+ assert_equals(transition.playState, 'running',
+ 'Transition succeeds in running after being re-started');
+}, 'After canceling a transition, it can still be re-used');
+
+promise_test(async t => {
+ const div = addDiv(t, { style: 'margin-left: 0px' });
+ getComputedStyle(div).marginLeft;
+
+ div.style.transition = 'margin-left 100s';
+ div.style.marginLeft = '1000px';
+
+ const transition = div.getAnimations()[0];
+ await transition.ready;
+
+ transition.finish();
+ transition.cancel();
+ assert_equals(getComputedStyle(div).marginLeft, '1000px',
+ 'margin-left style is not animated after canceling');
+ transition.play();
+ assert_equals(getComputedStyle(div).marginLeft, '0px',
+ 'margin-left style is animated after re-starting transition');
+
+ await transition.ready;
+
+ assert_equals(transition.playState, 'running',
+ 'Transition succeeds in running after being re-started');
+}, 'After canceling a finished transition, it can still be re-used');
+
+test(t => {
+ const div = addDiv(t, { style: 'margin-left: 0px' });
+ getComputedStyle(div).marginLeft;
+
+ div.style.transition = 'margin-left 100s';
+ div.style.marginLeft = '1000px';
+
+ const transition = div.getAnimations()[0];
+ transition.cancel();
+ assert_equals(getComputedStyle(div).marginLeft, '1000px',
+ 'margin-left style is not animated after canceling');
+
+ // Trigger a change to a transition property and check that this
+ // doesn't cause the animation to become live again
+ div.style.transitionDuration = '200s';
+ getComputedStyle(div).marginLeft;
+ assert_equals(getComputedStyle(div).marginLeft, '1000px',
+ 'margin-left style is still not animated after updating'
+ + ' transition-duration');
+ assert_equals(transition.playState, 'idle',
+ 'Transition is still idle after updating transition-duration');
+}, 'After canceling a transition, updating transition properties doesn\'t make'
+ + ' it live again');
+
+promise_test(async t => {
+ const div = addDiv(t, { style: 'margin-left: 0px' });
+ getComputedStyle(div).marginLeft;
+
+ div.style.transition = 'margin-left 100s';
+ div.style.marginLeft = '1000px';
+
+ const transition = div.getAnimations()[0];
+ await transition.ready;
+
+ assert_equals(transition.playState, 'running');
+ div.style.display = 'none';
+
+ await waitForFrame();
+
+ assert_equals(transition.playState, 'idle');
+ assert_equals(getComputedStyle(div).marginLeft, '1000px');
+}, 'Setting display:none on an element cancels its transitions');
+
+promise_test(async t => {
+ const parentDiv = addDiv(t);
+ const childDiv = document.createElement('div');
+ parentDiv.appendChild(childDiv);
+ childDiv.setAttribute('style', 'margin-left: 0px');
+
+ getComputedStyle(childDiv).marginLeft;
+
+ childDiv.style.transition = 'margin-left 100s';
+ childDiv.style.marginLeft = '1000px';
+
+ const transition = childDiv.getAnimations()[0];
+ await transition.ready;
+
+ assert_equals(transition.playState, 'running');
+ parentDiv.style.display = 'none';
+ await waitForFrame();
+
+ assert_equals(transition.playState, 'idle');
+ assert_equals(getComputedStyle(childDiv).marginLeft, '1000px');
+}, 'Setting display:none cancels transitions on a child element');
+
+promise_test(async t => {
+ const div = addDiv(t, { style: 'margin-left: 0px' });
+ getComputedStyle(div).marginLeft;
+
+ div.style.transition = 'margin-left 100s';
+ div.style.marginLeft = '1000px';
+
+ const transition = div.getAnimations()[0];
+ await transition.ready;
+
+ assert_equals(transition.playState, 'running');
+ // Set an unrecognized property value
+ div.style.transitionProperty = 'none';
+ getComputedStyle(div).marginLeft;
+ await waitForFrame();
+
+ assert_equals(transition.playState, 'idle');
+ assert_equals(getComputedStyle(div).marginLeft, '1000px');
+}, 'Removing a property from transition-property cancels transitions on that '+
+ 'property');
+
+promise_test(async t => {
+ const div = addDiv(t, { style: 'margin-left: 0px' });
+ getComputedStyle(div).marginLeft;
+
+ div.style.transition = 'margin-left 100s';
+ div.style.marginLeft = '1000px';
+
+ const transition = div.getAnimations()[0];
+ await transition.ready;
+
+ assert_equals(transition.playState, 'running');
+ div.style.transition = 'margin-left 10s -10s'; // combined duration is zero
+
+ // Note that simply setting the combined duration to zero is not enough to
+ // cancel the transition. We must also update the end value so that the,
+ // "the end value of the running transition is not equal to the value of the
+ // property in the after-change style" condition is true.
+ //
+ // (And note that the zero combined duration is not strictly necessary to
+ // cancel the original transition--but it does ensure another transition is
+ // not generated in its place.)
+
+ div.style.marginLeft = '2000px';
+ getComputedStyle(div).marginLeft;
+ await waitForFrame();
+
+ assert_equals(transition.playState, 'idle');
+ assert_equals(getComputedStyle(div).marginLeft, '2000px');
+}, 'Setting zero combined duration');
+
+promise_test(async t => {
+ const div = addDiv(t, { style: 'margin-left: 0px' });
+ getComputedStyle(div).marginLeft;
+
+ div.style.transition = 'margin-left 100s';
+ div.style.marginLeft = '1000px';
+
+ const transition = div.getAnimations()[0];
+ await transition.ready;
+
+ assert_equals(transition.playState, 'running');
+ div.style.marginLeft = '2000px';
+ getComputedStyle(div).marginLeft;
+ await waitForFrame();
+
+ assert_equals(transition.playState, 'idle');
+}, 'Changing style to another interpolable value cancels the original ' +
+ 'transition');
+
+promise_test(async t => {
+ const div = addDiv(t, { style: 'margin-left: 0px' });
+ getComputedStyle(div).marginLeft;
+
+ div.style.transition = 'margin-left 100s';
+ div.style.marginLeft = '1000px';
+
+ const transition = div.getAnimations()[0];
+ await transition.ready;
+
+ assert_equals(transition.playState, 'running');
+ div.style.marginLeft = 'auto';
+ getComputedStyle(div).marginLeft;
+ await waitForFrame();
+
+ assert_equals(div.getAnimations().length, 0,
+ 'There should be no transitions');
+ assert_equals(transition.playState, 'idle');
+}, 'An after-change style value can\'t be interpolated');
+
+promise_test(async t => {
+ const div = addDiv(t, { style: 'margin-left: 0px' });
+ getComputedStyle(div).marginLeft;
+
+ div.style.transition = 'margin-left 100s';
+ div.style.marginLeft = '1000px';
+
+ const transition = div.getAnimations()[0];
+ await transition.ready;
+
+ assert_equals(transition.playState, 'running');
+ div.style.marginLeft = '0px';
+ getComputedStyle(div).marginLeft;
+ await waitForFrame();
+
+ assert_equals(transition.playState, 'idle');
+}, 'Reversing a running transition cancels the original transition');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-transitions/CSSTransition-currentTime.tentative.html b/testing/web-platform/tests/css/css-transitions/CSSTransition-currentTime.tentative.html
new file mode 100644
index 0000000000..d663ab6447
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/CSSTransition-currentTime.tentative.html
@@ -0,0 +1,145 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>CSSTransition.currentTime</title>
+<!-- TODO: Add a more specific link for this once it is specified. -->
+<link rel="help" href="https://drafts.csswg.org/css-transitions-2/#csstransition">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/helper.js"></script>
+<div id="log"></div>
+<script>
+
+'use strict';
+
+const marginLeft = div => parseFloat(getComputedStyle(div).marginLeft);
+
+promise_test(async t => {
+ const div = addDiv(t, {
+ style: 'margin-left: 100px; transition: margin-left 100s linear 100s',
+ });
+ getComputedStyle(div).marginLeft;
+ div.style.marginLeft = '200px';
+
+ const animation = div.getAnimations()[0];
+ assert_equals(
+ animation.currentTime,
+ 0,
+ 'currentTime should initially be zero'
+ );
+
+ await animation.ready;
+
+ const seekTime = 150 * MS_PER_SEC;
+ animation.currentTime = seekTime;
+
+ assert_time_equals_literal(
+ animation.currentTime,
+ seekTime,
+ 'currentTime is updated'
+ );
+ assert_equals(getComputedStyle(div).marginLeft, '150px');
+}, 'currentTime can be used to seek a CSS transition');
+
+promise_test(async t => {
+ const div = addDiv(t, {
+ style: 'margin-left: 100px; transition: margin-left 100s linear 100s',
+ });
+ const eventWatcher = new EventWatcher(t, div, 'transitionend');
+ getComputedStyle(div).marginLeft;
+ div.style.marginLeft = '200px';
+
+ const animation = div.getAnimations()[0];
+ await animation.ready;
+
+ const marginLeft = () => parseFloat(getComputedStyle(div).marginLeft);
+ assert_equals(marginLeft(div), 100);
+
+ animation.currentTime = 100 * MS_PER_SEC;
+ assert_equals(marginLeft(div), 100);
+
+ animation.currentTime = 150 * MS_PER_SEC;
+ assert_equals(marginLeft(div), 150);
+
+ animation.currentTime = 200 * MS_PER_SEC;
+ await eventWatcher.wait_for('transitionend');
+ assert_equals(marginLeft(div), 200);
+}, 'Skipping forwards through transition');
+
+promise_test(async t => {
+ const div = addDiv(t, {
+ style: 'margin-left: 100px; transition: margin-left 100s linear 100s',
+ });
+ const eventWatcher = new EventWatcher(t, div, 'transitionend');
+ getComputedStyle(div).marginLeft;
+ div.style.marginLeft = '200px';
+
+ const animation = div.getAnimations()[0];
+ await animation.ready;
+
+ // Unlike in the case of CSS animations, we cannot skip to the end and skip
+ // backwards since when we reach the end the transition effect is removed and
+ // changes to the Animation object no longer affect the element. For
+ // this reason we only skip forwards as far as the 50% through point.
+
+ animation.currentTime = 150 * MS_PER_SEC;
+ assert_equals(marginLeft(div), 150);
+
+ animation.currentTime = 100 * MS_PER_SEC;
+ assert_equals(marginLeft(div), 100);
+}, 'Skipping backwards through transition');
+
+promise_test(async t => {
+ const div = addDiv(t, {
+ style: 'margin-left: 100px; transition: margin-left 100s linear 100s',
+ });
+ getComputedStyle(div).marginLeft;
+ div.style.marginLeft = '200px';
+ const animation = div.getAnimations()[0];
+
+ await animation.ready;
+
+ assert_throws_js(
+ TypeError,
+ () => {
+ animation.currentTime = null;
+ },
+ 'Expect TypeError exception on trying to set Animation.currentTime to null'
+ );
+}, 'Setting currentTime to null on a CSS transition throws');
+
+test(t => {
+ const div = addDiv(t);
+
+ div.style.left = '0px';
+ getComputedStyle(div).transitionProperty;
+ div.style.transition = 'left 100s ease-in';
+ div.style.left = '100px';
+
+ const transition = div.getAnimations()[0];
+
+ // Seek to the middle. Note, this is not equivalent to 50% progress since the
+ // timing-function is non-linear.
+ transition.currentTime = 50 * MS_PER_SEC;
+ const portion = transition.effect.getComputedTiming().progress;
+
+ // Reverse the transition.
+ div.style.left = '0px';
+ const reversedTransition = div.getAnimations()[0];
+
+ // If the transition reversing behavior does not advance the previous
+ // transition to the time set by currentTime, start and end values will both
+ // be 0px and no transition will be produced.
+ assert_not_equals(reversedTransition, undefined,
+ "A reversed transition is produced");
+
+ const expectedDuration = 100 * MS_PER_SEC * portion;
+ assert_approx_equals(
+ reversedTransition.effect.getComputedTiming().activeDuration,
+ expectedDuration,
+ 1,
+ "The reversed transition has correctly reduced duration"
+ );
+}, "Transition reversing behavior respects currentTime and uses the " +
+ "transition's current position.");
+
+</script>
diff --git a/testing/web-platform/tests/css/css-transitions/CSSTransition-effect.tentative.html b/testing/web-platform/tests/css/css-transitions/CSSTransition-effect.tentative.html
new file mode 100644
index 0000000000..b58c93d2e6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/CSSTransition-effect.tentative.html
@@ -0,0 +1,239 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>CSSTransition.effect</title>
+<!-- TODO: Add a more specific link for this once it is specified. -->
+<link rel="help" href="https://drafts.csswg.org/css-transitions-2/#csstransition">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src='support/helper.js'></script>
+<div id="log"></div>
+<script>
+'use strict';
+
+function singleFrame() {
+ return new Promise((resolve, reject) => {
+ requestAnimationFrame(resolve);
+ });
+}
+
+test(t => {
+ const div = addDiv(t);
+ div.style.left = '0px';
+
+ div.style.transition = 'left 100s';
+ getComputedStyle(div).left;
+ div.style.left = '100px';
+
+ const transition = div.getAnimations()[0];
+
+ transition.effect = null;
+
+ assert_equals(transition.transitionProperty, 'left');
+}, 'After setting a transition\'s effect to null, it still reports the'
+ + ' original transition property');
+
+promise_test(async t => {
+ const div = addDiv(t);
+ div.style.left = '0px';
+
+ div.style.transition = 'left 100s';
+ getComputedStyle(div).left;
+ div.style.left = '100px';
+
+ const transition = div.getAnimations()[0];
+ await transition.ready;
+
+ transition.effect = null;
+ assert_equals(transition.playState, 'finished');
+}, 'After setting a transition\'s effect to null, it becomes finished');
+
+promise_test(async t => {
+ const div = addDiv(t);
+ div.style.left = '0px';
+
+ div.style.transition = 'left 100s';
+ getComputedStyle(div).left;
+ div.style.left = '100px';
+
+ const transition = div.getAnimations()[0];
+ await transition.ready;
+
+ transition.effect = null;
+ assert_equals(getComputedStyle(div).left, '100px');
+}, 'After setting a transition\'s effect to null, style is updated');
+
+// This is a regression test for https://crbug.com/964113, where Chromium would
+// crash if the running transition's effect was set to null and a new transition
+// was started before the running one could finish.
+promise_test(async t => {
+ const div = addDiv(t);
+ div.style.left = '0px';
+
+ div.style.transition = 'left 100s';
+ getComputedStyle(div).left;
+ div.style.left = '100px';
+
+ assert_equals(div.getAnimations().length, 1);
+
+ const transition = div.getAnimations()[0];
+ await transition.ready;
+
+ // Without yielding to the rendering loop, set the current transition's
+ // effect to null and start a new transition. This should work correctly.
+ transition.effect = null;
+
+ div.style.left = '150px';
+
+ // This will run style update.
+ assert_equals(div.getAnimations().length, 1);
+
+ const new_transition = div.getAnimations()[0];
+ await new_transition.ready;
+
+ assert_equals(getComputedStyle(div).left, '100px');
+}, 'After setting a transition\'s effect to null, a new transition can be started');
+
+// This is a regression test for https://crbug.com/992668, where Chromium would
+// crash if the running transition's effect was set to null and the transition
+// was interrupted before it could finish due to the null effect.
+promise_test(async t => {
+ const div = addDiv(t);
+ div.style.left = '0px';
+
+ div.style.transition = 'left 100s';
+ getComputedStyle(div).left;
+ div.style.left = '100px';
+
+ assert_equals(div.getAnimations().length, 1);
+
+ const transition = div.getAnimations()[0];
+ await transition.ready;
+
+ // The transition needs to have a non-zero currentTime for the interruption
+ // reversal logic to apply.
+ while (getComputedStyle(div).left == '0px') {
+ await singleFrame();
+ }
+ assert_not_equals(transition.currentTime, 0);
+
+ // Without yielding to the rendering loop, set the current transition's
+ // effect to null and interrupt the transition. This should work correctly.
+ transition.effect = null;
+ div.style.left = '0px';
+
+ // Yield to the rendering loop. This should not crash.
+ await singleFrame();
+}, 'After setting a transition\'s effect to null, it should be possible to '
+ + 'interrupt that transition');
+
+promise_test(async t => {
+ const div = addDiv(t);
+ div.style.left = '0px';
+ div.style.width = '0px';
+
+ div.style.transition = 'left 100s';
+ getComputedStyle(div).left;
+ div.style.left = '100px';
+
+ const transition = div.getAnimations()[0];
+ await transition.ready;
+
+ transition.currentTime = 50 * MS_PER_SEC;
+ transition.effect = new KeyframeEffect(div,
+ { left: [ '0px' , '100px'] },
+ 20 * MS_PER_SEC);
+
+ assert_equals(transition.playState, 'finished');
+}, 'After setting a new keyframe effect with a shorter duration,'
+ + ' the transition becomes finished');
+
+promise_test(async t => {
+ const div = addDiv(t);
+ div.style.left = '0px';
+ div.style.width = '0px';
+
+ div.style.transition = 'left 100s';
+ getComputedStyle(div).left;
+ div.style.left = '100px';
+
+ const transition = div.getAnimations()[0];
+ transition.effect = new KeyframeEffect(div,
+ { marginLeft: [ '0px' , '100px'] },
+ 100 * MS_PER_SEC);
+ assert_equals(transition.transitionProperty, 'left');
+}, 'After setting a new keyframe effect targeting different properties,'
+ + ' the transition continues to report the original transition property');
+
+promise_test(async t => {
+ const div = addDiv(t);
+ div.style.left = '0px';
+ div.style.width = '0px';
+
+ div.style.transition = 'left 100s';
+ getComputedStyle(div).left;
+ div.style.left = '100px';
+
+ const transition = div.getAnimations()[0];
+ assert_true(transition.pending);
+
+ transition.effect = new KeyframeEffect(div,
+ { marginLeft: [ '0px' , '100px'] },
+ 100 * MS_PER_SEC);
+ assert_true(transition.pending);
+
+ // As a sanity check, check that the transition actually exits the
+ // pending state.
+ await transition.ready;
+ assert_false(transition.pending);
+}, 'After setting a new keyframe effect on a play-pending transition,'
+ + ' the transition remains pending');
+
+test(t => {
+ const div = addDiv(t);
+
+ div.style.left = '0px';
+ getComputedStyle(div).transitionProperty;
+ div.style.transition = 'left 100s';
+ div.style.left = '100px';
+
+ const transition = div.getAnimations()[0];
+ transition.effect = null;
+
+ assert_equals(transition.transitionProperty, 'left');
+}, 'A transition with no effect still returns the original transitionProperty');
+
+test(t => {
+ const div = addDiv(t);
+
+ div.style.left = '0px';
+ getComputedStyle(div).transitionProperty;
+ div.style.transition = 'left 100s';
+ div.style.left = '100px';
+
+ const transition = div.getAnimations()[0];
+
+ // Seek to the middle and get the portion.
+ transition.currentTime = 50 * MS_PER_SEC;
+ const portion = transition.effect.getComputedTiming().progress;
+
+ // Replace the effect but keep the original timing
+ transition.effect = new KeyframeEffect(
+ div,
+ { top: ['200px', '300px', '100px'] },
+ transition.effect.getTiming()
+ );
+
+ // Reverse the transition
+ div.style.left = '0px';
+ const reversedTransition = div.getAnimations()[0];
+
+ const expectedDuration = 100 * MS_PER_SEC * portion;
+ assert_approx_equals(
+ reversedTransition.effect.getComputedTiming().activeDuration,
+ expectedDuration,
+ 1
+ );
+}, 'A transition with a replaced effect still exhibits the regular transition'
+ + ' reversing behavior');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-transitions/CSSTransition-finished.tentative.html b/testing/web-platform/tests/css/css-transitions/CSSTransition-finished.tentative.html
new file mode 100644
index 0000000000..23750e7a98
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/CSSTransition-finished.tentative.html
@@ -0,0 +1,40 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>CSSTransition.finished</title>
+<!-- TODO: Add a more specific link for this once it is specified. -->
+<link rel="help" href="https://drafts.csswg.org/css-transitions-2/#csstransition">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/helper.js"></script>
+<style>
+
+.animated-div {
+ margin-left: 100px;
+ transition: margin-left 100s linear 100s;
+}
+
+</style>
+<div id="log"></div>
+<script>
+
+'use strict';
+
+promise_test(async t => {
+ const div = addDiv(t, { class: 'animated-div' });
+ getComputedStyle(div).marginLeft;
+ div.style.marginLeft = '200px';
+ const animation = div.getAnimations()[0];
+
+ animation.finish();
+ await animation.finished;
+
+ animation.play();
+ const marginLeft = parseFloat(getComputedStyle(div).marginLeft);
+ assert_equals(
+ marginLeft,
+ 100,
+ 'Replaying a finished transition should update the target element\'s style'
+ );
+}, 'Restarting a finished transition rewinds playback');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-transitions/CSSTransition-ready.tentative.html b/testing/web-platform/tests/css/css-transitions/CSSTransition-ready.tentative.html
new file mode 100644
index 0000000000..92aaa49059
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/CSSTransition-ready.tentative.html
@@ -0,0 +1,73 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>CSSTransition.ready</title>
+<!-- TODO: Add a more specific link for this once it is specified. -->
+<link rel="help" href="https://drafts.csswg.org/css-transitions-2/#csstransition">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/helper.js"></script>
+<div id="log"></div>
+<script>
+'use strict';
+
+promise_test(async t => {
+ const div = addDiv(t);
+
+ // Set up pending transition
+ div.style.transform = 'translate(0px)';
+ getComputedStyle(div).transform;
+ div.style.transition = 'transform 100s';
+ div.style.transform = 'translate(10px)';
+ getComputedStyle(div).transform;
+
+ const animation = div.getAnimations()[0];
+ assert_true(animation.pending, 'Animation is initially pending');
+ const readyPromise = animation.ready;
+
+ // Now remove transform from transition-property and flush styles
+ div.style.transitionProperty = 'none';
+ getComputedStyle(div).transitionProperty;
+
+ try {
+ await readyPromise;
+ assert_unreached('ready promise was fulfilled');
+ } catch (err) {
+ assert_equals(err.name, 'AbortError',
+ 'ready promise is rejected with AbortError');
+ assert_equals(animation.playState, 'idle',
+ 'Animation is idle after transition was canceled');
+ }
+}, 'ready promise is rejected when a transition is canceled by updating'
+ + ' transition-property');
+
+promise_test(async t => {
+ const div = addDiv(t);
+
+ // Set up pending transition
+ div.style.marginLeft = '0px';
+ getComputedStyle(div).marginLeft;
+ div.style.transition = 'margin-left 100s';
+ div.style.marginLeft = '100px';
+ getComputedStyle(div).marginLeft;
+
+ const animation = div.getAnimations()[0];
+ assert_true(animation.pending, 'Animation is initially pending');
+ const readyPromise = animation.ready;
+
+ // Update the transition to animate to something not-interpolable
+ div.style.marginLeft = 'auto';
+ getComputedStyle(div).marginLeft;
+
+ try {
+ await readyPromise;
+ assert_unreached('ready promise was fulfilled');
+ } catch (err) {
+ assert_equals(err.name, 'AbortError',
+ 'ready promise is rejected with AbortError');
+ assert_equals(animation.playState, 'idle',
+ 'Animation is idle after transition was canceled');
+ }
+}, 'ready promise is rejected when a transition is canceled by changing'
+ + ' the transition property to something not interpolable');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-transitions/CSSTransition-startTime.tentative.html b/testing/web-platform/tests/css/css-transitions/CSSTransition-startTime.tentative.html
new file mode 100644
index 0000000000..4dbe863419
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/CSSTransition-startTime.tentative.html
@@ -0,0 +1,124 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>CSSTransition.startTime</title>
+<!-- TODO: Add a more specific link for this once it is specified. -->
+<link rel="help" href="https://drafts.csswg.org/css-transitions-2/#csstransition">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/helper.js"></script>
+<div id="log"></div>
+<script>
+
+'use strict';
+
+test(t => {
+ const div = addDiv(t, {
+ style: 'margin-left: 100px; transition: margin-left 100s linear 100s',
+ });
+ getComputedStyle(div).marginLeft;
+ div.style.marginLeft = '200px';
+ const animation = div.getAnimations()[0];
+
+ assert_equals(animation.startTime, null, 'startTime is unresolved');
+}, 'The start time of a newly-created transition is unresolved');
+
+promise_test(async t => {
+ const div = addDiv(t);
+
+ div.style.left = '0px';
+ div.style.top = '0px';
+ getComputedStyle(div).transitionProperty;
+
+ div.style.transition = 'all 100s';
+ div.style.left = '100px';
+ div.style.top = '100px';
+
+ let animations = div.getAnimations();
+ assert_equals(animations.length, 2);
+ await waitForAllAnimations(animations);
+
+ assert_equals(animations[0].startTime, animations[1].startTime,
+ 'CSS transitions started together have the same start time');
+
+ await waitForAnimationFrames(1);
+
+ div.style.backgroundColor = 'green';
+
+ animations = div.getAnimations();
+ assert_equals(animations.length, 3);
+ await waitForAllAnimations(animations);
+
+ assert_less_than(animations[1].startTime, animations[2].startTime,
+ 'A CSS transition added in a later frame has a later start time');
+}, 'The start time of transitions is based on when they are generated');
+
+test(t => {
+ const div = addDiv(t, {
+ style: 'margin-left: 100px; transition: margin-left 100s linear 100s',
+ });
+ getComputedStyle(div).marginLeft;
+ div.style.marginLeft = '200px';
+ const animation = div.getAnimations()[0];
+
+ const timelineTime = animation.timeline.currentTime;
+ animation.startTime = timelineTime;
+
+ assert_times_equal(
+ animation.startTime,
+ timelineTime,
+ 'Check setting of startTime actually works'
+ );
+}, 'The start time of a transition can be set');
+
+promise_test(async t => {
+ const div = addDiv(t, {
+ style: 'margin-left: 100px; transition: margin-left 100s linear 100s',
+ });
+ getComputedStyle(div).marginLeft;
+ div.style.marginLeft = '200px';
+ const animation = div.getAnimations()[0];
+
+ await animation.ready;
+
+ const timelineTime = animation.timeline.currentTime;
+ const marginLeft = () => parseFloat(getComputedStyle(div).marginLeft);
+
+ animation.startTime = timelineTime - 100 * MS_PER_SEC;
+ assert_equals(marginLeft(), 100);
+
+ animation.startTime = timelineTime - 150 * MS_PER_SEC;
+ assert_equals(marginLeft(), 150);
+}, 'The start time can be set to seek a transition');
+
+promise_test(async t => {
+ const div = addDiv(t, {
+ style: 'margin-left: 100px; transition: margin-left 100s linear 100s',
+ });
+ const eventWatcher = new EventWatcher(t, div, [
+ 'transitionstart',
+ 'transitionend',
+ ]);
+ getComputedStyle(div).marginLeft;
+ div.style.marginLeft = '200px';
+ const animation = div.getAnimations()[0];
+
+ await animation.ready;
+
+ const timelineTime = animation.timeline.currentTime;
+
+ animation.startTime = timelineTime - 100 * MS_PER_SEC;
+ await frameTimeout(
+ eventWatcher.wait_for('transitionstart'),
+ 2,
+ 'transitionstart'
+ );
+
+ animation.startTime = timelineTime - 200 * MS_PER_SEC;
+ await frameTimeout(
+ eventWatcher.wait_for('transitionend'),
+ 2,
+ 'transitionend'
+ );
+}, 'Seeking a transition using start time dispatches transition events');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-transitions/CSSTransition-transitionProperty.tentative.html b/testing/web-platform/tests/css/css-transitions/CSSTransition-transitionProperty.tentative.html
new file mode 100644
index 0000000000..8eb284107d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/CSSTransition-transitionProperty.tentative.html
@@ -0,0 +1,28 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>CSSTransition.transitionProperty</title>
+<link rel="help" href="https://drafts.csswg.org/css-transitions-2/#dom-csstransition-transitionproperty">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/helper.js"></script>
+<div id="log"></div>
+<script>
+'use strict';
+
+test(t => {
+ const div = addDiv(t);
+
+ div.style.left = '0px';
+ getComputedStyle(div).transitionProperty;
+ div.style.transition = 'all 100s';
+ div.style.left = '100px';
+
+ assert_equals(
+ div.getAnimations()[0].transitionProperty,
+ 'left',
+ 'The transitionProperty for the returned transition corresponds to the'
+ + ' specific property being transitioned'
+ );
+}, 'CSSTransition.transitionProperty');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-transitions/Document-getAnimations.tentative.html b/testing/web-platform/tests/css/css-transitions/Document-getAnimations.tentative.html
new file mode 100644
index 0000000000..d1cf6e499b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/Document-getAnimations.tentative.html
@@ -0,0 +1,196 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>Document.getAnimations() for CSS transitions</title>
+<link rel="help" href="https://drafts.csswg.org/css-transitions-2/#animation-composite-order">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/helper.js"></script>
+<div id="log"></div>
+<script>
+'use strict';
+
+test(t => {
+ assert_equals(document.getAnimations().length, 0,
+ 'getAnimations returns an empty sequence for a document'
+ + ' with no animations');
+}, 'getAnimations for non-animated content');
+
+test(t => {
+ const div = addDiv(t);
+
+ // Add a couple of transitions
+ div.style.left = '0px';
+ div.style.top = '0px';
+ getComputedStyle(div).transitionProperty;
+
+ div.style.transition = 'all 100s';
+ div.style.left = '100px';
+ div.style.top = '100px';
+ assert_equals(document.getAnimations().length, 2,
+ 'getAnimations returns two running CSS Transitions');
+
+ // Remove both
+ div.style.transitionProperty = 'none';
+ assert_equals(document.getAnimations().length, 0,
+ 'getAnimations returns no running CSS Transitions');
+}, 'getAnimations for CSS Transitions');
+
+test(t => {
+ const div = addDiv(t);
+
+ // Add a couple of transitions
+ div.style.top = '0px';
+ div.style.left = '0px';
+ getComputedStyle(div).transitionProperty;
+
+ div.style.transition = 'all 100s';
+ div.style.top = '100px';
+ div.style.left = '100px';
+
+ var animations = document.getAnimations();
+ assert_equals(animations.length, 2,
+ 'getAnimations returns two running CSS Transitions');
+ assert_equals(animations[0].transitionProperty, 'left');
+ assert_equals(animations[1].transitionProperty, 'top');
+}, 'getAnimations for CSS Transitions sort by property name');
+
+promise_test(async t => {
+ const div = addDiv(t);
+
+ // Add a couple of transitions
+ div.style.top = '0px';
+ div.style.left = '0px';
+ getComputedStyle(div).transitionProperty;
+
+ div.style.transition = 'all 100s';
+ div.style.top = '100px';
+ div.style.left = '100px';
+
+ var animations = document.getAnimations();
+ assert_equals(animations.length, 2,
+ 'getAnimations returns two running CSS Transitions');
+ assert_equals(animations[0].transitionProperty, 'left');
+ assert_equals(animations[1].transitionProperty, 'top');
+
+ // Add one more transition. As the previous call to getAnimations triggered a
+ // style change, the new animation is in a higher transition generation even
+ // though no frame was rendered for the previous transitions.
+ div.style.opacity = '1'
+ div.style.transition = 'all 100s';
+ div.style.opacity = '0'
+ animations = document.getAnimations();
+ assert_equals(animations.length, 3,
+ 'getAnimations returns three running CSS Transitions');
+ assert_equals(animations[0].transitionProperty, 'left', '1');
+ assert_equals(animations[1].transitionProperty, 'top', '2');
+ assert_equals(animations[2].transitionProperty, 'opacity', '3');
+}, 'getAnimations for CSS Transitions sort by transition generation');
+
+function pseudoTest(description, testMarkerPseudos) {
+ test(t => {
+ // Create two divs with the following arrangement:
+ //
+ // parent
+ // (::marker,) // Optionally
+ // ::before,
+ // ::after
+ // |
+ // child
+
+ addStyle(t, {
+ '.init::after': 'content: ""; width: 0px; transition: all 100s;',
+ '.init::before': 'content: ""; width: 0px; transition: all 100s;',
+ '.change::after': 'width: 100px;',
+ '.change::before': 'width: 100px;',
+ });
+
+ if (testMarkerPseudos) {
+ addStyle(t, {
+ '.init::marker': 'content: ""; color: red; transition: all 100s;',
+ '.change::marker': 'color: green;',
+ });
+ }
+
+ const parent = addDiv(t, { 'style': 'display: list-item' });
+ const child = addDiv(t);
+ parent.appendChild(child);
+
+ parent.style.left = '0px';
+ parent.style.transition = 'left 100s';
+ parent.classList.add('init');
+ child.style.left = '0px';
+ child.style.transition = 'left 100s';
+ getComputedStyle(parent).left;
+
+ parent.style.left = '100px';
+ parent.classList.add('change');
+ child.style.left = '100px';
+
+ const expectedTransitions = [
+ [parent, undefined],
+ [parent, '::marker'],
+ [parent, '::before'],
+ [parent, '::after'],
+ [child, undefined],
+ ];
+ if (!testMarkerPseudos) {
+ expectedTransitions.splice(1, 1);
+ }
+
+ const transitions = document.getAnimations();
+ assert_equals(
+ transitions.length,
+ expectedTransitions.length,
+ 'CSS transition on both pseudo-elements and elements are returned'
+ );
+
+ for (const [index, expected] of expectedTransitions.entries()) {
+ const [element, pseudo] = expected;
+ const actual = transitions[index];
+
+ if (pseudo) {
+ assert_equals(
+ actual.effect.target,
+ element,
+ `Transition #${index + 1} has expected target`
+ );
+ assert_equals(
+ actual.effect.pseudoElement,
+ pseudo,
+ `Transition #${index + 1} has expected pseudo type`
+ );
+ } else {
+ assert_equals(
+ actual.effect.target,
+ element,
+ `Transition #${index + 1} has expected target`
+ );
+ assert_equals(
+ actual.effect.pseudoElement,
+ null,
+ `Transition #${index + 1} has null pseudo type`
+ );
+ }
+ }
+ }, description);
+}
+
+pseudoTest('CSS Transitions targetting (pseudo-)elements should have correct '
+ + 'order after sorting', false)
+pseudoTest('CSS Transitions targetting (pseudo-)elements should have correct '
+ + 'order after sorting (::marker)', true)
+
+promise_test(async t => {
+ const div = addDiv(t, { style: 'left: 0px; transition: all 50ms' });
+ getComputedStyle(div).left;
+
+ div.style.left = '100px';
+ const animations = div.getAnimations();
+ assert_equals(animations.length, 1, 'Got transition');
+ await animations[0].finished;
+
+ assert_equals(document.getAnimations().length, 0,
+ 'No animations returned');
+}, 'Transitions are not returned after they have finished');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-transitions/Element-getAnimations.tentative.html b/testing/web-platform/tests/css/css-transitions/Element-getAnimations.tentative.html
new file mode 100644
index 0000000000..26e988ffe6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/Element-getAnimations.tentative.html
@@ -0,0 +1,117 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>Element.getAnimations() for CSS transitions</title>
+<link rel="help" href="https://drafts.csswg.org/css-transitions-2/#animation-composite-order">
+<!-- TODO: Add a more specific link for this once it is specified. -->
+<link rel="help" href="https://drafts.csswg.org/css-transitions-2/#csstransition">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/helper.js"></script>
+<div id="log"></div>
+<script>
+'use strict';
+
+promise_test(async t => {
+ const div = addDiv(t);
+
+ div.style.left = '0px';
+ div.style.top = '0px';
+ getComputedStyle(div).transitionProperty;
+
+ div.style.transition = 'all 100s';
+ div.style.left = '100px';
+ div.style.top = '100px';
+
+ assert_equals(div.getAnimations().length, 2);
+}, 'getAnimations returns one Animation per transitioning property');
+
+test(t => {
+ const div = addDiv(t, { style: 'left: 0px; transition: all 100s' });
+
+ getComputedStyle(div).left;
+ div.style.left = '100px';
+
+ assert_class_string(div.getAnimations()[0], 'CSSTransition',
+ 'Interface of returned animation is CSSTransition');
+}, 'getAnimations returns CSSTransition objects for CSS Transitions');
+
+promise_test(async t => {
+ const div = addDiv(t);
+
+ div.style.left = '0px';
+ getComputedStyle(div).left;
+ div.style.transition = 'all 0.01s';
+ div.style.left = '100px';
+ const animation = div.getAnimations()[0];
+
+ await animation.finished;
+
+ assert_equals(div.getAnimations().length, 0);
+}, 'getAnimations does not return finished CSS Transitions');
+
+test(t => {
+ const div = addDiv(t);
+
+ // animation-duration is not animatable
+ div.style.animationDuration = '10s';
+ getComputedStyle(div).animationDuration;
+
+ div.style.transition = 'all 100s';
+ div.style.animationDuration = '100s';
+
+ assert_equals(div.getAnimations().length, 0);
+}, 'getAnimations does not return a transition for a non-animatable property');
+
+test(t => {
+ const div = addDiv(t);
+
+ div.style.setProperty('-vendor-unsupported', '0px', '');
+ getComputedStyle(div).transitionProperty;
+ div.style.transition = 'all 100s';
+ div.style.setProperty('-vendor-unsupported', '100px', '');
+
+ assert_equals(div.getAnimations().length, 0);
+}, 'getAnimations does not return a transition for an unsupposed property');
+
+test(t => {
+ const div = addDiv(t, { style: 'transform: translate(0px); ' +
+ 'opacity: 0; ' +
+ 'border-width: 0px; ' + // Shorthand
+ 'border-style: solid' });
+ getComputedStyle(div).transform;
+
+ div.style.transition = 'all 100s';
+ div.style.transform = 'translate(100px)';
+ div.style.opacity = '1';
+ div.style.borderWidth = '1px';
+
+ const animations = div.getAnimations();
+ assert_equals(animations.length, 6,
+ 'Generated expected number of transitions');
+ assert_equals(animations[0].transitionProperty, 'border-bottom-width');
+ assert_equals(animations[1].transitionProperty, 'border-left-width');
+ assert_equals(animations[2].transitionProperty, 'border-right-width');
+ assert_equals(animations[3].transitionProperty, 'border-top-width');
+ assert_equals(animations[4].transitionProperty, 'opacity');
+ assert_equals(animations[5].transitionProperty, 'transform');
+}, 'getAnimations sorts simultaneous transitions by name');
+
+test(t => {
+ const div = addDiv(t, { style: 'transform: translate(0px); ' +
+ 'opacity: 0' });
+ getComputedStyle(div).transform;
+
+ div.style.transition = 'all 100s';
+ div.style.transform = 'translate(100px)';
+ assert_equals(div.getAnimations().length, 1,
+ 'Initially there is only one (transform) transition');
+ div.style.opacity = '1';
+ assert_equals(div.getAnimations().length, 2,
+ 'Then a second (opacity) transition is added');
+
+ const animations = div.getAnimations();
+ assert_equals(animations[0].transitionProperty, 'transform');
+ assert_equals(animations[1].transitionProperty, 'opacity');
+}, 'getAnimations sorts transitions by when they were generated');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-transitions/KeyframeEffect-getKeyframes-width-and-height-transition.tentative.html b/testing/web-platform/tests/css/css-transitions/KeyframeEffect-getKeyframes-width-and-height-transition.tentative.html
new file mode 100644
index 0000000000..b63f2d6ef8
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/KeyframeEffect-getKeyframes-width-and-height-transition.tentative.html
@@ -0,0 +1,43 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>AnimationEffect.getKeyframes() for CSS transitions of the width and height properties</title>
+<link rel="help" href="https://drafts.csswg.org/css-transitions-2/#csstransition">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/helper.js"></script>
+<style>
+
+.animated-div {
+ width: 100px;
+ height: 100px;
+}
+
+</style>
+<div id="log"></div>
+<script>
+
+'use strict';
+
+test(t => {
+ const div = addDiv(t, { class: 'animated-div' });
+ div.style.transition = 'width 10s';
+ getComputedStyle(div).width;
+ div.style.width = '200px';
+
+ const keyframes = div.getAnimations()[0].effect.getKeyframes();
+ assert_equals(keyframes[0].width, "100px", 'from keyframe value');
+ assert_equals(keyframes[1].width, "200px", 'to keyframe value');
+}, 'getKeyframes() output for a width transition');
+
+test(t => {
+ const div = addDiv(t, { class: 'animated-div' });
+ div.style.transition = 'height 10s';
+ getComputedStyle(div).height;
+ div.style.height = '200px';
+
+ const keyframes = div.getAnimations()[0].effect.getKeyframes();
+ assert_equals(keyframes[0].height, "100px", 'from keyframe value');
+ assert_equals(keyframes[1].height, "200px", 'to keyframe value');
+}, 'getKeyframes() output for a height transition');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-transitions/KeyframeEffect-getKeyframes.tentative.html b/testing/web-platform/tests/css/css-transitions/KeyframeEffect-getKeyframes.tentative.html
new file mode 100644
index 0000000000..56925fb0bd
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/KeyframeEffect-getKeyframes.tentative.html
@@ -0,0 +1,169 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>KeyframeEffect.getKeyframes() for CSS transitions</title>
+<!-- TODO: Add a more specific link for this once it is specified. -->
+<link rel="help" href="https://drafts.csswg.org/css-transitions-2/#csstransition">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/helper.js"></script>
+<style>
+:root {
+ --var-100px: 100px;
+}
+</style>
+<div id="log"></div>
+<script>
+'use strict';
+
+const getKeyframes = e => {
+ return e.getAnimations()[0].effect.getKeyframes();
+};
+
+const assert_frames_equal = (a, b, name) => {
+ assert_equals(
+ Object.keys(a).sort().toString(),
+ Object.keys(b).sort().toString(),
+ `properties on ${name}`
+ );
+ for (const p in a) {
+ assert_equals(a[p], b[p], `value for '${p}' on ${name}`);
+ }
+};
+
+test(t => {
+ const div = addDiv(t);
+
+ div.style.left = '0px';
+ getComputedStyle(div).transitionProperty;
+ div.style.transition = 'left 100s';
+ div.style.left = '100px';
+
+ const frames = getKeyframes(div);
+
+ assert_equals(frames.length, 2, 'number of frames');
+
+ const expected = [
+ { offset: 0,
+ computedOffset: 0,
+ easing: 'linear',
+ composite: 'auto',
+ left: '0px',
+ },
+ {
+ offset: 1,
+ computedOffset: 1,
+ easing: 'linear',
+ composite: 'auto',
+ left: '100px',
+ },
+ ];
+
+ for (let i = 0; i < frames.length; i++) {
+ assert_frames_equal(frames[i], expected[i], `ComputedKeyframe #${i}`);
+ }
+}, 'KeyframeEffect.getKeyframes() returns expected frames for a simple'
+ + ' transition');
+
+test(t => {
+ const div = addDiv(t);
+
+ div.style.left = '0px';
+ getComputedStyle(div).transitionProperty;
+ div.style.transition = 'left 100s steps(2,end)';
+ div.style.left = '100px';
+
+ const frames = getKeyframes(div);
+
+ assert_equals(frames.length, 2, 'number of frames');
+
+ const expected = [
+ {
+ offset: 0,
+ computedOffset: 0,
+ easing: 'linear',
+ composite: 'auto',
+ left: '0px',
+ },
+ {
+ offset: 1,
+ computedOffset: 1,
+ easing: 'linear',
+ composite: 'auto',
+ left: '100px',
+ },
+ ];
+
+ for (let i = 0; i < frames.length; i++) {
+ assert_frames_equal(frames[i], expected[i], `ComputedKeyframe #${i}`);
+ }
+}, 'KeyframeEffect.getKeyframes() returns frames unaffected by a non-default easing function');
+
+test(t => {
+ const div = addDiv(t);
+ div.style.left = '0px';
+ getComputedStyle(div).transitionProperty;
+ div.style.transition = 'left 100s';
+ div.style.left = 'var(--var-100px)';
+
+ const frames = getKeyframes(div);
+
+ // CSS transition endpoints are based on the computed value so we
+ // shouldn't see the variable reference
+ const expected = [
+ {
+ offset: 0,
+ computedOffset: 0,
+ easing: 'linear',
+ composite: 'auto',
+ left: '0px',
+ },
+ {
+ offset: 1,
+ computedOffset: 1,
+ easing: 'linear',
+ composite: 'auto',
+ left: '100px',
+ },
+ ];
+ for (let i = 0; i < frames.length; i++) {
+ assert_frames_equal(frames[i], expected[i], `ComputedKeyframe #${i}`);
+ }
+}, 'KeyframeEffect.getKeyframes() returns expected frames for a'
+ + ' transition with a CSS variable endpoint');
+
+test(t => {
+ const div = addDiv(t);
+ div.style.left = '0px';
+ getComputedStyle(div).transitionProperty;
+ div.style.transition = 'left 100s';
+ div.style.left = '100px';
+
+ // Resetting the effect target before retrieving the keyframes should not
+ // affect the computed property values.
+ const anim = div.getAnimations()[0];
+ anim.effect.target = null;
+ const frames = anim.effect.getKeyframes();
+
+ const expected = [
+ {
+ offset: 0,
+ computedOffset: 0,
+ easing: 'linear',
+ composite: 'auto',
+ left: '0px',
+ },
+ {
+ offset: 1,
+ computedOffset: 1,
+ easing: 'linear',
+ composite: 'auto',
+ left: '100px',
+ },
+ ];
+ for (let i = 0; i < frames.length; i++) {
+ assert_frames_equal(frames[i], expected[i], `ComputedKeyframe #${i}`);
+ }
+}, 'KeyframeEffect.getKeyframes() returns expected frames for a'
+ + ' transition after resetting the effect target');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-transitions/KeyframeEffect-setKeyframes.tentative.html b/testing/web-platform/tests/css/css-transitions/KeyframeEffect-setKeyframes.tentative.html
new file mode 100644
index 0000000000..91ebd55628
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/KeyframeEffect-setKeyframes.tentative.html
@@ -0,0 +1,177 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>KeyframeEffect.setKeyframes() for CSS transitions</title>
+<!-- TODO: Add a more specific link for this once it is specified. -->
+<link rel="help" href="https://drafts.csswg.org/css-transitions-2/#csstransition">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/helper.js"></script>
+<div id="log"></div>
+<script>
+'use strict';
+
+test(t => {
+ const div = addDiv(t);
+
+ div.style.left = '0px';
+ getComputedStyle(div).transitionProperty;
+ div.style.transition = 'left 100s';
+ div.style.left = '100px';
+
+ const transition = div.getAnimations()[0];
+ transition.effect.setKeyframes({ left: ['200px', '300px', '100px'] });
+
+ assert_equals(getComputedStyle(div).left, '200px');
+}, 'Keyframes set using setKeyframes() are reflected in computed style for'
+ + ' a running transition');
+
+test(t => {
+ const div = addDiv(t);
+
+ div.style.left = '0px';
+ getComputedStyle(div).transitionProperty;
+ div.style.transition = 'left 100s';
+ div.style.left = '100px';
+
+ const transition = div.getAnimations()[0];
+ transition.effect.setKeyframes({ top: ['0px', '100px', '300px'] });
+
+ assert_equals(transition.transitionProperty, 'left');
+}, 'A transition with replaced keyframes still returns the original'
+ + ' transitionProperty');
+
+test(t => {
+ const div = addDiv(t);
+
+ div.style.left = '0px';
+ getComputedStyle(div).transitionProperty;
+ div.style.transition = 'left 100s';
+ div.style.left = '100px';
+
+ const transition = div.getAnimations()[0];
+ transition.effect.setKeyframes({ });
+
+ assert_equals(transition.transitionProperty, 'left');
+}, 'A transition with no keyframes still returns the original'
+ + ' transitionProperty');
+
+function retarget_test(description, newKeyframes, reversed_start) {
+ test(t => {
+ const div = addDiv(t);
+
+ div.style.left = '0px';
+ getComputedStyle(div).transitionProperty;
+ div.style.transition = 'left 100s linear';
+ div.style.left = '100px';
+
+ const transition = div.getAnimations()[0];
+ transition.currentTime = 50 * MS_PER_SEC;
+ transition.effect.setKeyframes(newKeyframes);
+
+ // Reverse transition
+ div.style.left = '0px';
+ const reversedTransition = div.getAnimations()[0];
+
+ assert_approx_equals(
+ reversedTransition.effect.getComputedTiming().activeDuration,
+ 50 * MS_PER_SEC, 1,
+ "The reversed transition has correctly reduced duration"
+ );
+ assert_equals(reversedTransition.effect.getKeyframes()[0].left, reversed_start,
+ "The reversed transition starts at the expected point");
+ }, description);
+}
+
+retarget_test("A transition with replaced keyframes animating the same property " +
+ "still exhibits normal reversing behavior.",
+ {left: ['200px', '300px', '100px']}, '300px');
+
+retarget_test("A transition with replaced keyframes animating a different property " +
+ "still exhibits normal reversing behavior (reversing from the base value).",
+ {top: ['200px', '300px', '100px']}, '100px');
+
+retarget_test("A transition with replaced keyframes animating nothing " +
+ "still exhibits normal reversing behavior (reversing from the base value).",
+ {}, '100px');
+
+test(t => {
+ const div = addDiv(t);
+
+ // Initialize the style.
+ div.style.left = '100px';
+ div.style.top = '100px';
+ div.style.transition = 'left 100s linear, top 100s linear';
+ getComputedStyle(div).left;
+
+ // Start some transitions.
+ div.style.left ='200px';
+ div.style.top = '200px';
+ const transitions = div.getAnimations();
+
+ // Hand control of the left property over to top's transition. The composite
+ // ordering of the animations is 'left' then 'top' since the transitions were
+ // generated in the same transition generation and follow Unicode ordering.
+ assert_equals(transitions[0].transitionProperty, 'left');
+ transitions[0].effect.setKeyframes({});
+ transitions[1].effect.setKeyframes([
+ {left: '100px', top: '100px'},
+ {left: '400px', top: '200px'}])
+ getComputedStyle(div).left;
+
+ // These updates form a single style change, equivalent to setting times and
+ // then setting left.
+ transitions[0].currentTime = 50 * MS_PER_SEC;
+ div.style.left ='100px';
+ transitions[1].currentTime = 60 * MS_PER_SEC;
+
+ // As there was a style change event, the new 'left' transition now has a
+ // higher value for the transition generation than the 'top' transition,
+ // reversing the order of the transitions returned by getAnimations.
+ const reversedTransition = div.getAnimations()[1];
+ assert_equals(reversedTransition.transitionProperty, 'left',
+ "A reversed transition on left is produced");
+
+ assert_approx_equals(
+ reversedTransition.effect.getComputedTiming().activeDuration,
+ 50 * MS_PER_SEC, 1,
+ "The reversed transition has correctly reduced duration (based on the " +
+ "original left transition).");
+
+ assert_equals(reversedTransition.effect.getKeyframes()[0].left, '280px',
+ "The reversed transition gets its start value from the other " +
+ "transition controlling left");
+
+}, "A transition with replaced keyframes animating nothing on a property " +
+ "being controlled by another modified transition exhibits normal " +
+ "reversing behavior and reverses from the other transition's current " +
+ "value.");
+
+test(t => {
+ const div = addDiv(t);
+
+ // Initialize the style.
+ div.style.left = '100px';
+ div.style.transition = 'left 100s linear';
+ getComputedStyle(div).left;
+
+ // Start the transtion.
+ div.style.left ='200px';
+ const transition = div.getAnimations()[0];
+
+ // Update the keyframes and advance to the midpoint of the animation.
+ transition.effect.setKeyframes([
+ { offset: 0, left: '-50px', composite: 'add', easing: 'linear'}]);
+ transition.currentTime = 50 * MS_PER_SEC;
+ assert_equals(getComputedStyle(div).left, '175px',
+ 'The computed style is based on the updated keyframes');
+
+ div.style.left = '100px';
+ const reversedTransition = div.getAnimations()[0];
+ assert_equals(reversedTransition.effect.getKeyframes()[0].left, '175px',
+ 'The start value matches the \'before change\' value');
+
+}, 'A transition with replaced kefyrames and composite \'add\' exhibits ' +
+ 'normal reversing behavior, and the effect is not double counted when ' +
+ 'calculating the before change style');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-transitions/KeyframeEffect-target.tentative.html b/testing/web-platform/tests/css/css-transitions/KeyframeEffect-target.tentative.html
new file mode 100644
index 0000000000..dbb2a43f78
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/KeyframeEffect-target.tentative.html
@@ -0,0 +1,69 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>CSSTransition.effect.target</title>
+<!-- TODO: Add a more specific link for this once it is specified. -->
+<link rel="help" href="https://drafts.csswg.org/css-transitions-2/#csstransition">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/helper.js"></script>
+<div id="log"></div>
+<script>
+'use strict';
+
+test(t => {
+ const div = addDiv(t);
+
+ div.style.left = '0px';
+ getComputedStyle(div).transitionProperty;
+ div.style.transition = 'left 100s';
+ div.style.left = '100px';
+
+ const animation = div.getAnimations()[0];
+ assert_equals(animation.effect.target, div,
+ 'Animation.target is the animatable div');
+}, 'Returned CSS transitions have the correct Animation.target');
+
+test(t => {
+ addStyle(t, { '.init::after': 'content: ""; width: 0px; height: 0px; ' +
+ 'transition: all 10s;',
+ '.change::after': 'width: 100px; height: 100px;' });
+ const div = addDiv(t, { class: 'init' });
+ getComputedStyle(div).width;
+ div.classList.add('change');
+
+ const anims = document.getAnimations();
+ assert_equals(anims.length, 2,
+ 'Got transitions running on ::after pseudo element');
+ assert_equals(anims[0].effect.target, anims[1].effect.target,
+ 'Both transitions return the same target object');
+}, 'effect.target should return the same CSSPseudoElement object each time');
+
+test(t => {
+ addStyle(t, { '.init::after': 'content: ""; width: 0px; transition: all 10s;',
+ '.change::after': 'width: 100px;' });
+ const div = addDiv(t, { class: 'init' });
+ getComputedStyle(div).width;
+ div.classList.add('change');
+ const pseudoTarget = document.getAnimations()[0].effect.target;
+ const effect = new KeyframeEffect(pseudoTarget,
+ { background: ["blue", "red"] },
+ 3000);
+ const newAnim = new Animation(effect, document.timeline);
+ newAnim.play();
+
+ const anims = document.getAnimations();
+ assert_equals(anims.length, 2,
+ 'Got animations running on ::after pseudo element');
+ assert_not_equals(anims[0], newAnim,
+ 'The scriped-generated animation appears last');
+ assert_equals(newAnim.effect.target, pseudoTarget,
+ 'The effect.target of the scripted-generated animation is ' +
+ 'the same as the one from the argument of ' +
+ 'KeyframeEffect constructor');
+ assert_equals(anims[0].effect.target, newAnim.effect.target,
+ 'Both the transition and the scripted-generated animation ' +
+ 'return the same target object');
+}, 'effect.target from the script-generated animation should return the same ' +
+ 'CSSPseudoElement object as that from the CSS generated transition');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-transitions/META.yml b/testing/web-platform/tests/css/css-transitions/META.yml
new file mode 100644
index 0000000000..581515c493
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/META.yml
@@ -0,0 +1,3 @@
+spec: https://drafts.csswg.org/css-transitions/
+suggested_reviewers:
+ - dbaron
diff --git a/testing/web-platform/tests/css/css-transitions/README.md b/testing/web-platform/tests/css/css-transitions/README.md
new file mode 100644
index 0000000000..f72f11dcca
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/README.md
@@ -0,0 +1,75 @@
+# CSSWG Compatible Tests #
+
+## Hints ##
+
+* en/disable vendor-prefixing in `./support/helper.js` see `addVendorPrefixes`
+* remove extra `<length>` values to reduce test cases (and thus execution duration) in `./support.properties.js`, see `values.length`
+
+
+## General Properties Test Concept ##
+
+Using `support/property.js` test suites compile a list of animatable properties. `getPropertyTests()` (and the like) will expand the specification's `width: length, percentage` to `width: 1em, 1ex, 1px, … 1%` in order to test all possible value types. The propertyTests returned by `support/property.js` have the following general structure:
+
+```javascript
+{
+ // name of the test
+ "name": "background-color color(rgba)",
+ // property that is being tested
+ "property": "background-color",
+ // styles to set on the parent container (usually #container)
+ "parentStyle": {},
+ // initial styles to set on the transition element (usually #transition)
+ // may contain additional properties such as position: absolute; as required
+ "from": {
+ "background-color": "rgba(100,100,100,1)"
+ },
+ // styles to transition to
+ "to": {
+ "background-color": "rgba(10,10,10,0.4)"
+ },
+ // flags classifying property types,
+ // currently only {discrete:true} for visbility
+ "flags": {}
+}
+```
+
+For each compiled test case the test runner identifies computed initial and target values. If they match, no transition will take place, because the property couldn't be parsed. If after starting the transition the computed style matches the target value, the browser applied that value immediately and no transition will take place. During the transition the computed style may match neither initial nor target value (unless it's a discrete transition), or there was no transition.
+
+Besides value-assertions, the suites compare received TransitionEnd events. While the values are only matched against computed initial and target values, expected TransitionEnd events are declared explicitly. This can (and will) lead to some test failures that are arguably not a failure (mainly because the specification didn't cover the specific case). Transitioning `color` *may* (or not, depending on browser) also run a transition for `background-color`, as the latter's default value is `currentColor`. This suite considers those implicit transitions a failure. If it truly is a failure or not, should be decided in the specification (and tests updated accordingly).
+
+Browsers supporting requestAnimationFrame can run a test in 100ms. Browsers that don't need a wider time frame to allow the not very dead-on-target setTimeout() to be triggered between TransitionStart and TransitionEnd. Low-end CPU devices also benefit from slower transitions. Since a 300 hundred tests, each lasting 500ms would require 2.5 minutes to run, tests are run concurrently, as they cannot affect each other. For low-end devices (e.g. iPad) too many parallel tests lead to global failure, because a single `requestAnimationFrame()` would have to iterate too many nodes, which is why the suite shards into slices of 50 parallel tests. Tests are run in an off-viewport container, to prevent you from having seizures.
+
+To make individual tests a bit more readable, a lot of the test-functionality has been moved to external JavaScript files. All assertions reside within the test file itsel, though. Although they are mostly exact duplicates of other tests, it should help understanding what a test does (while abstracting away *how* it does it.)
+
+### Debugging ###
+
+1. reduce to the tests you want to take a closer look at - see `filterPropertyTests()` in `support/properties.js`
+2. disable final cleanup by commenting out `done` and `teardown` callbacks
+3. possibly increase the `duration` and disable the `#offscreen` (by simply naming it `#off-screen`)
+
+
+## Unspecified Behavior ##
+
+the following suites test behavior that is not covered in CSS3 Transitions (as of today):
+
+* `properties-value-002.html` - verify value types transitionable but not specified for properties
+* `properties-value-003.html` - verify transitionable properties thus far not specified at all
+* `properties-value-implicit-001.html` - verify behavior for `em` based `<length>` properties when `font-size` is changed
+* `events-006.html` - expect `TransitionEnd` event to be triggered and `event.pseudoElement` to be set properly
+* `before-load-001.html` - expect transitions to be performed before document is fully loaded
+* `hidden-container-001.html` - expect transitions to NOT be performed if they happen within hidden elements
+* `detached-container-001.html` - expect transitions to NOT be performed if they happen outside of the document
+
+
+## Yet To Be Tested ##
+
+These are topics I have identifed in need of testing, but haven gotten around to testing them.
+
+* Anything involving `<svg>`
+ * well, maybe some day...
+* proper execution of timing-functions - are the right property values set at a given time?
+ * how exactly do I pinpoint a specific time to verify a property's value at time `t`?
+ * need to implement cubic-bezier to actually calculate a property's value at time `t`?
+* `selector:hover:before {}`
+ * I have no clue how to trigger that from script
+
diff --git a/testing/web-platform/tests/css/css-transitions/all-with-discrete.tentative.html b/testing/web-platform/tests/css/css-transitions/all-with-discrete.tentative.html
new file mode 100644
index 0000000000..37946717b4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/all-with-discrete.tentative.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://github.com/w3c/csswg-drafts/issues/4441">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/css-animations/support/testcommon.js"></script>
+
+<div class=testcase id=discrete>Allow discrete</div>
+<div class=testcase id=normal>No discrete</div>
+
+<style>
+.testcase {
+ float: left;
+ width: 100px;
+ height: 100px;
+ transition: all 1s;
+}
+#discrete {
+ transition-behavior: allow-discrete;
+}
+.animated {
+ float: right;
+}
+</style>
+
+<script>
+promise_test(async () => {
+ await waitForAnimationFrames(2);
+ // Regression test for https://crbug.com/1518561
+ normal.classList.add('animated');
+ const normalAnims = normal.getAnimations();
+ assert_equals(normalAnims.length, 0,
+ "Started a discrete property transition on a normal element");
+
+ discrete.classList.add('animated');
+ const anims = discrete.getAnimations();
+ assert_equals(anims.length, 1,
+ "Did not start a discrete-property transition");
+ assert_equals(anims[0].transitionProperty, 'float');
+}, 'transition:all with transition-behavior:allow-discrete should animate discrete properties.');
+</script>
diff --git a/testing/web-platform/tests/css/css-transitions/animations/animate-with-color-mix.html b/testing/web-platform/tests/css/css-transitions/animations/animate-with-color-mix.html
new file mode 100644
index 0000000000..3e630a7a2b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/animations/animate-with-color-mix.html
@@ -0,0 +1,146 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <link rel="help" href="https://www.w3.org/TR/css-color-4/#interpolation">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <title>CSS transitions with color-mix</title>
+</head>
+<style>
+ #target-1, #target-2, #target-3, #target-4, #target-5, #target-6 {
+ color: black;
+ height: 100px;
+ width: 100px;
+ display: inline-block;
+ transition: background-color 1s linear;
+ }
+ #target-1,
+ #target-2.update-2,
+ #target-3,
+ #target-4.update-4 {
+ background-color: color-mix(in srgb, white 50%,
+ currentcolor);
+ }
+ #target-1.update-1,
+ #target-2 {
+ background-color: rgb(0, 255, 0);
+ }
+
+ #target-3.update-3,
+ #target-4 {
+ background-color: color(srgb 0.0 1.0 0.0);
+ }
+
+ #target-5, #target-6.update-6 {
+ background-color: color-mix(in srgb, transparent 50%,
+ currentcolor);
+ }
+
+ #target-6, #target-5.update-5 {
+ background-color: rgba(255, 255, 255, 0.75);
+ }
+
+</style>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/web-animations/testcommon.js"></script>
+<script src="/css/support/color-testcommon.js"></script>
+<body>
+ <div id="target-1"></div>
+ <div id="target-2"></div>
+ <div id="target-3"></div>
+ <div id="target-4"></div>
+ <div id="target-5"></div>
+ <div id="target-6"></div>
+</body>
+<script>
+ 'use strict';
+
+ async function runAnimationTest(t, elementId, update,
+ expected_colors) {
+ const elem = document.getElementById(elementId);
+ t.add_cleanup(() => {
+ elem.classList.remove(update);
+ });
+ await waitForNextFrame();
+ await waitForNextFrame();
+ elem.classList.add(update);
+ const anim = elem.getAnimations()[0];
+ await anim.ready;
+ // Keep the animation in effect when it reaches the end.
+ anim.effect.updateTiming({ fill: 'forwards' });
+ expected_colors.forEach(data => {
+ anim.currentTime = 1000 * data.at;
+ const actual = getComputedStyle(elem).backgroundColor;
+ const expected = data.value;
+ assert_oklab_color(
+ actual, expected,
+ `Background color at ${100*data.at}% animation progress`);
+ });
+ }
+
+ const gray_to_green = [
+ { at: 0, value: 'oklab(0.5981 0.0000 0.0000)' },
+ { at: 0.25, value: 'oklab(0.6652 -0.0584 0.0449)' },
+ { at: 0.5, value: 'oklab(0.7323 -0.1169 0.0898)' },
+ { at: 0.75, value: 'oklab(0.7994 -0.1754 0.1346)' },
+ { at: 1, value: 'oklab(0.8664 -0.2338 0.1795)' }
+ ];
+
+ const green_to_gray = [
+ { at: 0, value: 'oklab(0.8664 -0.2338 0.1795)' },
+ { at: 0.25, value: 'oklab(0.7994 -0.1754 0.1346)' },
+ { at: 0.5, value: 'oklab(0.7323 -0.1169 0.0898)' },
+ { at: 0.75, value: 'oklab(0.6652 -0.0584 0.0449)' },
+ { at: 1, value: 'oklab(0.5981 0.0000 0.0000)' }
+ ];
+
+ const translucent_black_to_white = [
+ { at: 0, value: 'oklab(0 0 0 / 0.5)' },
+ { at: 0.25, value: 'oklab(0.3330 0 0 / 0.5623)' },
+ { at: 0.5, value: 'oklab(0.5997 0 0 / 0.6245)' },
+ { at: 0.75, value: 'oklab(0.8180 0 0 / 0.6868)' },
+ { at: 1, value: 'oklab(1 0 0 / 0.75)' }
+ ];
+
+ const translucent_white_to_black = [
+ { at: 0, value: 'oklab(1 0 0 / 0.75)' },
+ { at: 0.25, value: 'oklab(0.8180 0 0. / 0.6868)' },
+ { at: 0.5, value: 'oklab(0.5997 0 0 / 0.6245)' },
+ { at: 0.75, value: 'oklab(0.3330 0 0 / 0.5623)' },
+ { at: 1, value: 'oklab(0 0 0 / 0.5)' }
+ ];
+
+ window.onload = async () => {
+ promise_test(t => {
+ return runAnimationTest(t, 'target-1', 'update-1',
+ gray_to_green);
+ }, 'Transition from color-mix to legacy rgb');
+
+ promise_test(t => {
+ return runAnimationTest(t, 'target-2', 'update-2',
+ green_to_gray);
+ }, 'Transition from legacy rgb to color-mix');
+
+ promise_test(t => {
+ return runAnimationTest(t, 'target-3', 'update-3',
+ gray_to_green);
+ }, 'Transition from color-mix to srgb');
+
+ promise_test(t => {
+ return runAnimationTest(t, 'target-4', 'update-4',
+ green_to_gray);
+ }, 'Transition from srgb to color-mix');
+
+ promise_test(t => {
+ return runAnimationTest(t, 'target-5', 'update-5',
+ translucent_black_to_white);
+ }, 'Transition from color-mix with transparency to legacy rgba');
+
+ promise_test(t => {
+ return runAnimationTest(t, 'target-6', 'update-6',
+ translucent_white_to_black);
+ }, 'Transition from legacy rgba to color-mix with transparency');
+ };
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-transitions/animations/change-duration-during-transition.html b/testing/web-platform/tests/css/css-transitions/animations/change-duration-during-transition.html
new file mode 100644
index 0000000000..cf03f2e120
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/animations/change-duration-during-transition.html
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>transition duration change</title>
+ <link rel="help" href="https://drafts.csswg.org/css-transitions-1/#starting">
+ <style>
+ #box {
+ position: absolute;
+ height: 100px;
+ width: 100px;
+ left: 0px;
+ background-color: blue;
+ transition-duration: 1s;
+ transition-delay: -0.75s;
+ transition-timing-function: linear;
+ transition-property: left;
+ }
+ </style>
+</head>
+<body>
+ <div id="box"></div>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <script src="/css/css-transitions/support/helper.js"></script>
+ <script>
+ 'use strict';
+
+ window.onload = () => {
+ promise_test(async t => {
+ // Make sure we have rendered the page before making the style change
+ // to ensure we get transitions.
+ await waitForAnimationFrames(2);
+
+ box.style.left = '400px';
+ assert_equals(
+ getComputedStyle(box).left, '300px',
+ 'The transition progresses 75% immediately due to negative ' +
+ 'transition-delay');
+
+ box.style.transitionDuration = '7.5s';
+ assert_equals(
+ getComputedStyle(box).left, '300px',
+ 'Changing the duration does not affect the current transition');
+
+ const anim = document.getAnimations()[0];
+ anim.finish();
+
+ assert_equals(
+ getComputedStyle(box).left, '400px',
+ 'The final value has been reached when finished');
+ box.style.left = '1400px';
+ assert_equals(
+ getComputedStyle(box).left, '500px',
+ 'With the new duration taking effect, the transition progresses ' +
+ '10% immediately');
+ }, 'Transition duration change should not affect transition in progress');
+ };
+ </script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-transitions/animations/color-transition-premultiplied.html b/testing/web-platform/tests/css/css-transitions/animations/color-transition-premultiplied.html
new file mode 100644
index 0000000000..745e6c0c73
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/animations/color-transition-premultiplied.html
@@ -0,0 +1,69 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>transition from transparent background</title>
+ <link rel="help" href="https://www.w3.org/TR/css-color-4/#interpolation-alpha">
+ <style>
+ .box {
+ width: 100px;
+ height: 100px;
+ margin: 10px;
+ border: 1px solid black;
+ transition: background-color 1s linear;
+ }
+
+ #one {
+ background-color: transparent;
+ }
+
+ #one.changed {
+ background-color: green;
+ }
+
+ #two {
+ background-color: rgba(0, 255, 0, 0);
+ }
+
+ #two.changed {
+ background-color: rgba(0, 0, 255, 1);
+ }
+ </style>
+</head>
+<body>
+ <div class="box" id="one"></div>
+ <div class="box" id="two"></div>
+</body>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/css-transitions/support/helper.js"></script>
+<script type="text/javascript">
+
+promise_test(async t => {
+ // Make sure we have rendered the page before making the style change
+ // to ensure we get transitions.
+ await waitForAnimationFrames(2);
+ promises = [];
+
+ const elem1 = document.getElementById('one');
+ const elem2 = document.getElementById('two');
+ elem1.classList.add('changed');
+ elem2.classList.add('changed');
+
+ document.getAnimations().forEach(anim => {
+ anim.pause();
+ anim.currentTime = 500;
+ promises.push(anim.ready);
+ });
+
+ Promise.all(promises).then(() => {
+ assert_equals(promises.length, 2, 'Unexpected animation count');
+ assert_equals(getComputedStyle(elem1).backgroundColor,
+ 'rgba(0, 128, 0, 0.5)');
+ assert_equals(getComputedStyle(elem2).backgroundColor,
+ 'rgba(0, 0, 255, 0.5)');
+ });
+}, 'Transition from transparent background');
+
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-transitions/animations/move-after-transition.html b/testing/web-platform/tests/css/css-transitions/animations/move-after-transition.html
new file mode 100644
index 0000000000..28180452f7
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/animations/move-after-transition.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="UTF-8">
+ <title>move after transition</title>
+ <link rel="help" href="https://drafts.csswg.org/css-transitions/#transition-property-property">
+ <style>
+ #container {
+ position: relative;
+ width: 400px;
+ height: 100px;
+ border: 1px solid black;
+ }
+ #box {
+ position: absolute;
+ width: 100px;
+ height: 100px;
+ background-color: green;
+ transform-style: preserve-3d;
+ transition: transform 300ms linear;
+ transform: translateX(0);
+ }
+ #container.moved #box {
+ transform: translateX(300px);
+ }
+ </style>
+</head>
+<body>
+ <div id="container">
+ <div id="box"></div>
+ </div>
+</body>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/css-transitions/support/helper.js"></script>
+<script type="text/javascript">
+ promise_test(async t => {
+ const container = document.getElementById('container');
+ const box = document.getElementById('box');
+
+ await waitForAnimationFrames(2);
+
+ container.classList.add('moved');
+ const animations = document.getAnimations();
+ assert_equals(animations.length, 1);
+ assert_equals(getComputedStyle(box).transform,
+ "matrix(1, 0, 0, 1, 0, 0)");
+
+ animations[0].finish();
+ assert_equals(getComputedStyle(box).transform,
+ "matrix(1, 0, 0, 1, 300, 0)");
+
+ // Verify that we do not create a second transform transition.
+ box.style.transitionProperty = 'none';
+ box.style.transform = 'translateX(150px)';
+
+ assert_equals(box.getAnimations().length, 0);
+ assert_equals(getComputedStyle(box).transform,
+ "matrix(1, 0, 0, 1, 150, 0)");
+ }, 'Move after transition.');
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-transitions/animations/text-shadow-composition.html b/testing/web-platform/tests/css/css-transitions/animations/text-shadow-composition.html
new file mode 100644
index 0000000000..d7d29c416a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/animations/text-shadow-composition.html
@@ -0,0 +1,101 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>text-shadow composition</title>
+<link rel="help" href="https://drafts.csswg.org/css-text-decor-3/#text-shadow-property">
+<meta name="assert" content="text-shadow supports animation">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<style>
+.target {
+ width: 40px;
+ height: 40px;
+ background-color: black;
+}
+.expected {
+ background-color: green;
+}
+</style>
+
+<body>
+<script>
+test_composition({
+ property: 'text-shadow',
+ replaceFrom: 'rgb(100, 100, 100) 10px 20px 30px',
+ addTo: 'rgb(200, 200, 200) 20px 40px 60px',
+}, [
+ {at: -0.3, expect: 'rgb(70, 70, 70 ) 7px 14px 21px'},
+ {at: 0, expect: 'rgb(100, 100, 100) 10px 20px 30px'},
+ {at: 0.5, expect: 'rgb(150, 150, 150) 15px 30px 45px'},
+ {at: 1, expect: 'rgb(200, 200, 200) 20px 40px 60px'},
+ {at: 1.5, expect: 'rgb(250, 250, 250) 25px 50px 75px'},
+]);
+
+test_composition({
+ property: 'text-shadow',
+ underlying: 'rgb(10, 20, 30) 1px 2px 3px',
+ addFrom: 'rgb(100, 100, 100) 10px 20px 30px',
+ addTo: 'rgb(200, 200, 200) 20px 40px 60px',
+}, [
+ {at: -0.3, expect: 'rgb(10, 20, 30) 1px 2px 3px, rgb(70, 70, 70) 7px 14px 21px'},
+ {at: 0, expect: 'rgb(10, 20, 30) 1px 2px 3px, rgb(100, 100, 100) 10px 20px 30px'},
+ {at: 0.5, expect: 'rgb(10, 20, 30) 1px 2px 3px, rgb(150, 150, 150) 15px 30px 45px'},
+ {at: 1, expect: 'rgb(10, 20, 30) 1px 2px 3px, rgb(200, 200, 200) 20px 40px 60px'},
+ {at: 1.5, expect: 'rgb(10, 20, 30) 1px 2px 3px, rgb(250, 250, 250) 25px 50px 75px'},
+]);
+
+test_composition({
+ property: 'text-shadow',
+ underlying: 'rgb(10, 20, 30) 1px 2px 3px, rgb(20, 40, 60) 2px 4px 6px',
+ addFrom: 'rgb(100, 100, 100) 10px 20px 30px',
+ addTo: 'rgb(200, 200, 200) 20px 40px 60px',
+}, [
+ {at: -0.3, expect: 'rgb(10, 20, 30) 1px 2px 3px, rgb(20, 40, 60) 2px 4px 6px, rgb(70, 70, 70) 7px 14px 21px'},
+ {at: 0, expect: 'rgb(10, 20, 30) 1px 2px 3px, rgb(20, 40, 60) 2px 4px 6px, rgb(100, 100, 100) 10px 20px 30px'},
+ {at: 0.5, expect: 'rgb(10, 20, 30) 1px 2px 3px, rgb(20, 40, 60) 2px 4px 6px, rgb(150, 150, 150) 15px 30px 45px'},
+ {at: 1, expect: 'rgb(10, 20, 30) 1px 2px 3px, rgb(20, 40, 60) 2px 4px 6px, rgb(200, 200, 200) 20px 40px 60px'},
+ {at: 1.5, expect: 'rgb(10, 20, 30) 1px 2px 3px, rgb(20, 40, 60) 2px 4px 6px, rgb(250, 250, 250) 25px 50px 75px'},
+]);
+
+test_composition({
+ property: 'text-shadow',
+ underlying: 'rgb(10, 20, 30) 1px 2px 3px, rgb(20, 40, 60) 2px 4px 6px',
+ addFrom: 'rgb(100, 100, 100) 10px 20px 30px',
+ replaceTo: 'rgb(200, 200, 200) 20px 40px 60px',
+}, [
+ {at: -0.3, expect: 'rgb(0, 0, 0) -4.7px -9.4px 0px, rgb(26, 52, 78) 2.6px 5.2px 7.8px, rgb(130, 130, 130) 13px 26px 39px'},
+ {at: 0, expect: 'rgb(10, 20, 30) 1px 2px 3px, rgb(20, 40, 60) 2px 4px 6px, rgb(100, 100, 100) 10px 20px 30px'},
+ {at: 0.5, expect: 'rgb(105, 110, 115) 10.5px 21px 31.5px, rgba(20, 40, 60, 0.5) 1px 2px 3px, rgba(100, 100, 100, 0.5) 5px 10px 15px'},
+ {at: 1, expect: 'rgb(200, 200, 200) 20px 40px 60px, rgba(0, 0, 0, 0) 0px 0px 0px, rgba(0, 0, 0, 0) 0px 0px 0px'},
+ {at: 1.5, expect: 'rgb(255, 255, 255) 29.5px 59px 88.5px, rgba(0, 0, 0, 0) -1px -2px 0px, rgba(0, 0, 0, 0) -5px -10px 0px'},
+]);
+
+test_composition({
+ property: 'text-shadow',
+ underlying: 'rgb(10, 20, 30) 1px 2px 3px, rgb(20, 40, 60) 2px 4px 6px',
+ replaceFrom: 'rgb(100, 100, 100) 10px 20px 30px',
+ addTo: 'rgb(200, 200, 200) 20px 40px 60px',
+}, [
+ {at: -0.3, expect: 'rgb(127, 124, 121) 12.7px 25.4px 38.1px, rgba(0, 0, 0, 0) -0.6px -1.2px 0px, rgba(0, 0, 0, 0) -6px -12px 0px'},
+ {at: 0, expect: 'rgb(100, 100, 100) 10px 20px 30px, rgba(0, 0, 0, 0) 0px 0px 0px, rgba(0, 0, 0, 0) 0px 0px 0px'},
+ {at: 0.5, expect: 'rgb(55, 60, 65) 5.5px 11px 16.5px, rgba(20, 40, 60, 0.5) 1px 2px 3px, rgba(200, 200, 200, 0.5) 10px 20px 30px'},
+ {at: 1, expect: 'rgb(10, 20, 30) 1px 2px 3px, rgb(20, 40, 60) 2px 4px 6px, rgb(200, 200, 200) 20px 40px 60px'},
+ {at: 1.5, expect: 'rgb(0, 0, 0) -3.5px -7px 0px, rgb(30, 60, 90) 3px 6px 9px, rgb(255, 255, 255) 30px 60px 90px'},
+]);
+
+test_composition({
+ property: 'text-shadow',
+ underlying: 'rgb(10, 20, 30) 1px 2px 3px, rgb(20, 40, 60) 2px 4px 6px, rgb(40, 80, 120) 4px 8px 12px',
+ addFrom: 'rgb(100, 100, 100) 10px 20px 30px, rgb(200, 200, 200) 20px 40px 60px',
+ replaceTo: 'rgb(200, 200, 200) 20px 40px 60px',
+}, [
+ {at: -0.3, expect: 'rgb(0, 0, 0) -4.7px -9.4px 0px, rgb(26, 52, 78) 2.6px 5.2px 7.8px, rgb(52, 104, 156) 5.2px 10.4px 15.6px, rgb(130, 130, 130) 13px 26px 39px, rgb(255, 255, 255) 26px 52px 78px'},
+ {at: 0, expect: 'rgb(10, 20, 30) 1px 2px 3px, rgb(20, 40, 60) 2px 4px 6px, rgb(40, 80, 120) 4px 8px 12px, rgb(100, 100, 100) 10px 20px 30px, rgb(200, 200, 200) 20px 40px 60px'},
+ {at: 0.5, expect: 'rgb(105, 110, 115) 10.5px 21px 31.5px, rgba(20, 40, 60, 0.5) 1px 2px 3px, rgba(40, 80, 120, 0.5) 2px 4px 6px, rgba(100, 100, 100, 0.5) 5px 10px 15px, rgba(200, 200, 200, 0.5) 10px 20px 30px'},
+ {at: 1, expect: 'rgb(200, 200, 200) 20px 40px 60px, rgba(0, 0, 0, 0) 0px 0px 0px, rgba(0, 0, 0, 0) 0px 0px 0px, rgba(0, 0, 0, 0) 0px 0px 0px, rgba(0, 0, 0, 0) 0px 0px 0px'},
+ {at: 1.5, expect: 'rgb(255, 255, 255) 29.5px 59px 88.5px, rgba(0, 0, 0, 0) -1px -2px 0px, rgba(0, 0, 0, 0) -2px -4px 0px, rgba(0, 0, 0, 0) -5px -10px 0px, rgba(0, 0, 0, 0) -10px -20px 0px'},
+]);
+</script>
+</body>
diff --git a/testing/web-platform/tests/css/css-transitions/animations/text-shadow-interpolation.html b/testing/web-platform/tests/css/css-transitions/animations/text-shadow-interpolation.html
new file mode 100644
index 0000000000..d4a75654a9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/animations/text-shadow-interpolation.html
@@ -0,0 +1,123 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>text-shadow interpolation</title>
+<link rel="help" href="https://drafts.csswg.org/css-text-decor-3/#text-shadow-property">
+<meta name="assert" content="text-shadow supports animation">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<style>
+.parent {
+ text-shadow: 30px 10px 30px orange;
+}
+
+.target {
+ display: inline-block;
+ font-size: 60pt;
+ margin-right: 20px;
+ margin-bottom: 30px;
+ color: green;
+ text-shadow: 10px 30px 10px orange;
+}
+
+.expected {
+ margin-right: 40px;
+}
+</style>
+<body>
+<template id="target-template">T</template>
+<script>
+test_interpolation({
+ property: 'text-shadow',
+ from: neutralKeyframe,
+ to: 'green 20px 20px 20px',
+}, [
+ {at: -0.3, expect: 'rgb(255, 176, 0) 7px 33px 7px'},
+ {at: 0, expect: 'rgb(255, 165, 0) 10px 30px 10px'},
+ {at: 0.3, expect: 'rgb(179, 154, 0) 13px 27px 13px'},
+ {at: 0.6, expect: 'rgb(102, 143, 0) 16px 24px 16px'},
+ {at: 1, expect: 'rgb(0, 128, 0) 20px 20px 20px'},
+ {at: 1.5, expect: 'rgb(0, 110, 0) 25px 15px 25px'},
+]);
+
+test_interpolation({
+ property: 'text-shadow',
+ from: 'initial',
+ to: 'green 20px 20px 20px',
+}, [
+ {at: -0.3, expect: 'rgba(0, 0, 0, 0) -6px -6px 0px'},
+ {at: 0, expect: 'rgba(0, 0, 0, 0) 0px 0px 0px'},
+ {at: 0.3, expect: 'rgba(0, 128, 0, 0.3) 6px 6px 6px'},
+ {at: 0.6, expect: 'rgba(0, 128, 0, 0.6) 12px 12px 12px'},
+ {at: 1, expect: 'rgb(0, 128, 0) 20px 20px 20px'},
+ {at: 1.5, expect: 'rgb(0, 192, 0) 30px 30px 30px'},
+]);
+
+test_interpolation({
+ property: 'text-shadow',
+ from: 'inherit',
+ to: 'green 20px 20px 20px',
+}, [
+ {at: -0.3, expect: 'rgb(255, 176, 0) 33px 7px 33px'},
+ {at: 0, expect: 'rgb(255, 165, 0) 30px 10px 30px'},
+ {at: 0.3, expect: 'rgb(179, 154, 0) 27px 13px 27px'},
+ {at: 0.6, expect: 'rgb(102, 143, 0) 24px 16px 24px'},
+ {at: 1, expect: 'rgb(0, 128, 0) 20px 20px 20px'},
+ {at: 1.5, expect: 'rgb(0, 110, 0) 15px 25px 15px'},
+]);
+
+test_interpolation({
+ property: 'text-shadow',
+ from: 'unset',
+ to: 'green 20px 20px 20px',
+}, [
+ {at: -0.3, expect: 'rgb(255, 176, 0) 33px 7px 33px'},
+ {at: 0, expect: 'rgb(255, 165, 0) 30px 10px 30px'},
+ {at: 0.3, expect: 'rgb(179, 154, 0) 27px 13px 27px'},
+ {at: 0.6, expect: 'rgb(102, 143, 0) 24px 16px 24px'},
+ {at: 1, expect: 'rgb(0, 128, 0) 20px 20px 20px'},
+ {at: 1.5, expect: 'rgb(0, 110, 0) 15px 25px 15px'},
+]);
+
+test_interpolation({
+ property: 'text-shadow',
+ from: 'black 15px 10px 5px',
+ to: 'orange -15px -10px 25px',
+}, [
+ {at: -0.3, expect: 'rgb(0, 0, 0) 24px 16px 0px'},
+ {at: 0, expect: 'rgb(0, 0, 0) 15px 10px 5px'},
+ {at: 0.3, expect: 'rgb(77, 50, 0) 6px 4px 11px'},
+ {at: 0.6, expect: 'rgb(153, 99, 0) -3px -2px 17px'},
+ {at: 1, expect: 'rgb(255, 165, 0) -15px -10px 25px'},
+ {at: 1.5, expect: 'rgb(255, 248, 0) -30px -20px 35px'},
+]);
+
+test_interpolation({
+ property: 'text-shadow',
+ from: 'black 10px 10px 10px',
+ to: 'currentColor 10px 10px 10px',
+}, [
+ {at: -0.3, expect: 'rgb(0, 0, 0) 10px 10px 10px'},
+ {at: 0, expect: 'rgb(0, 0, 0) 10px 10px 10px'},
+ {at: 0.3, expect: 'rgb(0, 38, 0) 10px 10px 10px'},
+ {at: 0.6, expect: 'rgb(0, 77, 0) 10px 10px 10px'},
+ {at: 1, expect: 'rgb(0, 128, 0) 10px 10px 10px'},
+ {at: 1.5, expect: 'rgb(0, 192, 0) 10px 10px 10px'},
+]);
+
+test_interpolation({
+ property: 'text-shadow',
+ from: 'black 0px 0px 0px',
+ to: 'black 1px 1px 1px',
+}, [
+ {at: -0.3, expect: 'rgb(0, 0, 0) -0.3px -0.3px 0px'},
+ {at: 0, expect: 'rgb(0, 0, 0) 0px 0px 0px'},
+ {at: 0.3, expect: 'rgb(0, 0, 0) 0.3px 0.3px 0.3px'},
+ {at: 0.6, expect: 'rgb(0, 0, 0) 0.6px 0.6px 0.6px'},
+ {at: 1, expect: 'rgb(0, 0, 0) 1px 1px 1px'},
+ {at: 1.5, expect: 'rgb(0, 0, 0) 1.5px 1.5px 1.5px'},
+]);
+</script>
+</body>
diff --git a/testing/web-platform/tests/css/css-transitions/animations/transition-end-event-shorthands.html b/testing/web-platform/tests/css/css-transitions/animations/transition-end-event-shorthands.html
new file mode 100644
index 0000000000..3816821972
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/animations/transition-end-event-shorthands.html
@@ -0,0 +1,65 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="UTF-8">
+ <title>transition end event with shorthand property</title>
+ <link rel="help" href="https://drafts.csswg.org/css-transitions/#transition-property-property">
+ <style>
+ #box {
+ transition: padding 1s;
+ padding: 0px 1px 2px 3px; // top right bottom left
+ }
+ </style>
+</head>
+<body>
+ <div id="container">
+ <div id="box"></div>
+ </div>
+</body>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/css-transitions/support/helper.js"></script>
+<script>
+ window.onload = () => {
+ function timeoutPromise() {
+ return waitForAnimationFrames(5);
+ }
+
+ promise_test(async t => {
+ // Make sure we have rendered the page before making the style change
+ // to ensure we get transitions.
+ await waitForAnimationFrames(2);
+
+ // Change three padding properties, but preserve padding-bottom.
+ // This should trigger 3 transitions.
+ box.style.padding = "8px 7px 2px 5px";
+
+ const animations = document.getAnimations();
+ const properties =
+ animations.map(anim => anim.transitionProperty).sort();
+ assert_array_equals(properties,
+ ['padding-left', 'padding-right', 'padding-top']);
+
+ // Expect a transitionend event for each of the CSSTransitions.
+ const eventWatcher =
+ new EventWatcher(t, box, 'transitionend', timeoutPromise);
+
+ const eventsPromise =
+ eventWatcher.wait_for(
+ ['transitionend', 'transitionend', 'transitionend'],
+ { record: 'all' }).then(events => {
+ events.forEach(event => {
+ assert_times_equal(event.elapsedTime, 1);
+ })
+ });
+ animations.forEach(anim => {
+ anim.finish();
+ });
+ await eventsPromise;
+
+ // Ensure no unexpected events are received.
+ await waitForAnimationFrames(2);
+ }, 'Transition end events generated for transition on shorthand property');
+ };
+</script>
+</html>
diff --git a/testing/web-platform/tests/css/css-transitions/animations/transition-timing-function.html b/testing/web-platform/tests/css/css-transitions/animations/transition-timing-function.html
new file mode 100644
index 0000000000..6dc42f5529
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/animations/transition-timing-function.html
@@ -0,0 +1,87 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="UTF-8">
+ <title>transition timing function</title>
+ <link rel="help" href="https://drafts.csswg.org/css-transitions-1/#transition-timing-function-property">
+ <style>
+ .box {
+ position: relative;
+ left: 0;
+ height: 100px;
+ width: 100px;
+ margin: 10px;
+ background-color: blue;
+ transition: left 1s linear;
+ }
+ .animating > .box {
+ left: 400px;
+ }
+ </style>
+</head>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/css-transitions/support/helper.js"></script>
+<script src="/css/css-easing/testcommon.js"></script>
+<script>
+ window.onload = () => {
+ function verifyPosition(element_id, expected) {
+ const element = document.getElementById(element_id);
+ const actual = Math.round(parseFloat(getComputedStyle(element).left));
+ assert_equals(actual, expected, `verify ${element_id} left`);
+ }
+
+ function easing(x1, y1, x2, y2) {
+ return Math.round(400 * cubicBezier(x1, y1, x2, y2)(0.5));
+ }
+
+ function ease() {
+ return easing(0.25, 0.1, 0.25, 1); // 321
+ }
+
+ function easeIn() {
+ return easing(0.42, 0, 1, 1); // 126
+ }
+
+ function easeOut() {
+ return easing(0.0, 0.0, 0.58, 1.0); // 274
+ }
+
+ function easeInOut() {
+ return easing(0.42, 0.0, 0.58, 1.0); // 200
+ }
+
+ promise_test(async t => {
+ // Make sure we have rendered the page before making the style change
+ // to ensure we get transitions.
+ await waitForAnimationFrames(2);
+ promises = [];
+ document.getElementById('container').className = 'animating';
+ document.getAnimations().forEach(anim => {
+ anim.pause();
+ anim.currentTime = 500;
+ promises.push(anim.ready);
+ });
+ await Promise.all(promises).then(() => {
+ assert_equals(promises.length, 6, 'Unexpected animation count');
+ verifyPosition('box1', 200); // linear easing
+ verifyPosition('box2', ease());
+ verifyPosition('box3', easeIn());
+ verifyPosition('box4', easeOut());
+ verifyPosition('box5', easeInOut());
+ verifyPosition('box6', 400);
+ });
+ }, 'Ensure that transition easing functions are properly applied.');
+ };
+</script>
+<body>
+<div id="container">
+ <div id="box1" class="box" style="transition-timing-function: linear;"></div>
+ <div id="box2" class="box" style="transition-timing-function: ease;"></div>
+ <div id="box3" class="box" style="transition-timing-function: ease-in;"></div>
+ <div id="box4" class="box" style="transition-timing-function: ease-out;"></div>
+ <div id="box5" class="box" style="transition-timing-function: ease-in-out;"></div>
+ <div id="box6" class="box" style="transition-timing-function: linear(0, 1, 0);"></div>
+</div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-transitions/animations/vertical-align-composition.html b/testing/web-platform/tests/css/css-transitions/animations/vertical-align-composition.html
new file mode 100644
index 0000000000..222a511679
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/animations/vertical-align-composition.html
@@ -0,0 +1,65 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>vertical-align composition</title>
+<link rel="help" href="https://www.w3.org/TR/CSS2/visudet.html#propdef-vertical-align">
+<meta name="assert" content="vertical-align supports animation">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<body>
+<script>
+test_composition({
+ property: 'vertical-align',
+ underlying: '50px',
+ addFrom: '100px',
+ addTo: '200px',
+}, [
+ {at: -0.3, expect: '120px'},
+ {at: 0, expect: '150px'},
+ {at: 0.5, expect: '200px'},
+ {at: 1, expect: '250px'},
+ {at: 1.5, expect: '300px'},
+]);
+
+test_composition({
+ property: 'vertical-align',
+ underlying: '100px',
+ addFrom: '10px',
+ addTo: '2px',
+}, [
+ {at: -0.5, expect: '114px'},
+ {at: 0, expect: '110px'},
+ {at: 0.5, expect: '106px'},
+ {at: 1, expect: '102px'},
+ {at: 1.5, expect: '98px'},
+]);
+
+test_composition({
+ property: 'vertical-align',
+ underlying: '10%',
+ addFrom: '100px',
+ addTo: '20%',
+}, [
+ {at: -0.3, expect: 'calc(130px + 4%)'},
+ {at: 0, expect: 'calc(100px + 10%)'},
+ {at: 0.5, expect: 'calc(50px + 20%)'},
+ {at: 1, expect: '30%'},
+ {at: 1.5, expect: 'calc(-50px + 40%)'},
+]);
+
+test_composition({
+ property: 'vertical-align',
+ underlying: '50px',
+ addFrom: '100px',
+ replaceTo: '200px',
+}, [
+ {at: -0.3, expect: '135px'},
+ {at: 0, expect: '150px'},
+ {at: 0.5, expect: '175px'},
+ {at: 1, expect: '200px'},
+ {at: 1.5, expect: '225px'},
+]);
+</script>
+</body>
diff --git a/testing/web-platform/tests/css/css-transitions/animations/vertical-align-interpolation.html b/testing/web-platform/tests/css/css-transitions/animations/vertical-align-interpolation.html
new file mode 100644
index 0000000000..194f9fc9f6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/animations/vertical-align-interpolation.html
@@ -0,0 +1,98 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>vertical-align interpolation</title>
+<link rel="help" href="https://www.w3.org/TR/CSS2/visudet.html#propdef-vertical-align">
+<meta name="assert" content="vertical-align supports animation">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<style>
+.parent {
+ vertical-align: 100px;
+}
+.target {
+ width: 100px;
+ height: 100px;
+ background-color: black;
+ display: inline-block;
+ vertical-align: 10px;
+}
+.expected {
+ background-color: green;
+}
+</style>
+
+<body>
+<script>
+test_interpolation({
+ property: 'vertical-align',
+ from: neutralKeyframe,
+ to: '40px',
+}, [
+ {at: -0.5, expect: '-5px'},
+ {at: 0, expect: '10px'},
+ {at: 0.3, expect: '19px'},
+ {at: 0.6, expect: '28px'},
+ {at: 1, expect: '40px'},
+ {at: 1.5, expect: '55px'},
+]);
+
+test_no_interpolation({
+ property: 'vertical-align',
+ from: 'initial',
+ to: '40px',
+});
+
+test_interpolation({
+ property: 'vertical-align',
+ from: 'inherit',
+ to: '40px',
+}, [
+ {at: -0.5, expect: '130px'},
+ {at: 0, expect: '100px'},
+ {at: 0.3, expect: '82px'},
+ {at: 0.6, expect: '64px'},
+ {at: 1, expect: '40px'},
+ {at: 1.5, expect: '10px'},
+]);
+
+test_no_interpolation({
+ property: 'vertical-align',
+ from: 'unset',
+ to: '40px',
+});
+
+test_interpolation({
+ property: 'vertical-align',
+ from: '0px',
+ to: '100px'
+}, [
+ {at: -0.5, expect: '-50px'},
+ {at: 0, expect: '0px'},
+ {at: 0.3, expect: '30px'},
+ {at: 0.6, expect: '60px'},
+ {at: 1, expect: '100px'},
+ {at: 1.5, expect: '150px'}
+]);
+
+test_interpolation({
+ property: 'vertical-align',
+ from: '40px',
+ to: '40%'
+}, [
+ {at: -0.5, expect: 'calc(60px - 20%)'},
+ {at: 0, expect: 'calc(40px + 0%)'},
+ {at: 0.3, expect: 'calc(28px + 12%)'},
+ {at: 1, expect: '40%'},
+ {at: 1.5, expect: 'calc(-20px + 60%)'}
+]);
+
+test_no_interpolation({
+ property: 'vertical-align',
+ from: 'super',
+ to: '40%'
+});
+</script>
+</body>
diff --git a/testing/web-platform/tests/css/css-transitions/animations/z-index-interpolation.html b/testing/web-platform/tests/css/css-transitions/animations/z-index-interpolation.html
new file mode 100644
index 0000000000..9673cc4d8c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/animations/z-index-interpolation.html
@@ -0,0 +1,130 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<title>z-index interpolation</title>
+<link rel="help" href="https://www.w3.org/TR/CSS2/visuren.html#z-index">
+<meta name="assert" content="z-index supports animation">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/interpolation-testcommon.js"></script>
+
+<style>
+body {
+ margin-top: 20px;
+}
+.layer-reference {
+ position: fixed;
+ top: 0px;
+ height: 100vh;
+ width: 50px;
+ background-color: rgba(255, 255, 255, 0.75);
+ font-family: sans-serif;
+ text-align: center;
+ padding-top: 5px;
+ border: 1px solid;
+}
+.parent {
+ z-index: 15;
+}
+.target {
+ position: relative;
+ width: 350px;
+ height: 10px;
+ z-index: -2;
+}
+.actual {
+ background-color: black;
+}
+.expected {
+ background-color: green;
+}
+</style>
+
+<body></body>
+
+<script>
+test_interpolation({
+ property: 'z-index',
+ from: neutralKeyframe,
+ to: '5',
+}, [
+ {at: -0.3, expect: '-4'},
+ {at: 0, expect: '-2'},
+ {at: 0.3, expect: '0'},
+ {at: 0.6, expect: '2'},
+ {at: 1, expect: '5'},
+ {at: 1.5, expect: '9'},
+]);
+
+test_no_interpolation({
+ property: 'z-index',
+ from: 'initial',
+ to: '5',
+});
+
+// We fail to inherit correctly due to style overadjustment: crbug.com/375982
+test_interpolation({
+ property: 'z-index',
+ from: 'inherit',
+ to: '5',
+}, [
+ {at: -0.3, expect: '18'},
+ {at: 0, expect: '15'},
+ {at: 0.3, expect: '12'},
+ {at: 0.6, expect: '9'},
+ {at: 1, expect: '5'},
+ {at: 1.5, expect: '0'},
+]);
+
+test_no_interpolation({
+ property: 'z-index',
+ from: 'unset',
+ to: '5',
+});
+
+test_interpolation({
+ property: 'z-index',
+ from: '-5',
+ to: '5'
+}, [
+ {at: -0.3, expect: '-8'},
+ {at: 0, expect: '-5'},
+ {at: 0.3, expect: '-2'},
+ {at: 0.6, expect: '1'},
+ {at: 1, expect: '5'},
+ {at: 1.5, expect: '10'},
+]);
+
+test_interpolation({
+ property: 'z-index',
+ from: '2',
+ to: '4'
+}, [
+ {at: -0.3, expect: '1'},
+ {at: 0, expect: '2'},
+ {at: 0.3, expect: '3'},
+ {at: 0.6, expect: '3'},
+ {at: 1, expect: '4'},
+ {at: 1.5, expect: '5'},
+]);
+
+test_interpolation({
+ property: 'z-index',
+ from: '-2',
+ to: '-4'
+}, [
+ {at: -0.3, expect: '-1'},
+ {at: 0, expect: '-2'},
+ {at: 0.1, expect: '-2'},
+ {at: 0.3, expect: '-3'},
+ {at: 0.6, expect: '-3'},
+ {at: 1, expect: '-4'},
+ {at: 1.5, expect: '-5'},
+]);
+
+test_no_interpolation({
+ property: 'z-index',
+ from: 'auto',
+ to: '10',
+});
+</script>
diff --git a/testing/web-platform/tests/css/css-transitions/before-load-001.html b/testing/web-platform/tests/css/css-transitions/before-load-001.html
new file mode 100644
index 0000000000..fe9fb97681
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/before-load-001.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Transitions Test: Transitioning before load event</title>
+<meta name="assert" content="Test checks that transitions are run even before the load event fires">
+<!-- NOTE: This test covers unspecified behavior and should probably be
+ removed. It this behavior *were* specified, it would probably be
+ specified here: -->
+<link rel="help" title="5. Transition Events" href="https://drafts.csswg.org/css-transitions/#starting">
+<link rel="author" title="Rodney Rehm" href="http://rodneyrehm.de/en/">
+
+<script src="/resources/testharness.js" type="text/javascript"></script>
+<script src="/resources/testharnessreport.js" type="text/javascript"></script>
+<script src="./support/helper.js" type="text/javascript"></script>
+
+</head>
+<body>
+
+<script>
+// Make sure a transition can run before the load event fires.
+
+let loadEventFired = false;
+window.addEventListener('load', () => {
+ loadEventFired = true;
+}, false);
+
+async_test(t => {
+ const div = addDiv(t, { style: 'transition: height .01s linear; ' +
+ 'height: 1px' });
+ getComputedStyle(div).height;
+ div.style.height = '100px';
+
+ div.addEventListener('transitionrun', t.step_func_done(() => {
+ assert_false(
+ loadEventFired,
+ 'load event should not have fired yet'
+ );
+ document.getElementById('cat').src = '';
+ }));
+});
+</script>
+
+<img src="support/cat.png?pipe=trickle(d1)" id="cat">
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-transitions/changing-while-transition-001.html b/testing/web-platform/tests/css/css-transitions/changing-while-transition-001.html
new file mode 100644
index 0000000000..026b16877c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/changing-while-transition-001.html
@@ -0,0 +1,56 @@
+<!doctype html>
+<html>
+<head>
+<meta charset=utf-8>
+<title>CSS Transitions Test: behavior when transition-duration changes while transitioning</title>
+<meta name="assert" content="Checks a change to the transition-duration
+property does not affect an in-flight transition">
+<link rel="help" title="3. Starting of transitions" href="https://drafts.csswg.org/css-transitions/#starting">
+
+<script src="/resources/testharness.js" type="text/javascript"></script>
+<script src="/resources/testharnessreport.js" type="text/javascript"></script>
+<script src="./support/helper.js" type="text/javascript"></script>
+
+</head>
+<body>
+<div id="log"></div>
+
+<script>
+promise_test(async t => {
+ // Start a 100s transition 50% of the way through
+ const div = addDiv(t, {
+ style: 'transition: height 100s -50s linear; height: 0px',
+ });
+ getComputedStyle(div).height;
+ div.style.height = '100px';
+ assert_equals(
+ getComputedStyle(div).height,
+ '50px',
+ 'Transition should be initially 50% complete'
+ );
+
+ // Extend the transition-duration to 200s.
+ div.style.transitionDuration = '200s';
+
+ // If the change to the transition-duration was reflected, the
+ // computed height would now be '25px'.
+ assert_equals(
+ getComputedStyle(div).height,
+ '50px',
+ 'Even after updating the transition-duration, the transition should be 50% complete'
+ );
+
+ // Wait a frame just to be sure that the changed duration is not later
+ // updated.
+ await waitForFrame();
+
+ assert_greater_than_equal(
+ parseInt(getComputedStyle(div).height),
+ 50,
+ 'Even in the next frame the updated transition-duration should not apply'
+ );
+}, 'Changes to transition-duration should not affect in-flight transitions');
+</script>
+
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-transitions/changing-while-transition-002.html b/testing/web-platform/tests/css/css-transitions/changing-while-transition-002.html
new file mode 100644
index 0000000000..363be8a987
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/changing-while-transition-002.html
@@ -0,0 +1,56 @@
+<!doctype html>
+<html>
+<head>
+<meta charset=utf-8>
+<title>CSS Transitions Test: behavior when transition-timing-function changes while transitioning</title>
+<meta name="assert" content="Checks a change to the transition-timing-function
+property does not affect an in-flight transition">
+<link rel="help" title="3. Starting of transitions" href="https://drafts.csswg.org/css-transitions/#starting">
+
+<script src="/resources/testharness.js" type="text/javascript"></script>
+<script src="/resources/testharnessreport.js" type="text/javascript"></script>
+<script src="./support/helper.js" type="text/javascript"></script>
+
+</head>
+<body>
+<div id="log"></div>
+
+<script>
+promise_test(async t => {
+ // Start a transition 50% of the way through with a linear timing function
+ const div = addDiv(t, {
+ style: 'transition: height 100s -50s linear; height: 0px',
+ });
+ getComputedStyle(div).height;
+ div.style.height = '100px';
+ assert_equals(
+ getComputedStyle(div).height,
+ '50px',
+ 'Transition should be initially 50% complete'
+ );
+
+ // Update the timing function
+ div.style.transitionTimingFunction = 'steps(1, end)';
+
+ // If the change to the transition-timing-function was reflected, the
+ // computed height would now be '0px'.
+ assert_equals(
+ getComputedStyle(div).height,
+ '50px',
+ 'Even after updating the transition-timing-function, the transition should be 50% complete'
+ );
+
+ // Wait a frame just to be sure that the changed timing function is not later
+ // updated.
+ await waitForFrame();
+
+ assert_greater_than_equal(
+ parseInt(getComputedStyle(div).height),
+ 50,
+ 'Even in the next frame the updated transition-timing-function should not apply'
+ );
+}, 'Changes to transition-timing-function should not affect in-flight transitions');
+</script>
+
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-transitions/changing-while-transition-003.html b/testing/web-platform/tests/css/css-transitions/changing-while-transition-003.html
new file mode 100644
index 0000000000..8c8f4bb50d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/changing-while-transition-003.html
@@ -0,0 +1,56 @@
+<!doctype html>
+<html>
+<head>
+<meta charset=utf-8>
+<title>CSS Transitions Test: behavior when transition-delay changes while transitioning</title>
+<meta name="assert" content="Checks a change to the transition-delay
+property does not affect an in-flight transition">
+<link rel="help" title="3. Starting of transitions" href="https://drafts.csswg.org/css-transitions/#starting">
+
+<script src="/resources/testharness.js" type="text/javascript"></script>
+<script src="/resources/testharnessreport.js" type="text/javascript"></script>
+<script src="./support/helper.js" type="text/javascript"></script>
+
+</head>
+<body>
+<div id="log"></div>
+
+<script>
+promise_test(async t => {
+ // Start a 200s transition 50% of the way through
+ const div = addDiv(t, {
+ style: 'transition: height 200s -100s linear; height: 0px',
+ });
+ getComputedStyle(div).height;
+ div.style.height = '100px';
+ assert_equals(
+ getComputedStyle(div).height,
+ '50px',
+ 'Transition should be initially 50% complete'
+ );
+
+ // Set the transition-delay to -50s.
+ div.style.transitionDelay = '-50s';
+
+ // If the change to the transition-delay was reflected, the
+ // computed height would now be '25px'.
+ assert_equals(
+ getComputedStyle(div).height,
+ '50px',
+ 'Even after updating the transition-delay, the transition should be 50% complete'
+ );
+
+ // Wait a frame just to be sure that the changed delay is not later
+ // updated.
+ await waitForFrame();
+
+ assert_greater_than_equal(
+ parseInt(getComputedStyle(div).height),
+ 50,
+ 'Even in the next frame the updated transition-delay should not apply'
+ );
+}, 'Changes to transition-delay should not affect in-flight transitions');
+</script>
+
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-transitions/changing-while-transition-004.html b/testing/web-platform/tests/css/css-transitions/changing-while-transition-004.html
new file mode 100644
index 0000000000..71038ac11f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/changing-while-transition-004.html
@@ -0,0 +1,57 @@
+<!doctype html>
+<html>
+<head>
+<meta charset=utf-8>
+<title>CSS Transitions Test: behavior when transition changes to default while transitioning</title>
+<meta name="assert" content="Checks a change to the transition-duration
+property does not affect an in-flight transition">
+<link rel="help" title="3. Starting of transitions" href="https://drafts.csswg.org/css-transitions/#starting">
+
+<script src="/resources/testharness.js" type="text/javascript"></script>
+<script src="/resources/testharnessreport.js" type="text/javascript"></script>
+<script src="./support/helper.js" type="text/javascript"></script>
+
+</head>
+<body>
+<div id="log"></div>
+
+<script>
+promise_test(async t => {
+ // Start a 100s transition 50% of the way through
+ const div = addDiv(t, {
+ style: 'transition: height 100s -50s linear; height: 0px',
+ });
+ getComputedStyle(div).height;
+ div.style.height = '100px';
+ assert_equals(
+ getComputedStyle(div).height,
+ '50px',
+ 'Transition should be initially 50% complete'
+ );
+
+ // Unset the transition property (with default all 0s).
+ div.style.transition = '';
+
+ // If the change to the transition-duration was reflected, the
+ // transition would be cancelled and the computed height
+ // would now be '25px'.
+ assert_equals(
+ getComputedStyle(div).height,
+ '50px',
+ 'Even after unsetting transition, the transition should be 50% complete'
+ );
+
+ // Wait a frame just to be sure that the changed duration is not later
+ // updated.
+ await waitForFrame();
+
+ assert_greater_than_equal(
+ parseInt(getComputedStyle(div).height),
+ 50,
+ 'Even in the next frame the updated transition should not apply'
+ );
+}, 'Unsettign transition should not affect in-flight transitions');
+</script>
+
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-transitions/crashtests/transition-during-style-attr-mutation.html b/testing/web-platform/tests/css/css-transitions/crashtests/transition-during-style-attr-mutation.html
new file mode 100644
index 0000000000..255794bfa8
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/crashtests/transition-during-style-attr-mutation.html
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML>
+<title>Don't crash when mutating style attribute with non-initial transition</title>
+<link rel="help" href="https://crbug.com/1313554">
+<style>
+ #foo { transition: --unset 1s linear; }
+</style>
+<div id=foo style="background-color:red">PASS if no crash</div>
+<script>
+foo.offsetTop;
+foo.style.backgroundColor = 'green';
+foo.offsetTop;
+</script>
diff --git a/testing/web-platform/tests/css/css-transitions/crashtests/transition-large-word-spacing-001.html b/testing/web-platform/tests/css/css-transitions/crashtests/transition-large-word-spacing-001.html
new file mode 100644
index 0000000000..24ac2a7780
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/crashtests/transition-large-word-spacing-001.html
@@ -0,0 +1,15 @@
+<!DOCTYPE HTML>
+<title>CSS Test (Transitions): Transition of large word-spacing value</title>
+<link rel="author" title="L. David Baron" href="https://dbaron.org/">
+<link rel="author" title="Google" href="http://www.google.com/">
+<link rel="help" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1266769">
+<meta name="assert" content="This should not crash.">
+
+<div id="d" style="transition-duration: 1s"></div>
+<script>
+
+let d = document.getElementById("d");
+d.offsetTop;
+d.style.wordSpacing = "100000000000000000000000000000000000000000000000000in";
+
+</script>
diff --git a/testing/web-platform/tests/css/css-transitions/currentcolor-animation-001.html b/testing/web-platform/tests/css/css-transitions/currentcolor-animation-001.html
new file mode 100644
index 0000000000..bcc7991a82
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/currentcolor-animation-001.html
@@ -0,0 +1,53 @@
+<!doctype html>
+<html>
+<head>
+<meta charset=utf-8>
+<title>CSS Transitions of currentcolor</title>
+<link rel="author" title="L. David Baron" href="https://dbaron.org/">
+<link rel="author" title="Mozilla Corporation" href="https://mozilla.com/">
+<link rel="help" href="https://drafts.csswg.org/css-transitions/#starting">
+<link rel="help" href="https://drafts.csswg.org/css-color/#resolving-color-values">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id="log"></div>
+<div id="test"></div>
+<script>
+
+test(() => {
+ const div = document.getElementById('test');
+ const cs = getComputedStyle(div, '');
+
+ // Setup before-change style
+ div.style.color = 'red';
+ div.style.backgroundColor = 'currentcolor';
+ cs.backgroundColor; // Flush style
+
+ // Change color -- this should NOT trigger a transition because as per [1]
+ // the computed value of 'currentcolor' for properties other than 'color'
+ // is 'currentcolor' and transitions operate on computed values (not used
+ // values).
+ //
+ // [1] https://drafts.csswg.org/css-color/#resolving-color-values
+ div.style.transition = 'background-color linear 50s -10s';
+ div.style.color = 'blue';
+ const valueAfterUpdatingColor = cs.backgroundColor;
+
+ // Generate some reference values for comparing
+ div.style.transition = '';
+ div.style.backgroundColor = 'rgb(204, 0, 51)';
+ const quarterReference = cs.backgroundColor;
+
+ div.style.backgroundColor = 'blue';
+ const finalReference = cs.backgroundColor;
+
+ assert_true(
+ valueAfterUpdatingColor != quarterReference &&
+ valueAfterUpdatingColor == finalReference
+ );
+}, 'Transition does not occur when the value is currentcolor and color changes');
+
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-transitions/disconnected-element-001.html b/testing/web-platform/tests/css/css-transitions/disconnected-element-001.html
new file mode 100644
index 0000000000..dd08e559c9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/disconnected-element-001.html
@@ -0,0 +1,190 @@
+<!doctype html>
+<html>
+<head>
+<meta charset=utf-8>
+<title>CSS Transitions Test: Transitions do not run for a disconnected element</title>
+<meta name="assert" content="If an element is not in the document during that
+style change event or was not in the document during the previous style change
+event, then transitions are not started for that element in that style change
+event.">
+<meta name="assert" content="If an element is no longer in the document,
+implementations must cancel any running transitions on it and remove transitions
+on it from the completed transitions.">
+<link rel="help" title="Starting transitions"
+ href="https://drafts.csswg.org/css-transitions/#starting">
+
+<script src="/resources/testharness.js" type="text/javascript"></script>
+<script src="/resources/testharnessreport.js" type="text/javascript"></script>
+<script src="./support/helper.js" type="text/javascript"></script>
+
+</head>
+<body>
+<div id="log"></div>
+
+<script>
+promise_test(async t => {
+ // Create element and remove it from the document
+ const div = addDiv(t, {
+ style: 'transition: background-color 100s; background-color: red',
+ });
+ div.remove();
+
+ // Attach event listeners
+ div.addEventListener('transitionrun', t.step_func(() => {
+ assert_unreached('transitionrun event should not be fired');
+ }));
+
+ // Resolve before-change style
+ getComputedStyle(div).backgroundColor;
+
+ // Set up and resolve after-change style
+ div.style.backgroundColor = 'green';
+ getComputedStyle(div).backgroundColor;
+
+ // There should be no events received for the triggered transition.
+ await waitForFrame();
+ await waitForFrame();
+}, 'Transitions do not run on an element not in the document');
+
+test(t => {
+ // Create element but do not attach it to the document
+ const div = addDiv(t, {
+ style: 'transition: background-color 100s; background-color: red',
+ });
+ div.remove();
+
+ // Resolve before-change style
+ getComputedStyle(div).backgroundColor;
+
+ // Add to document
+ document.documentElement.append(div);
+
+ // Set up and resolve after-change style
+ div.style.backgroundColor = 'green';
+ getComputedStyle(div).backgroundColor;
+
+ // We should have jumped immediately to the after-change style rather than
+ // transitioning to it.
+ assert_equals(
+ getComputedStyle(div).backgroundColor,
+ 'rgb(0, 128, 0)',
+ 'No transition should run'
+ );
+}, 'Transitions do not run for an element newly added to the document');
+
+promise_test(async t => {
+ // Create element and attach it to the document
+ const div = addDiv(t, {
+ style: 'transition: background-color 100s; background-color: red',
+ });
+
+ // Attach event listeners
+ div.addEventListener('transitionrun', t.step_func(() => {
+ assert_unreached('transitionrun event should not be fired');
+ }));
+
+ // Resolve before-change style
+ getComputedStyle(div).backgroundColor;
+
+ // Set up after-change style
+ div.style.backgroundColor = 'green';
+
+ // But remove the document before the next style change event
+ div.remove();
+
+ // There should be no events received for the triggered transition.
+ await waitForFrame();
+ await waitForFrame();
+}, 'Transitions do not run for an element newly removed from the document');
+
+promise_test(async t => {
+ // Create element and attach it to the document
+ const div = addDiv(t, {
+ style: 'transition: background-color 100s; background-color: red',
+ });
+
+ // Attach event listeners
+ const eventWatcher = new EventWatcher(t, div, [
+ 'transitionrun',
+ 'transitioncancel',
+ ]);
+
+ // Trigger transition
+ getComputedStyle(div).backgroundColor;
+ div.style.backgroundColor = 'green';
+ getComputedStyle(div).backgroundColor;
+
+ await eventWatcher.wait_for('transitionrun');
+
+ // Remove the element from the document
+ div.remove();
+
+ await eventWatcher.wait_for('transitioncancel');
+}, 'Transitions are canceled when an element is removed from the document');
+
+promise_test(async t => {
+ // Create a container element. We'll need this later.
+ const container = addDiv(t);
+
+ // Create element and attach it to the document
+ const div = addDiv(t, {
+ style: 'transition: background-color 100s; background-color: red',
+ });
+
+ // Attach event listeners
+ const eventWatcher = new EventWatcher(t, div, [
+ 'transitionrun',
+ 'transitioncancel',
+ ]);
+
+ // Trigger transition
+ getComputedStyle(div).backgroundColor;
+ div.style.backgroundColor = 'green';
+ getComputedStyle(div).backgroundColor;
+
+ await eventWatcher.wait_for('transitionrun');
+
+ // Re-parent element
+ container.append(div);
+
+ await eventWatcher.wait_for('transitioncancel');
+ assert_equals(
+ getComputedStyle(div).backgroundColor,
+ 'rgb(0, 128, 0)',
+ 'There should be no transition after re-parenting'
+ );
+}, 'Transitions are canceled when an element is re-parented');
+
+promise_test(async t => {
+ // Create element and attach it to the document
+ const div = addDiv(t, {
+ style: 'transition: background-color 100s; background-color: red',
+ });
+
+ // Attach event listeners
+ const eventWatcher = new EventWatcher(t, div, [
+ 'transitionrun',
+ 'transitioncancel',
+ ]);
+
+ // Trigger transition
+ getComputedStyle(div).backgroundColor;
+ div.style.backgroundColor = 'green';
+ getComputedStyle(div).backgroundColor;
+
+ await eventWatcher.wait_for('transitionrun');
+
+ // Re-parent element to same parent
+ document.documentElement.append(div);
+
+ await eventWatcher.wait_for('transitioncancel');
+ assert_equals(
+ getComputedStyle(div).backgroundColor,
+ 'rgb(0, 128, 0)',
+ 'There should be no transition after re-parenting'
+ );
+}, 'Transitions are canceled when an element is re-parented to the same node');
+</script>
+
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-transitions/display-none-no-animations.html b/testing/web-platform/tests/css/css-transitions/display-none-no-animations.html
new file mode 100644
index 0000000000..32535baf9c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/display-none-no-animations.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<link rel=help href="mailto:jarhar@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<div id=target>target</div>
+<style>
+#target {
+ display: none;
+ transition: 1s;
+ color: red;
+}
+#target.animated {
+ transition: 1s;
+ color: green;
+}
+</style>
+
+<script>
+test(() => {
+ target.addEventListener('transitionstart', () => {
+ assert_unreached('transitionstart should not be fired.');
+ });
+ target.classList.add('animated');
+ assert_equals(target.getAnimations().length, 0,
+ 'There should not be any animations running.');
+}, 'Transitions and animations should not occur on display:none elements.');
+</script>
diff --git a/testing/web-platform/tests/css/css-transitions/dynamic-root-element.html b/testing/web-platform/tests/css/css-transitions/dynamic-root-element.html
new file mode 100644
index 0000000000..befc20d1d0
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/dynamic-root-element.html
@@ -0,0 +1,34 @@
+<!doctype html>
+<meta charset="utf-8">
+<link rel="help" href="https://drafts.csswg.org/css-transitions/#starting">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1816672">
+<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
+<link rel="author" title="Mozilla" href="https://mozilla.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<iframe></iframe>
+<script>
+ let t = async_test("Transitions don't incorrectly start on dynamic document element insertion");
+ window.onload = t.step_func_done(function() {
+ let frame = document.querySelector("iframe");
+ let doc = frame.contentDocument;
+ doc.open();
+ doc.write("<!doctype html>");
+ let root = doc.createElement("html");
+ root.innerHTML = `
+ <style>
+ div {
+ width: 100px;
+ height: 100px;
+ background-color: blue;
+ transition: margin-left 10s ease;
+ margin-left: 100px;
+ }
+ </style>
+ <div></div>
+ `;
+ doc.appendChild(root);
+ doc.close();
+ assert_equals(frame.contentWindow.getComputedStyle(doc.querySelector("div")).marginLeft, "100px", "Transition shouldn't have started");
+ });
+</script>
diff --git a/testing/web-platform/tests/css/css-transitions/event-dispatch.tentative.html b/testing/web-platform/tests/css/css-transitions/event-dispatch.tentative.html
new file mode 100644
index 0000000000..5ed01cdd25
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/event-dispatch.tentative.html
@@ -0,0 +1,435 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>CSS transition event dispatch</title>
+<link rel="help" href="https://drafts.csswg.org/css-transitions-2/#event-dispatch">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/helper.js"></script>
+<div id="log"></div>
+<script>
+'use strict';
+
+// All transition events should be received on the next animation frame. If
+// two animation frames pass before receiving the expected events then we
+// can immediately fail the current test.
+const transitionEventsTimeout = () => {
+ return waitForAnimationFrames(2);
+};
+
+const setupTransition = (t, transitionStyle) => {
+ const div = addDiv(t, { style: 'transition: ' + transitionStyle });
+ const watcher = new EventWatcher(t, div, [ 'transitionrun',
+ 'transitionstart',
+ 'transitionend',
+ 'transitioncancel' ],
+ transitionEventsTimeout);
+ getComputedStyle(div).marginLeft;
+
+ div.style.marginLeft = '100px';
+ const transition = div.getAnimations()[0];
+
+ return { transition, watcher, div };
+};
+
+// On the next frame (i.e. when events are queued), whether or not the
+// transition is still pending depends on the implementation.
+promise_test(async t => {
+ const { transition, watcher } =
+ setupTransition(t, 'margin-left 100s 100s');
+ const evt = await watcher.wait_for('transitionrun');
+ assert_equals(evt.elapsedTime, 0.0);
+}, 'Idle -> Pending or Before');
+
+promise_test(async t => {
+ const { transition, watcher } =
+ setupTransition(t, 'margin-left 100s 100s');
+ // Force the transition to leave the idle phase
+ transition.startTime = document.timeline.currentTime;
+ const evt = await watcher.wait_for('transitionrun');
+ assert_equals(evt.elapsedTime, 0.0);
+}, 'Idle -> Before');
+
+promise_test(async t => {
+ const { transition, watcher } = setupTransition(t, 'margin-left 100s 100s');
+
+ // Seek to Active phase.
+ transition.currentTime = 100 * MS_PER_SEC;
+ transition.pause();
+ const events = await watcher.wait_for(['transitionrun', 'transitionstart'], {
+ record: 'all',
+ });
+ assert_equals(events[0].elapsedTime, 0.0);
+ assert_equals(events[1].elapsedTime, 0.0);
+}, 'Idle or Pending -> Active');
+
+promise_test(async t => {
+ const { transition, watcher } = setupTransition(t, 'margin-left 100s 100s');
+
+ // Seek to After phase.
+ transition.finish();
+ const events = await watcher.wait_for(
+ ['transitionrun', 'transitionstart', 'transitionend'],
+ {
+ record: 'all',
+ }
+ );
+ assert_equals(events[0].elapsedTime, 0.0);
+ assert_equals(events[1].elapsedTime, 0.0);
+ assert_equals(events[2].elapsedTime, 100.0);
+}, 'Idle or Pending -> After');
+
+promise_test(async t => {
+ const { transition, watcher, div } =
+ setupTransition(t, 'margin-left 100s 100s');
+
+ await Promise.all([ watcher.wait_for('transitionrun'), transition.ready ]);
+
+ // Make idle
+ div.style.display = 'none';
+ getComputedStyle(div).marginLeft;
+ const evt = await watcher.wait_for('transitioncancel');
+ assert_equals(evt.elapsedTime, 0.0);
+}, 'Before -> Idle (display: none)');
+
+promise_test(async t => {
+ const { transition, watcher } =
+ setupTransition(t, 'margin-left 100s 100s');
+
+ await Promise.all([ watcher.wait_for('transitionrun'), transition.ready ]);
+
+ // Make idle
+ transition.timeline = null;
+ const evt = await watcher.wait_for('transitioncancel');
+ assert_equals(evt.elapsedTime, 0.0);
+}, 'Before -> Idle (Animation.timeline = null)');
+
+promise_test(async t => {
+ const { transition, watcher } =
+ setupTransition(t, 'margin-left 100s 100s');
+
+ await Promise.all([ watcher.wait_for('transitionrun'), transition.ready ]);
+
+ transition.currentTime = 100 * MS_PER_SEC;
+ const evt = await watcher.wait_for('transitionstart');
+ assert_equals(evt.elapsedTime, 0.0);
+}, 'Before -> Active');
+
+promise_test(async t => {
+ const { transition, watcher } = setupTransition(t, 'margin-left 100s 100s');
+
+ await Promise.all([ watcher.wait_for('transitionrun'), transition.ready ]);
+ // Seek to After phase.
+ transition.currentTime = 200 * MS_PER_SEC;
+ const events = await watcher.wait_for(['transitionstart', 'transitionend'], {
+ record: 'all',
+ });
+
+ assert_equals(events[0].elapsedTime, 0.0);
+ assert_equals(events[1].elapsedTime, 100.0);
+}, 'Before -> After');
+
+promise_test(async t => {
+ const { transition, watcher, div } = setupTransition(t, 'margin-left 100s');
+
+ // Seek to Active start position.
+ transition.pause();
+ await watcher.wait_for([ 'transitionrun', 'transitionstart' ]);
+
+ // Make idle
+ div.style.display = 'none';
+ getComputedStyle(div).marginLeft;
+ const evt = await watcher.wait_for('transitioncancel');
+ assert_equals(evt.elapsedTime, 0.0);
+}, 'Active -> Idle, no delay (display: none)');
+
+promise_test(async t => {
+ const { transition, watcher } = setupTransition(t, 'margin-left 100s');
+
+ await watcher.wait_for([ 'transitionrun', 'transitionstart' ]);
+
+ // Make idle
+ transition.currentTime = 0;
+ transition.timeline = null;
+ const evt = await watcher.wait_for('transitioncancel');
+ assert_equals(evt.elapsedTime, 0.0);
+}, 'Active -> Idle, no delay (Animation.timeline = null)');
+
+promise_test(async t => {
+ const { transition, watcher, div } =
+ setupTransition(t, 'margin-left 100s 100s');
+ // Pause so the currentTime is fixed and we can accurately compare the event
+ // time in transition cancel events.
+ transition.pause();
+
+ // Seek to Active phase.
+ transition.currentTime = 100 * MS_PER_SEC;
+ await watcher.wait_for([ 'transitionrun', 'transitionstart' ]);
+
+ // Make idle
+ div.style.display = 'none';
+ getComputedStyle(div).marginLeft;
+ const evt = await watcher.wait_for('transitioncancel');
+ assert_equals(evt.elapsedTime, 0.0);
+}, 'Active -> Idle, with positive delay (display: none)');
+
+promise_test(async t => {
+ const { transition, watcher } = setupTransition(t, 'margin-left 100s 100s');
+
+ // Seek to Active phase.
+ transition.currentTime = 100 * MS_PER_SEC;
+ await watcher.wait_for([ 'transitionrun', 'transitionstart' ]);
+
+ // Make idle
+ transition.currentTime = 100 * MS_PER_SEC;
+ transition.timeline = null;
+ const evt = await watcher.wait_for('transitioncancel');
+ assert_equals(evt.elapsedTime, 0.0);
+}, 'Active -> Idle, with positive delay (Animation.timeline = null)');
+
+promise_test(async t => {
+ const { transition, watcher, div } =
+ setupTransition(t, 'margin-left 100s -50s');
+
+ // Pause so the currentTime is fixed and we can accurately compare the event
+ // time in transition cancel events.
+ transition.pause();
+
+ await watcher.wait_for([ 'transitionrun', 'transitionstart' ]);
+
+ // Make idle
+ div.style.display = 'none';
+ getComputedStyle(div).marginLeft;
+ const evt = await watcher.wait_for('transitioncancel');
+ assert_equals(evt.elapsedTime, 50.0);
+}, 'Active -> Idle, with negative delay (display: none)');
+
+promise_test(async t => {
+ const { transition, watcher } = setupTransition(t, 'margin-left 100s -50s');
+
+ await watcher.wait_for([ 'transitionrun', 'transitionstart' ]);
+
+ // Make idle
+ transition.currentTime = 50 * MS_PER_SEC;
+ transition.timeline = null;
+ const evt = await watcher.wait_for('transitioncancel');
+ assert_equals(evt.elapsedTime, 0.0);
+}, 'Active -> Idle, with negative delay (Animation.timeline = null)');
+
+promise_test(async t => {
+ const { transition, watcher } = setupTransition(t, 'margin-left 100s 100s');
+
+ // Seek to Active phase.
+ transition.currentTime = 100 * MS_PER_SEC;
+ await watcher.wait_for([ 'transitionrun', 'transitionstart' ]);
+
+ // Seek to Before phase.
+ transition.currentTime = 0;
+ const evt = await watcher.wait_for('transitionend');
+ assert_equals(evt.elapsedTime, 0.0);
+}, 'Active -> Before');
+
+promise_test(async t => {
+ const { transition, watcher } = setupTransition(t, 'margin-left 100s 100s');
+
+ // Seek to Active phase.
+ transition.currentTime = 100 * MS_PER_SEC;
+ await watcher.wait_for([ 'transitionrun', 'transitionstart' ]);
+
+ // Seek to After phase.
+ transition.currentTime = 200 * MS_PER_SEC;
+ const evt = await watcher.wait_for('transitionend');
+ assert_equals(evt.elapsedTime, 100.0);
+}, 'Active -> After');
+
+promise_test(async t => {
+ const { transition, watcher } = setupTransition(t, 'margin-left 100s 100s');
+
+ // Seek to After phase.
+ transition.finish();
+ await watcher.wait_for([ 'transitionrun',
+ 'transitionstart',
+ 'transitionend' ]);
+
+ // Seek to Before phase.
+ transition.currentTime = 0;
+ const events = await watcher.wait_for(['transitionstart', 'transitionend'], {
+ record: 'all',
+ });
+
+ assert_equals(events[0].elapsedTime, 100.0);
+ assert_equals(events[1].elapsedTime, 0.0);
+}, 'After -> Before');
+
+promise_test(async t => {
+ const { transition, watcher } = setupTransition(t, 'margin-left 100s 100s');
+
+ // Seek to After phase.
+ transition.finish();
+ await watcher.wait_for([ 'transitionrun',
+ 'transitionstart',
+ 'transitionend' ]);
+
+ // Seek to Active phase.
+ transition.currentTime = 100 * MS_PER_SEC;
+ const evt = await watcher.wait_for('transitionstart');
+ assert_equals(evt.elapsedTime, 100.0);
+}, 'After -> Active');
+
+promise_test(async t => {
+ const { transition, watcher } = setupTransition(t, 'margin-left 100s -50s');
+
+ const events = await watcher.wait_for(['transitionrun', 'transitionstart'], {
+ record: 'all',
+ });
+
+ assert_equals(events[0].elapsedTime, 50.0);
+ assert_equals(events[1].elapsedTime, 50.0);
+ transition.finish();
+
+ const evt = await watcher.wait_for('transitionend');
+ assert_equals(evt.elapsedTime, 100.0);
+}, 'Calculating the interval start and end time with negative start delay.');
+
+promise_test(async t => {
+ const { transition, watcher, div } = setupTransition(
+ t,
+ 'margin-left 100s 100s'
+ );
+
+ await watcher.wait_for('transitionrun');
+
+ // We can't set the end delay via generated effect timing
+ // because mutating CSS transitions is not specced yet.
+ transition.effect = new KeyframeEffect(
+ div,
+ { marginLeft: ['0px', '100px'] },
+ {
+ duration: 100 * MS_PER_SEC,
+ endDelay: -50 * MS_PER_SEC,
+ }
+ );
+ // Seek to Before and play.
+ transition.cancel();
+ transition.play();
+ const events = await watcher.wait_for(
+ ['transitioncancel', 'transitionrun', 'transitionstart'],
+ { record: 'all' }
+ );
+ assert_equals(events[2].elapsedTime, 0.0);
+
+ // Seek to After phase.
+ transition.finish();
+ const evt = await watcher.wait_for('transitionend');
+ assert_equals(evt.elapsedTime, 50.0);
+}, 'Calculating the interval start and end time with negative end delay.');
+
+promise_test(async t => {
+ const { transition, watcher, div } =
+ setupTransition(t, 'margin-left 100s 100s');
+
+ await watcher.wait_for('transitionrun');
+
+ // Make idle
+ div.style.display = 'none';
+ getComputedStyle(div).marginLeft;
+ await watcher.wait_for('transitioncancel');
+
+ transition.cancel();
+ // Then wait a couple of frames and check that no event was dispatched
+ await waitForAnimationFrames(2);
+}, 'Call Animation.cancel after canceling transition.');
+
+promise_test(async t => {
+ const { transition, watcher, div } =
+ setupTransition(t, 'margin-left 100s 100s');
+
+ await watcher.wait_for('transitionrun');
+
+ // Make idle
+ transition.cancel();
+ transition.play();
+ await watcher.wait_for([ 'transitioncancel',
+ 'transitionrun' ]);
+}, 'Restart transition after canceling transition immediately');
+
+promise_test(async t => {
+ const { transition, watcher, div } =
+ setupTransition(t, 'margin-left 100s 100s');
+
+ await watcher.wait_for('transitionrun');
+
+ // Make idle
+ div.style.display = 'none';
+ getComputedStyle(div).marginLeft;
+ transition.play();
+ transition.cancel();
+ await watcher.wait_for('transitioncancel');
+
+ // Then wait a couple of frames and check that no event was dispatched
+ await waitForAnimationFrames(2);
+}, 'Call Animation.cancel after restarting transition immediately');
+
+promise_test(async t => {
+ const { transition, watcher } = setupTransition(t, 'margin-left 100s');
+
+ await watcher.wait_for([ 'transitionrun', 'transitionstart' ]);
+
+ // Make idle
+ transition.timeline = null;
+ await watcher.wait_for('transitioncancel');
+
+ transition.timeline = document.timeline;
+ transition.play();
+
+ await watcher.wait_for(['transitionrun', 'transitionstart']);
+}, 'Set timeline and play transition after clear the timeline');
+
+promise_test(async t => {
+ const { transition, watcher, div } =
+ setupTransition(t, 'margin-left 100s');
+
+ await watcher.wait_for([ 'transitionrun', 'transitionstart' ]);
+
+ transition.cancel();
+ await watcher.wait_for('transitioncancel');
+
+ // Make After phase
+ transition.effect = null;
+
+ // Then wait a couple of frames and check that no event was dispatched
+ await waitForAnimationFrames(2);
+}, 'Set null target effect after canceling the transition');
+
+promise_test(async t => {
+ const { transition, watcher, div } = setupTransition(t, 'margin-left 100s');
+
+ await watcher.wait_for([ 'transitionrun', 'transitionstart' ]);
+
+ transition.effect = null;
+ await watcher.wait_for('transitionend');
+
+ transition.cancel();
+
+ // Then wait a couple of frames and check that no event was dispatched
+ await waitForAnimationFrames(2);
+}, 'Cancel the transition after clearing the target effect');
+
+promise_test(async t => {
+ const { transition, watcher, div } = setupTransition(t, 'margin-left 100s');
+
+ // Seek to After phase.
+ transition.finish();
+ const events = await watcher.wait_for(
+ ['transitionrun', 'transitionstart', 'transitionend'],
+ {
+ record: 'all',
+ }
+ );
+
+ transition.cancel();
+
+ // Then wait a couple of frames and check that no event was dispatched
+ await waitForAnimationFrames(2);
+}, 'Cancel the transition after it finishes');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-transitions/events-001.html b/testing/web-platform/tests/css/css-transitions/events-001.html
new file mode 100644
index 0000000000..59d2011b39
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/events-001.html
@@ -0,0 +1,150 @@
+<!doctype html>
+<html>
+<head>
+<meta charset=utf-8>
+<title>CSS Transitions Test: transitionend event for shorthand property</title>
+<meta name="assert" content="This test checks that all transitionend events are triggered for shorthand property">
+<link rel="help" href="http://www.w3.org/TR/css3-transitions/#transition-property-property">
+<link rel="help" href="http://www.w3.org/TR/css3-transitions/#transition-events">
+<link rel="author" title="Rodney Rehm" href="http://rodneyrehm.de/en/">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="./support/helper.js"></script>
+
+</head>
+<body>
+
+<script>
+promise_test(t => {
+ const div = addDiv(t, { style: 'transition: all .01s linear; ' +
+ 'padding-left: 1px' });
+ getComputedStyle(div).paddingLeft;
+ div.style.paddingLeft = '10px';
+
+ const watcher = new EventWatcher(t, div, [ 'transitionend' ]);
+ return watcher.wait_for('transitionend').then(evt => {
+ assert_end_events_equal(evt, 'padding-left', 0.01);
+ });
+}, 'transition:all changing padding-left');
+
+promise_test(t => {
+ const div = addDiv(t, { style: 'transition: all .01s linear; ' +
+ 'padding: 1px' });
+ getComputedStyle(div).paddingLeft;
+ div.style.padding = '10px';
+
+ const watcher = new EventWatcher(t, div, [ 'transitionend' ]);
+ return watcher.wait_for(Array(4).fill('transitionend'),
+ { record: 'all' }).then(evts => {
+ assert_end_event_batch_equal(evts,
+ [ 'padding-bottom',
+ 'padding-left',
+ 'padding-right',
+ 'padding-top' ],
+ 0.01);
+ });
+}, 'transition:all changing padding');
+
+promise_test(t => {
+ const div = addDiv(t, { style: 'transition: all .01s linear; ' +
+ 'padding: 1px' });
+ getComputedStyle(div).paddingLeft;
+ div.style.padding = '10px 10px 1px 10px';
+
+ const watcher = new EventWatcher(t, div, [ 'transitionend' ]);
+ return watcher.wait_for(Array(3).fill('transitionend'),
+ { record: 'all' }).then(evts => {
+ assert_end_event_batch_equal(evts,
+ [ 'padding-left',
+ 'padding-right',
+ 'padding-top' ],
+ 0.01);
+ });
+}, 'transition:all changing padding but not padding-bottom');
+
+promise_test(t => {
+ const div = addDiv(t, { style: 'transition: padding .01s linear; ' +
+ 'padding-left: 1px' });
+ getComputedStyle(div).paddingLeft;
+ div.style.paddingLeft = '10px';
+
+ const watcher = new EventWatcher(t, div, [ 'transitionend' ]);
+ return watcher.wait_for('transitionend').then(evt => {
+ assert_end_events_equal(evt, 'padding-left', 0.01);
+ });
+}, 'transition:padding changing padding-left');
+
+promise_test(t => {
+ const div = addDiv(t, { style: 'transition: padding .01s linear; ' +
+ 'padding: 1px' });
+ getComputedStyle(div).paddingLeft;
+ div.style.padding = '10px';
+
+ const watcher = new EventWatcher(t, div, [ 'transitionend' ]);
+ return watcher.wait_for(Array(4).fill('transitionend'),
+ { record: 'all' }).then(evts => {
+ assert_end_event_batch_equal(evts,
+ [ 'padding-bottom',
+ 'padding-left',
+ 'padding-right',
+ 'padding-top' ],
+ 0.01);
+ });
+}, 'transition:padding changing padding');
+
+promise_test(t => {
+ const div = addDiv(t, { style: 'transition: padding .01s linear; ' +
+ 'padding: 1px' });
+ getComputedStyle(div).paddingLeft;
+ div.style.padding = '10px 10px 1px 10px';
+
+ const watcher = new EventWatcher(t, div, [ 'transitionend' ]);
+ return watcher.wait_for(Array(3).fill('transitionend'),
+ { record: 'all' }).then(evts => {
+ assert_end_event_batch_equal(evts,
+ [ 'padding-left',
+ 'padding-right',
+ 'padding-top' ],
+ 0.01);
+ });
+}, 'transition:padding changing padding but not padding-bottom');
+
+promise_test(t => {
+ const div = addDiv(t, { style: 'transition: padding-left .01s linear; ' +
+ 'padding-left: 1px' });
+ getComputedStyle(div).paddingLeft;
+ div.style.paddingLeft = '10px';
+
+ const watcher = new EventWatcher(t, div, [ 'transitionend' ]);
+ return watcher.wait_for('transitionend').then(evt => {
+ assert_end_events_equal(evt, 'padding-left', 0.01);
+ });
+}, 'transition:padding-left changing padding-left');
+
+promise_test(t => {
+ const div = addDiv(t, { style: 'transition: padding-left .01s linear; ' +
+ 'padding: 1px' });
+ getComputedStyle(div).paddingLeft;
+ div.style.padding = '10px';
+
+ const watcher = new EventWatcher(t, div, [ 'transitionend' ]);
+ return watcher.wait_for('transitionend').then(evt => {
+ assert_end_events_equal(evt, 'padding-left', 0.01);
+ });
+}, 'transition:padding-left changing padding');
+
+promise_test(t => {
+ const div = addDiv(t, { style: 'transition: padding-left .01s linear; ' +
+ 'padding: 1px' });
+ getComputedStyle(div).paddingLeft;
+ div.style.padding = '10px 10px 1px 10px';
+
+ const watcher = new EventWatcher(t, div, [ 'transitionend' ]);
+ return watcher.wait_for('transitionend').then(evt => {
+ assert_end_events_equal(evt, 'padding-left', 0.01);
+ });
+}, 'transition:padding-left changing padding but not padding-bottom');
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-transitions/events-002.html b/testing/web-platform/tests/css/css-transitions/events-002.html
new file mode 100644
index 0000000000..3ec2cc3da4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/events-002.html
@@ -0,0 +1,49 @@
+<!doctype html>
+<html>
+<head>
+<meta charset=utf-8>
+<title>CSS Transitions Test: transitionend event for implied property value</title>
+<meta name="assert" content="Test checks that all transitionend events are triggered for implied property value">
+<link rel="help" title="5. Transition Events" href="http://www.w3.org/TR/css3-transitions/#transition-events">
+<link rel="author" title="Rodney Rehm" href="http://rodneyrehm.de/en/">
+
+<script src="/resources/testharness.js" type="text/javascript"></script>
+<script src="/resources/testharnessreport.js" type="text/javascript"></script>
+<script src="./support/helper.js" type="text/javascript"></script>
+
+</head>
+<body>
+
+<div id="log"></div>
+
+<script>
+promise_test(t => {
+ const div = addDiv(t, { style: 'transition: all .01s linear' });
+ getComputedStyle(div).paddingLeft;
+ div.style.paddingLeft = '10px';
+
+ const watcher = new EventWatcher(t, div, [ 'transitionend' ]);
+ return watcher.wait_for('transitionend').then(evt => {
+ assert_end_events_equal(evt, 'padding-left', 0.01);
+ });
+}, 'transition:all changing padding-left from nothing');
+
+promise_test(t => {
+ const div = addDiv(t, { style: 'transition: all .01s linear' });
+ getComputedStyle(div).paddingLeft;
+ div.style.padding = '10px';
+
+ const watcher = new EventWatcher(t, div, [ 'transitionend' ]);
+ return watcher.wait_for(Array(4).fill('transitionend'),
+ { record: 'all' }).then(evts => {
+ assert_end_event_batch_equal(evts,
+ [ 'padding-bottom',
+ 'padding-left',
+ 'padding-right',
+ 'padding-top' ],
+ 0.01);
+ });
+}, 'transition:all changing padding from nothing');
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-transitions/events-003.html b/testing/web-platform/tests/css/css-transitions/events-003.html
new file mode 100644
index 0000000000..2f8ac7f424
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/events-003.html
@@ -0,0 +1,34 @@
+<!doctype html>
+<html>
+<head>
+<meta charset=utf-8>
+<title>CSS Transitions Test: transitionend event with negative delay</title>
+<meta name="assert" content="Test checks that transitionend event is triggered for duration time being canceled out by negative delay">
+<link rel="help" title="2.4. The 'transition-delay' Property" href="http://www.w3.org/TR/css3-transitions/#transition-delay-property">
+<link rel="help" title="5. Transition Events" href="http://www.w3.org/TR/css3-transitions/#transition-events">
+<link rel="author" title="Rodney Rehm" href="http://rodneyrehm.de/en/">
+
+<script src="/resources/testharness.js" type="text/javascript"></script>
+<script src="/resources/testharnessreport.js" type="text/javascript"></script>
+<script src="./support/helper.js" type="text/javascript"></script>
+
+</head>
+<body>
+
+<div id="log"></div>
+
+<script>
+promise_test(t => {
+ const div = addDiv(t, { style: 'transition: all .02s -.01s; ' +
+ 'padding-left: 1px' });
+ getComputedStyle(div).paddingLeft;
+ div.style.paddingLeft = '10px';
+
+ const watcher = new EventWatcher(t, div, [ 'transitionend' ]);
+ return watcher.wait_for('transitionend').then(evt => {
+ assert_end_events_equal(evt, 'padding-left', 0.02);
+ });
+}, 'duration: 0.02s, delay: -0.01s');
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-transitions/events-004.html b/testing/web-platform/tests/css/css-transitions/events-004.html
new file mode 100644
index 0000000000..17195f40eb
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/events-004.html
@@ -0,0 +1,61 @@
+<!doctype html>
+<html>
+<head>
+<meta charset=utf-8>
+<title>CSS Transitions Test: transitionend event with non matching lists</title>
+<meta name="assert" content="Test checks that non-matching lists are properly resolved">
+<link rel="help" title="2. Transitions - Example 3" href="http://www.w3.org/TR/css3-transitions/#list-matching">
+<link rel="help" title="5. Transition Events" href="http://www.w3.org/TR/css3-transitions/#transition-events">
+<link rel="author" title="Rodney Rehm" href="http://rodneyrehm.de/en/">
+
+<script src="/resources/testharness.js" type="text/javascript"></script>
+<script src="/resources/testharnessreport.js" type="text/javascript"></script>
+<script src="./support/helper.js" type="text/javascript"></script>
+
+</head>
+<body>
+
+<div id="log"></div>
+
+<script>
+promise_test(t => {
+ const div = addDiv(t, { style: 'padding: 1px' });
+ getComputedStyle(div).paddingLeft;
+
+ div.style.transitionProperty =
+ 'padding-top, padding-right, padding-bottom, padding-left';
+ div.style.transitionDuration = '0.02s, 0.01s';
+ div.style.transitionTimingFunction = 'linear, ease-in';
+ div.style.transitionDelay = '0.01s, 0.02s';
+ div.style.padding = '10px';
+
+ const watcher = new EventWatcher(t, div, ['transitionend']);
+ return watcher
+ .wait_for(Array(4).fill('transitionend'), { record: 'all' })
+ .then(evts => {
+ assert_end_event_batch_equal(
+ evts,
+ [ 'padding-top', 'padding-right', 'padding-bottom', 'padding-left' ],
+ [ 0.02, 0.01, 0.02, 0.01 ]
+ );
+ });
+}, 'repeating lists');
+
+promise_test(t => {
+ const div = addDiv(t, { style: 'padding: 1px' });
+ getComputedStyle(div).paddingLeft;
+
+ div.style.transitionProperty = 'padding-top';
+ div.style.transitionDuration = '0.02s, 0.01s';
+ div.style.transitionTimingFunction = 'linear, ease-in';
+ div.style.transitionDelay = '0.01s, 0.02s';
+ div.style.padding = '10px';
+
+ const watcher = new EventWatcher(t, div, [ 'transitionend' ]);
+ return watcher.wait_for('transitionend').then(evt => {
+ assert_end_events_equal(evt, 'padding-top', 0.02);
+ });
+}, 'truncating lists');
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-transitions/events-005.html b/testing/web-platform/tests/css/css-transitions/events-005.html
new file mode 100644
index 0000000000..48ba63ab2d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/events-005.html
@@ -0,0 +1,67 @@
+<!doctype html>
+<html>
+<head>
+<meta charset=utf-8>
+<title>CSS Transitions Test: transitionend event with property specificity</title>
+<meta name="assert" content="Test checks that property specificity is properly resolved">
+<link rel="help" title="2.1. The 'transition-property' Property" href="http://www.w3.org/TR/css3-transitions/#transition-property-property">
+<link rel="help" title="5. Transition Events" href="http://www.w3.org/TR/css3-transitions/#transition-events">
+<link rel="author" title="Rodney Rehm" href="http://rodneyrehm.de/en/">
+
+<script src="/resources/testharness.js" type="text/javascript"></script>
+<script src="/resources/testharnessreport.js" type="text/javascript"></script>
+<script src="./support/helper.js" type="text/javascript"></script>
+
+</head>
+<body>
+
+<div id="log"></div>
+
+<script>
+promise_test(t => {
+ const div = addDiv(t, {
+ style:
+ 'transition: padding-left .01s, padding-left .02s;' +
+ 'padding-left: 1px'
+ });
+ getComputedStyle(div).paddingLeft;
+ div.style.paddingLeft = '10px';
+
+ const watcher = new EventWatcher(t, div, [ 'transitionend' ]);
+ return watcher.wait_for('transitionend').then(evt => {
+ assert_end_events_equal(evt, 'padding-left', 0.02);
+ });
+}, 'property repetition');
+
+promise_test(t => {
+ const div = addDiv(t, {
+ style:
+ 'transition: padding .01s, padding-left .02s;' +
+ 'padding-left: 1px'
+ });
+ getComputedStyle(div).paddingLeft;
+ div.style.paddingLeft = '10px';
+
+ const watcher = new EventWatcher(t, div, [ 'transitionend' ]);
+ return watcher.wait_for('transitionend').then(evt => {
+ assert_end_events_equal(evt, 'padding-left', 0.02);
+ });
+}, 'padding, padding-left');
+
+promise_test(t => {
+ const div = addDiv(t, {
+ style:
+ 'transition: padding-left .01s, padding .02s;' +
+ 'padding-left: 1px'
+ });
+ getComputedStyle(div).paddingLeft;
+ div.style.paddingLeft = '10px';
+
+ const watcher = new EventWatcher(t, div, [ 'transitionend' ]);
+ return watcher.wait_for('transitionend').then(evt => {
+ assert_end_events_equal(evt, 'padding-left', 0.02);
+ });
+}, 'padding-left, padding');
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-transitions/events-006.html b/testing/web-platform/tests/css/css-transitions/events-006.html
new file mode 100644
index 0000000000..36412bcd9e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/events-006.html
@@ -0,0 +1,58 @@
+<!doctype html>
+<html>
+<head>
+<meta charset=utf-8>
+<title>CSS Transitions Test: transitionend event for pseudo elements</title>
+<meta name="assert" content="Test checks that TransitionEnd events are fired for pseudo-elements">
+<link rel="help" title="5. Transition Events" href="http://www.w3.org/TR/css3-transitions/#transition-events">
+<link rel="help" title="CSS21 - 12.1 The :before and :after pseudo-elements" href="http://www.w3.org/TR/CSS21/generate.html#before-after-content">
+<link rel="help" title="CSS3 Generated and Replaced Content Module" href="http://www.w3.org/TR/css3-content/">
+<link rel="author" title="Rodney Rehm" href="http://rodneyrehm.de/en/">
+
+<script src="/resources/testharness.js" type="text/javascript"></script>
+<script src="/resources/testharnessreport.js" type="text/javascript"></script>
+<script src="./support/helper.js" type="text/javascript"></script>
+
+<style>
+.before::before,
+.after:after {
+ content: '';
+ transition: padding-left .01s;
+ padding-left: 1px;
+}
+.before.active::before,
+.after.active:after {
+ padding-left: 10px;
+}
+</style>
+
+</head>
+<body>
+
+<div id="log"></div>
+
+<script>
+promise_test(t => {
+ const div = addDiv(t, { 'class': 'before' });
+ getComputedStyle(div).paddingLeft;
+ div.classList.add('active');
+
+ const watcher = new EventWatcher(t, div, [ 'transitionend' ]);
+ return watcher.wait_for('transitionend').then(evt => {
+ assert_end_events_equal(evt, 'padding-left', 0.01, '::before');
+ });
+}, 'transition padding-left on ::before');
+
+promise_test(t => {
+ const div = addDiv(t, { 'class': 'after' });
+ getComputedStyle(div).paddingLeft;
+ div.classList.add('active');
+
+ const watcher = new EventWatcher(t, div, [ 'transitionend' ]);
+ return watcher.wait_for('transitionend').then(evt => {
+ assert_end_events_equal(evt, 'padding-left', 0.01, '::after');
+ });
+}, 'transition padding-left on ::after');
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-transitions/events-007.html b/testing/web-platform/tests/css/css-transitions/events-007.html
new file mode 100644
index 0000000000..610df6e85d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/events-007.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Transitions Test: no transitionend event after display:none</title>
+<link rel="author" title="Chris Rebert" href="http://chrisrebert.com">
+<link rel="help" href="http://www.w3.org/TR/css3-transitions/#transition-events">
+<link rel="help" href="https://lists.w3.org/Archives/Public/www-style/2015Apr/0405.html" title="[CSSWG] Minutes Telecon 2015-04-29" data-section-title="AnimationEnd events and display: none">
+<meta name="assert" content="Making an element display:none; while it has a transition in progress should prevent a transitionend event from getting fired.">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="./support/helper.js" type="text/javascript"></script>
+
+</head>
+<body>
+
+<div id="log"></div>
+
+<script>
+async_test(t => {
+ window.addEventListener('load', function () {
+ const div = addDiv(t, { 'style': 'transition: background-color 0.4s;' +
+ 'background-color: red' });
+ getComputedStyle(div).backgroundColor;
+ div.style.backgroundColor = 'blue';
+
+ // Wait until the transition has started before registering the event
+ // listener. That way, if the transition finishes before the
+ // requestAnimationFrame callback is called and the element is made
+ // display:none, we won't report an error if transitionend is dispatched.
+ //
+ // In that case, there will be no indication that the test didn't test
+ // anything. However, that's preferable to having this test fail
+ // intermittently on slower automation hardware and end up being disabled
+ // as a result.
+ requestAnimationFrame(t.step_func(() => {
+ div.addEventListener('transitionend', t.step_func(() => {
+ assert_unreached('transitionend event didn\'t fire');
+ }), false);
+
+ div.style.display = 'none';
+
+ setTimeout(t.done.bind(t), 500);
+ }));
+ }, false);
+}, 'transitionend should not be fired if the element is made display:none during the transition');
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-transitions/historical.html b/testing/web-platform/tests/css/css-transitions/historical.html
new file mode 100644
index 0000000000..e01ed4da9d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/historical.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+
+<title>Historical CSS Transition features must be removed</title>
+<link rel="help" href="http://www.w3.org/TR/css3-transitions-1/#starting">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+function isInterfaceNuked(name) {
+ test(function() {
+ assert_equals(window[name], undefined)
+ }, "Historical CSS features must be removed: " + name)
+}
+var nukedInterfaces = [
+ "WebKitTransitionEvent", // Replaced by unprefixed TransitionEvent
+];
+nukedInterfaces.forEach(isInterfaceNuked);
+</script>
diff --git a/testing/web-platform/tests/css/css-transitions/idlharness-2.html b/testing/web-platform/tests/css/css-transitions/idlharness-2.html
new file mode 100644
index 0000000000..236bf5642b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/idlharness-2.html
@@ -0,0 +1,28 @@
+<!doctype html>
+<title>css-transitions-2 IDL tests</title>
+<link rel="help" href="https://drafts.csswg.org/css-transitions-2/">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/WebIDLParser.js"></script>
+<script src="/resources/idlharness.js"></script>
+<!-- used to provide objects -->
+<style>
+ @starting-style {
+ #id { color: green }
+ }
+</style>
+<script>
+ "use strict";
+
+ idl_test(
+ ['css-transitions-2'],
+ ['web-animations', 'cssom', 'html', 'dom'],
+ idl_array => {
+ idl_array.add_objects({
+ Animation: ['new Animation()'],
+ CSSStartingStyleRule: ['sheet.cssRules[0]'],
+ });
+ self.sheet = document.styleSheets[0];
+ }
+ );
+</script>
diff --git a/testing/web-platform/tests/css/css-transitions/idlharness.html b/testing/web-platform/tests/css/css-transitions/idlharness.html
new file mode 100644
index 0000000000..4cc7ee50eb
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/idlharness.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<title>css-transitions IDL tests</title>
+<link rel="help" href="https://drafts.csswg.org/css-transitions/">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/WebIDLParser.js"></script>
+<script src="/resources/idlharness.js"></script>
+<script>
+ "use strict";
+
+ idl_test(
+ ['css-transitions'],
+ ['cssom', 'html', 'dom'],
+ idl_array => {
+ idl_array.add_objects({
+ TransitionEvent: ['new TransitionEvent("transitionend")'],
+ // These include GlobalEventHandlers
+ Document: ['document'],
+ HTMLElement: ['document'],
+ Window: ['window'],
+ })
+ }
+ );
+</script>
diff --git a/testing/web-platform/tests/css/css-transitions/inert-while-transitioning-to-display-none.html b/testing/web-platform/tests/css/css-transitions/inert-while-transitioning-to-display-none.html
new file mode 100644
index 0000000000..2831c668d6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/inert-while-transitioning-to-display-none.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://github.com/w3c/csswg-drafts/issues/8389">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<dialog>
+ <button>button</button>
+</dialog>
+
+<style>
+dialog.ready {
+ transition: display 500ms;
+}
+</style>
+
+<script>
+promise_test(async () => {
+ const dialog = document.querySelector('dialog');
+ const button = document.querySelector('button');
+
+ dialog.showModal();
+ button.blur(); // Dialog initial focus focused the button
+ dialog.classList.add('ready');
+
+ dialog.close();
+ await new Promise(resolve => requestAnimationFrame(resolve));
+ button.focus();
+
+ assert_not_equals(document.activeElement, button, 'Inert elements should not be focusable.');
+}, 'Elements which are transitioning to display:none should be inert.');
+</script>
diff --git a/testing/web-platform/tests/css/css-transitions/infinite-duration-crash.html b/testing/web-platform/tests/css/css-transitions/infinite-duration-crash.html
new file mode 100644
index 0000000000..dba53d66b7
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/infinite-duration-crash.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<style>
+ * {
+ transition: all ease-out, linear 2733ms background, all calc(2s / 0) steps(706573049);
+ }
+</style>
+<script>
+ document.addEventListener("DOMContentLoaded", () => {
+ const style = document.createElement("style")
+ document.head.appendChild(style)
+ const selection = window.getSelection()
+ style.sheet.insertRule(`* { background-clip: padding-box, padding-box, border-box, content-box; }`, 0)
+ selection.selectAllChildren(style)
+ style.sheet.disabled = true
+ })
+</script>
diff --git a/testing/web-platform/tests/css/css-transitions/inherit-background-color-transition-ref.html b/testing/web-platform/tests/css/css-transitions/inherit-background-color-transition-ref.html
new file mode 100644
index 0000000000..b7a5824836
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/inherit-background-color-transition-ref.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<html>
+ <body style="color: black; background-color: white">
+ <div><div>PASS if black on white</div></div>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/css/css-transitions/inherit-background-color-transition.html b/testing/web-platform/tests/css/css-transitions/inherit-background-color-transition.html
new file mode 100644
index 0000000000..2c0e4aed93
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/inherit-background-color-transition.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<html id="html" class="reftest-wait">
+ <title>Verifies that 'background-color' from a transition inherits explicitly down if requested</title>
+ <link rel="help" href="https://crbug.com/1325340">
+ <link rel="match" href="inherit-background-color-transition-ref.html">
+ <script src="support/helper.js"></script>
+ <style>
+ body { transition: background-color 1s; color: white; background-color: black; }
+ .light { color: black; background-color: white; }
+ </style>
+</head>
+<body id="body">
+ <div style="background-color: inherit">
+ <div style="background-color: inherit">PASS if black on white</div>
+ </div>
+ <script>
+ body.offsetTop;
+
+ async function run() {
+ let transitionEnd = new Promise((resolve) => {
+ body.addEventListener('transitionend', resolve);
+ });
+
+ // Trigger transition:
+ body.classList.toggle('light');
+
+ const transition = body.getAnimations()[0];
+ await transition.ready;
+ await waitForFrame();
+
+ // Expedite transition, but let it finish naturally.
+ transition.currentTime = transition.effect.getTiming().duration - 1;
+ await transitionEnd;
+
+ await waitForFrame();
+ }
+
+ run().then(() => html.classList.toggle('reftest-wait'));
+ </script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-transitions/inherit-height-transition.html b/testing/web-platform/tests/css/css-transitions/inherit-height-transition.html
new file mode 100644
index 0000000000..e411da3396
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/inherit-height-transition.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-transitions/#starting">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+ div { height: inherit; }
+ #outer { height: 50px; }
+ #outer.collapsed {
+ height: 0px;
+ transition: height 0.01s;
+ }
+</style>
+<div id="outer">
+ <div>
+ <div id="inner">You should only see a flash of red.</div>
+ </div>
+</div>
+<script>
+ promise_test(t => {
+ outer.offsetTop;
+ outer.className = "collapsed";
+ return (new Promise((resolve) => outer.addEventListener("transitionend", resolve))).then(() => {
+ assert_equals(getComputedStyle(inner).height, "0px");
+ });
+ }, "Transitioned height, explicitly inherited down two DOM levels, should inherit correctly");
+</script>
diff --git a/testing/web-platform/tests/css/css-transitions/inheritance.html b/testing/web-platform/tests/css/css-transitions/inheritance.html
new file mode 100644
index 0000000000..986436950e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/inheritance.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Inheritance of CSS Transitions properties</title>
+<link rel="help" href="https://drafts.csswg.org/css-transitions/#property-index">
+<meta name="assert" content="Properties inherit or not according to the spec.">
+<meta name="assert" content="Properties have initial values according to the spec.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/inheritance-testcommon.js"></script>
+</head>
+<body>
+<div id="container">
+<div id="target"></div>
+</div>
+<script>
+assert_not_inherited('transition-delay', '0s', '2s');
+assert_not_inherited('transition-duration', '0s', '3s');
+assert_not_inherited('transition-property', 'all', 'opacity');
+assert_not_inherited('transition-timing-function', 'ease', 'linear');
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-transitions/non-rendered-element-001.html b/testing/web-platform/tests/css/css-transitions/non-rendered-element-001.html
new file mode 100644
index 0000000000..10419b9467
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/non-rendered-element-001.html
@@ -0,0 +1,127 @@
+<!doctype html>
+<html>
+<head>
+<meta charset=utf-8>
+<title>CSS Transitions Test: Transitions do not run for an element that is not being rendered</title>
+<link rel="help" title="Starting transitions"
+ href="https://drafts.csswg.org/css-transitions/#starting">
+
+<script src="/resources/testharness.js" type="text/javascript"></script>
+<script src="/resources/testharnessreport.js" type="text/javascript"></script>
+<script src="./support/helper.js" type="text/javascript"></script>
+
+</head>
+<body>
+<div id="log"></div>
+
+<script>
+promise_test(async t => {
+ // Create element that is not rendered
+ const div = addDiv(t, {
+ style:
+ 'transition: background-color 100s;' +
+ 'background-color: red;' +
+ 'display: none',
+ });
+
+ // Attach event listeners
+ div.addEventListener(
+ 'transitionrun',
+ t.step_func(() => {
+ assert_unreached('transitionrun event should not be fired');
+ })
+ );
+
+ // Resolve before-change style
+ getComputedStyle(div).backgroundColor;
+
+ // Set up and resolve after-change style
+ div.style.backgroundColor = 'green';
+ getComputedStyle(div).backgroundColor;
+
+ // There should be no events received for the triggered transition.
+ await waitForFrame();
+ await waitForFrame();
+}, 'Transitions do not run on an element not being rendered');
+
+test(t => {
+ // Create element that is not rendered
+ const div = addDiv(t, {
+ style:
+ 'transition: background-color 100s;' +
+ 'background-color: red;' +
+ 'display: none',
+ });
+
+ // Resolve before-change style
+ getComputedStyle(div).backgroundColor;
+
+ // Make it rendered
+ div.style.display = 'block';
+
+ // Set up and resolve after-change style
+ div.style.backgroundColor = 'green';
+ getComputedStyle(div).backgroundColor;
+
+ // We should have jumped immediately to the after-change style rather than
+ // transitioning to it.
+ assert_equals(
+ getComputedStyle(div).backgroundColor,
+ 'rgb(0, 128, 0)',
+ 'No transition should run'
+ );
+}, 'Transitions do not run for an element newly rendered');
+
+promise_test(async t => {
+ // Create element
+ const div = addDiv(t, {
+ style: 'transition: background-color 100s; background-color: red',
+ });
+
+ // Attach event listeners
+ div.addEventListener('transitionrun', t.step_func(() => {
+ assert_unreached('transitionrun event should not be fired');
+ }));
+
+ // Resolve before-change style
+ getComputedStyle(div).backgroundColor;
+
+ // Set up after-change style
+ div.style.backgroundColor = 'green';
+
+ // But make the element non-rendered
+ div.style.display = 'none';
+
+ // There should be no events received for the triggered transition.
+ await waitForFrame();
+ await waitForFrame();
+}, 'Transitions do not run for an element newly made not rendered');
+
+promise_test(async t => {
+ // Create element
+ const div = addDiv(t, {
+ style: 'transition: background-color 100s; background-color: red',
+ });
+
+ // Attach event listeners
+ const eventWatcher = new EventWatcher(t, div, [
+ 'transitionrun',
+ 'transitioncancel',
+ ]);
+
+ // Trigger transition
+ getComputedStyle(div).backgroundColor;
+ div.style.backgroundColor = 'green';
+ getComputedStyle(div).backgroundColor;
+
+ await eventWatcher.wait_for('transitionrun');
+
+ // Make the element no longer rendered
+ div.style.display = 'none';
+
+ await eventWatcher.wait_for('transitioncancel');
+}, 'Transitions are canceled when an element is no longer rendered');
+</script>
+
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-transitions/non-rendered-element-002.html b/testing/web-platform/tests/css/css-transitions/non-rendered-element-002.html
new file mode 100644
index 0000000000..accf141037
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/non-rendered-element-002.html
@@ -0,0 +1,57 @@
+<!doctype html>
+<html>
+<head>
+<meta charset=utf-8>
+<title>CSS Transitions Test: Transitions do not run for a pseudo-element that is not being rendered</title>
+<link rel="help" title="Starting transitions"
+ href="https://drafts.csswg.org/css-transitions/#starting">
+
+<script src="/resources/testharness.js" type="text/javascript"></script>
+<script src="/resources/testharnessreport.js" type="text/javascript"></script>
+<script src="./support/helper.js" type="text/javascript"></script>
+
+</head>
+<body>
+<div id="log"></div>
+
+<script>
+
+promise_test(async t => {
+ for (const pseudoType of ['before', 'after']) {
+ const style = addStyle(t, {
+ [`.init::${pseudoType}`]: 'content: ""; width: 0px; transition: width 100s;',
+ [`.change::${pseudoType}`]: 'width: 100px;',
+ [`.cancel::${pseudoType}`]: 'content: none',
+ });
+
+ // Create element (and pseudo-element) and attach event listeners
+ const div = addDiv(t);
+ div.classList.add('init');
+
+ const eventWatcher = new EventWatcher(t, div, [
+ 'transitionrun',
+ 'transitioncancel',
+ ]);
+
+ // Trigger transition
+ getComputedStyle(div).width;
+ div.classList.add('change');
+ getComputedStyle(div).width;
+
+ await eventWatcher.wait_for('transitionrun');
+
+ // Make the pseudo-element no longer rendered
+ div.classList.add('cancel');
+
+ await eventWatcher.wait_for('transitioncancel');
+
+ div.remove();
+ style.remove();
+ }
+}, 'Transitions on ::before/::after pseudo-elements are canceled when the'
+ + ' content property is cleared');
+
+</script>
+
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-transitions/non-rendered-element-004.tentative.html b/testing/web-platform/tests/css/css-transitions/non-rendered-element-004.tentative.html
new file mode 100644
index 0000000000..1fe2af1253
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/non-rendered-element-004.tentative.html
@@ -0,0 +1,51 @@
+<!doctype html>
+<html>
+<head>
+<meta charset=utf-8>
+<title>CSS Transitions Test: Transitions do not run for a ::marker-element that is not being rendered</title>
+<link rel="help" title="Starting transitions"
+ href="https://drafts.csswg.org/css-transitions/#starting">
+
+<script src="/resources/testharness.js" type="text/javascript"></script>
+<script src="/resources/testharnessreport.js" type="text/javascript"></script>
+<script src="./support/helper.js" type="text/javascript"></script>
+
+</head>
+<body>
+<div id="log"></div>
+
+<script>
+
+promise_test(async t => {
+ addStyle(t, {
+ '.init::marker': 'content: ""; color: red; transition: color 100s;',
+ '.change::marker': 'color: green',
+ });
+
+ // Create element (and pseudo-element) and attach event listeners
+ const div = addDiv(t, { 'style': 'display: list-item' });
+ div.classList.add('init');
+
+ const eventWatcher = new EventWatcher(t, div, [
+ 'transitionrun',
+ 'transitioncancel',
+ ]);
+
+ // Trigger transition
+ getComputedStyle(div).color;
+ div.classList.add('change');
+ getComputedStyle(div).color;
+
+ await eventWatcher.wait_for('transitionrun');
+
+ // Make the parent element no longer display: list-item so that the pseudo
+ // element no longer renders
+ div.style.display = 'block';
+
+ await eventWatcher.wait_for('transitioncancel');
+}, 'Transitions on ::marker pseudo-elements are canceled when the'
+ + ' parent display type is no longer list-item');
+</script>
+
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-transitions/parsing/transition-behavior.html b/testing/web-platform/tests/css/css-transitions/parsing/transition-behavior.html
new file mode 100644
index 0000000000..6e4729f9db
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/parsing/transition-behavior.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://github.com/w3c/csswg-drafts/issues/8857">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+<div id="target"></div>
+<script>
+test_valid_value('transition-behavior', 'normal');
+test_computed_value('transition-behavior', 'normal');
+
+test_valid_value('transition-behavior', 'allow-discrete');
+test_computed_value('transition-behavior', 'allow-discrete');
+
+test_valid_value('transition', 'allow-discrete display', 'display allow-discrete');
+test_computed_value('transition', 'allow-discrete display', 'display allow-discrete');
+
+test_valid_value('transition', 'allow-discrete display 3s', 'display 3s allow-discrete');
+test_computed_value('transition', 'allow-discrete display 3s', 'display 3s allow-discrete');
+
+test_valid_value('transition', 'allow-discrete display 3s 1s', 'display 3s 1s allow-discrete');
+test_computed_value('transition', 'allow-discrete display 3s 1s', 'display 3s 1s allow-discrete');
+
+test_valid_value('transition', 'allow-discrete display 3s ease-in-out', 'display 3s ease-in-out allow-discrete');
+test_computed_value('transition', 'allow-discrete display 3s ease-in-out', 'display 3s ease-in-out allow-discrete');
+
+test_valid_value('transition', 'allow-discrete display 3s ease-in-out 1s', 'display 3s ease-in-out 1s allow-discrete');
+test_computed_value('transition', 'allow-discrete display 3s ease-in-out 1s', 'display 3s ease-in-out 1s allow-discrete');
+
+test_invalid_value('transition', 'asdf display');
+test_invalid_value('transition', 'display asdf');
+
+// Putting "discrete" anywhere in the shorthand should still work
+test_valid_value('transition', 'display allow-discrete 3s ease-in-out 1s', 'display 3s ease-in-out 1s allow-discrete');
+test_valid_value('transition', 'display 3s allow-discrete ease-in-out 1s', 'display 3s ease-in-out 1s allow-discrete');
+test_valid_value('transition', 'display 3s ease-in-out allow-discrete 1s', 'display 3s ease-in-out 1s allow-discrete');
+test_valid_value('transition', 'display 3s ease-in-out 1s allow-discrete', 'display 3s ease-in-out 1s allow-discrete');
+test_computed_value('transition', 'display allow-discrete 3s ease-in-out 1s', 'display 3s ease-in-out 1s allow-discrete');
+test_computed_value('transition', 'display 3s allow-discrete ease-in-out 1s', 'display 3s ease-in-out 1s allow-discrete');
+test_computed_value('transition', 'display 3s ease-in-out allow-discrete 1s', 'display 3s ease-in-out 1s allow-discrete');
+test_computed_value('transition', 'display 3s ease-in-out 1s allow-discrete', 'display 3s ease-in-out 1s allow-discrete');
+
+// Serialization with multiple shorthands, including different order
+test_valid_value('transition',
+ 'allow-discrete display, normal opacity, color',
+ 'display allow-discrete, opacity, color');
+test_computed_value('transition',
+ 'allow-discrete display, normal opacity, color',
+ 'display allow-discrete, opacity, color');
+test_valid_value('transition',
+ 'normal opacity, color, allow-discrete display',
+ 'opacity, color, display allow-discrete');
+test_computed_value('transition',
+ 'normal opacity, color, allow-discrete display',
+ 'opacity, color, display allow-discrete');
+</script>
diff --git a/testing/web-platform/tests/css/css-transitions/parsing/transition-computed.html b/testing/web-platform/tests/css/css-transitions/parsing/transition-computed.html
new file mode 100644
index 0000000000..ccd7f7e583
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/parsing/transition-computed.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Transitions: getComputedStyle().transition</title>
+<link rel="help" href="https://drafts.csswg.org/css-transitions/#transition-shorthand-property">
+<meta name="assert" content="transition computed value is as specified.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+</head>
+<body>
+<div id="target"></div>
+<script>
+// <single-transition> = [ none | <single-transition-property> ] ||
+// <time> || <easing-function> || <time>
+
+test(() => {
+ assert_equals(getComputedStyle(document.getElementById('target')).transition, "all");
+}, "Default transition value");
+
+test_computed_value("transition", "1s");
+test_computed_value("transition", "cubic-bezier(0, -2, 1, 3)");
+test_computed_value("transition", "1s -3s");
+test_computed_value("transition", "none");
+test_computed_value("transition", "top");
+
+test_computed_value("transition", "1s -3s cubic-bezier(0, -2, 1, 3) top", "top 1s cubic-bezier(0, -2, 1, 3) -3s");
+test_computed_value("transition", "1s -3s, cubic-bezier(0, -2, 1, 3) top", "1s -3s, top cubic-bezier(0, -2, 1, 3)");
+
+test_computed_value("transition", "all, all");
+
+test(() => {
+ const target = document.getElementById('target');
+ target.style.transition = "initial";
+ target.style.transitionDelay = "1s";
+ assert_equals(getComputedStyle(target).transition, "0s 1s");
+}, "Transition with a delay but no duration");
+
+// TODO: Add test with a single timing-function keyword.
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-transitions/parsing/transition-delay-computed.html b/testing/web-platform/tests/css/css-transitions/parsing/transition-delay-computed.html
new file mode 100644
index 0000000000..8e5b0e80da
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/parsing/transition-delay-computed.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Transitions: getComputedStyle().transitionDelay</title>
+<link rel="help" href="https://drafts.csswg.org/css-transitions/#propdef-transition-delay">
+<meta name="assert" content="transition-delay converts to seconds.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+</head>
+<body>
+<div id="target"></div>
+<script>
+test_computed_value("transition-delay", "-500ms, calc(2 * 3s)", "-0.5s, 6s");
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-transitions/parsing/transition-delay-invalid.html b/testing/web-platform/tests/css/css-transitions/parsing/transition-delay-invalid.html
new file mode 100644
index 0000000000..4b7a143286
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/parsing/transition-delay-invalid.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Transitions: parsing transition-delay with invalid values</title>
+<link rel="help" href="https://drafts.csswg.org/css-transitions/#propdef-transition-delay">
+<meta name="assert" content="transition-delay supports only the grammar '<time> #'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_invalid_value("transition-delay", 'infinite');
+test_invalid_value("transition-delay", '0');
+test_invalid_value("transition-delay", '500ms 0.5s');
+
+test_invalid_value("transition-delay", '-3s, initial');
+test_invalid_value("transition-delay", 'initial, -3s');
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-transitions/parsing/transition-delay-valid.html b/testing/web-platform/tests/css/css-transitions/parsing/transition-delay-valid.html
new file mode 100644
index 0000000000..d6b42b9c05
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/parsing/transition-delay-valid.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Transitions: parsing transition-delay with valid values</title>
+<link rel="help" href="https://drafts.csswg.org/css-transitions/#propdef-transition-delay">
+<meta name="assert" content="transition-delay supports the full grammar '<time> #'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_valid_value("transition-delay", '0s');
+test_valid_value("transition-delay", '500ms');
+test_valid_value("transition-delay", '1s, 2s');
+test_valid_value("transition-delay", '-1s, -2s');
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-transitions/parsing/transition-duration-computed.html b/testing/web-platform/tests/css/css-transitions/parsing/transition-duration-computed.html
new file mode 100644
index 0000000000..f82b4e6d2d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/parsing/transition-duration-computed.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Transitions: getComputedStyle().transitionDuration</title>
+<link rel="help" href="https://drafts.csswg.org/css-transitions/#propdef-transition-duration">
+<meta name="assert" content="transition-duration converts to seconds.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+</head>
+<body>
+<div id="target"></div>
+<script>
+test_computed_value("transition-duration", "500ms", "0.5s");
+test_computed_value("transition-duration", "calc(2 * 3s)", "6s");
+test_computed_value("transition-duration", "20s, 10s");
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-transitions/parsing/transition-duration-invalid.html b/testing/web-platform/tests/css/css-transitions/parsing/transition-duration-invalid.html
new file mode 100644
index 0000000000..4474089bbb
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/parsing/transition-duration-invalid.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Transitions: parsing transition-duration with invalid values</title>
+<link rel="help" href="https://drafts.csswg.org/css-transitions/#propdef-transition-duration">
+<meta name="assert" content="transition-duration supports only the grammar '<time> #'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_invalid_value("transition-duration", 'infinite');
+test_invalid_value("transition-duration", '-500ms');
+test_invalid_value("transition-duration", '1s 2s');
+
+test_invalid_value("transition-duration", '1s, initial');
+test_invalid_value("transition-duration", 'initial, 1s');
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-transitions/parsing/transition-duration-valid.html b/testing/web-platform/tests/css/css-transitions/parsing/transition-duration-valid.html
new file mode 100644
index 0000000000..311ca08669
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/parsing/transition-duration-valid.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Transitions: parsing transition-duration with valid values</title>
+<link rel="help" href="https://drafts.csswg.org/css-transitions/#propdef-transition-duration">
+<meta name="assert" content="transition-duration supports the full grammar '<time> #'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_valid_value("transition-duration", '0s');
+test_valid_value("transition-duration", '500ms');
+test_valid_value("transition-duration", '1s, 2s');
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-transitions/parsing/transition-invalid.html b/testing/web-platform/tests/css/css-transitions/parsing/transition-invalid.html
new file mode 100644
index 0000000000..2138ad89b9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/parsing/transition-invalid.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Transitions: parsing transition with invalid values</title>
+<link rel="help" href="https://drafts.csswg.org/css-transitions/#transition-shorthand-property">
+<meta name="assert" content="transition supports only the grammar '<single-transition> #'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+// <single-transition> = [ none | <single-transition-property> ] ||
+// <time> || <easing-function> || <time>
+test_invalid_value("transition", "1s 2s 3s");
+test_invalid_value("transition", "-1s -2s");
+
+test_invalid_value("transition", "steps(1) steps(2)");
+
+test_invalid_value("transition", "none top");
+
+test_invalid_value("transition", "initial 1s");
+
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-transitions/parsing/transition-property-computed.html b/testing/web-platform/tests/css/css-transitions/parsing/transition-property-computed.html
new file mode 100644
index 0000000000..1e8cfeb22d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/parsing/transition-property-computed.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Transitions: getComputedStyle().transitionProperty</title>
+<link rel="help" href="https://drafts.csswg.org/css-transitions/#propdef-transition-property">
+<meta name="assert" content="transition-property keeps unrecognized properties.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+</head>
+<body>
+<div id="target"></div>
+<script>
+test_computed_value("transition-property", "left, top, right, bottom");
+test_computed_value("transition-property", "one, two, three");
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-transitions/parsing/transition-property-invalid.html b/testing/web-platform/tests/css/css-transitions/parsing/transition-property-invalid.html
new file mode 100644
index 0000000000..f71963f52c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/parsing/transition-property-invalid.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Transitions: parsing transition-property with invalid values</title>
+<link rel="help" href="https://drafts.csswg.org/css-transitions/#propdef-transition-property">
+<meta name="assert" content="transition-property supports only the grammar 'none | <single-transition-property> #'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_invalid_value("transition-property", 'one two three');
+test_invalid_value("transition-property", '1, 2, 3');
+test_invalid_value("transition-property", 'none, one');
+
+test_invalid_value("transition-property", 'initial, top');
+test_invalid_value("transition-property", 'top, initial');
+test_invalid_value("transition-property", 'inherit, top');
+test_invalid_value("transition-property", 'top, inherit');
+test_invalid_value("transition-property", 'unset, top');
+test_invalid_value("transition-property", 'top, unset');
+test_invalid_value("transition-property", 'default, top');
+test_invalid_value("transition-property", 'top, default');
+test_invalid_value("transition-property", 'revert, top');
+test_invalid_value("transition-property", 'top, revert');
+test_invalid_value("transition-property", 'revert-layer, top');
+test_invalid_value("transition-property", 'top, revert-layer');
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-transitions/parsing/transition-property-valid.html b/testing/web-platform/tests/css/css-transitions/parsing/transition-property-valid.html
new file mode 100644
index 0000000000..4e3894f5aa
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/parsing/transition-property-valid.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Transitions: parsing transition-property with valid values</title>
+<link rel="help" href="https://drafts.csswg.org/css-transitions/#propdef-transition-property">
+<meta name="assert" content="transition-property supports the full grammar 'none | <single-transition-property> #'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_valid_value("transition-property", 'none');
+test_valid_value("transition-property", 'all');
+test_valid_value("transition-property", 'one');
+test_valid_value("transition-property", 'one-two-three');
+test_valid_value("transition-property", 'one, two, three');
+test_valid_value("transition-property", 'width, all');
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-transitions/parsing/transition-shorthand.html b/testing/web-platform/tests/css/css-transitions/parsing/transition-shorthand.html
new file mode 100644
index 0000000000..fcd14d2a14
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/parsing/transition-shorthand.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Transitions: transition sets longhands</title>
+<link rel="help" href="https://drafts.csswg.org/css-transitions/#transition-shorthand-property">
+<meta name="assert" content="transition supports the full grammar '<single-transition> #'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/shorthand-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_shorthand_value('transition', '1s -3s cubic-bezier(0, -2, 1, 3) top', {
+ 'transition-property': 'top',
+ 'transition-duration': '1s',
+ 'transition-timing-function': 'cubic-bezier(0, -2, 1, 3)',
+ 'transition-delay': '-3s',
+ 'transition-behavior': 'normal'
+});
+
+test_shorthand_value('transition', '1s -3s, cubic-bezier(0, -2, 1, 3) top', {
+ 'transition-property': 'all, top',
+ 'transition-duration': '1s, 0s',
+ 'transition-timing-function': 'ease, cubic-bezier(0, -2, 1, 3)',
+ 'transition-delay': '-3s, 0s',
+ 'transition-behavior': 'normal, normal'
+});
+
+test_shorthand_value('transition', 'cubic-bezier(0, -2, 1, 3) top, 1s -3s', {
+ 'transition-property': 'top, all',
+ 'transition-duration': '0s, 1s',
+ 'transition-timing-function': 'cubic-bezier(0, -2, 1, 3), ease',
+ 'transition-delay': '0s, -3s',
+ 'transition-behavior': 'normal, normal'
+});
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-transitions/parsing/transition-timing-function-computed.html b/testing/web-platform/tests/css/css-transitions/parsing/transition-timing-function-computed.html
new file mode 100644
index 0000000000..cb110549d0
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/parsing/transition-timing-function-computed.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Animations: getComputedStyle().transitionTimingFunction</title>
+<link rel="help" href="https://drafts.csswg.org/css-transitions/#propdef-transition-timing-function">
+<meta name="assert" content="transition-timing-function computed value is a computed <easing-function> list.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+</head>
+<body>
+<div id="target"></div>
+<script>
+test_computed_value("transition-timing-function", "linear");
+
+test_computed_value("transition-timing-function", "ease");
+test_computed_value("transition-timing-function", "ease-in");
+test_computed_value("transition-timing-function", "ease-out");
+test_computed_value("transition-timing-function", "ease-in-out");
+test_computed_value("transition-timing-function", "cubic-bezier(0.1, 0.2, 0.8, 0.9)");
+test_computed_value("transition-timing-function", "cubic-bezier(0, -2, 1, 3)");
+test_computed_value("transition-timing-function", "cubic-bezier(0, 0.7, 1, 1.3)");
+
+test_computed_value("transition-timing-function", "step-start", "steps(1, start)");
+test_computed_value("transition-timing-function", "step-end", "steps(1)");
+test_computed_value("transition-timing-function", "steps(4)");
+test_computed_value("transition-timing-function", "steps(4, start)");
+test_computed_value("transition-timing-function", "steps(2, end)", "steps(2)");
+test_computed_value("transition-timing-function", "steps(2, jump-start)");
+test_computed_value("transition-timing-function", "steps(2, jump-end)", "steps(2)");
+test_computed_value("transition-timing-function", "steps(2, jump-both)");
+test_computed_value("transition-timing-function", "steps(2, jump-none)");
+
+test_computed_value("transition-timing-function", "linear, ease, linear");
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-transitions/parsing/transition-timing-function-invalid.html b/testing/web-platform/tests/css/css-transitions/parsing/transition-timing-function-invalid.html
new file mode 100644
index 0000000000..c69b7e75d3
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/parsing/transition-timing-function-invalid.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Animations: parsing transition-timing-function with invalid values</title>
+<link rel="help" href="https://drafts.csswg.org/css-transitions/#propdef-transition-timing-function">
+<link rel="help" href="https://drafts.csswg.org/css-easing-1/#typedef-timing-function">
+<meta name="assert" content="transition-timing-function supports only the grammar '<timing-function> #'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_invalid_value("transition-timing-function", "auto");
+test_invalid_value("transition-timing-function", "ease-in ease-out");
+
+test_invalid_value("transition-timing-function", "cubic-bezier(foobar)");
+test_invalid_value("transition-timing-function", "cubic-bezier(1, 2, 3)");
+test_invalid_value("transition-timing-function", "cubic-bezier(1, 2, 3, infinite)");
+test_invalid_value("transition-timing-function", "cubic-bezier(1, 2, 3, 4, 5)");
+test_invalid_value("transition-timing-function", "cubic-bezier(-0.1, 0.1, 0.5, 0.9)");
+test_invalid_value("transition-timing-function", "cubic-bezier(0.5, 0.1, 1.1, 0.9)");
+
+test_invalid_value("transition-timing-function", "steps(foobar)");
+test_invalid_value("transition-timing-function", "steps(3.3, end)");
+test_invalid_value("transition-timing-function", "steps(3, top)");
+test_invalid_value("transition-timing-function", "steps(-3, top)");
+test_invalid_value("transition-timing-function", "steps(0, jump-start)");
+test_invalid_value("transition-timing-function", "steps(0, jump-end)");
+test_invalid_value("transition-timing-function", "steps(0, jump-both)");
+test_invalid_value("transition-timing-function", "steps(1, jump-none)");
+
+test_invalid_value("transition-timing-function", "initial, cubic-bezier(0, -2, 1, 3)");
+test_invalid_value("transition-timing-function", "cubic-bezier(0, -2, 1, 3), initial");
+</script>
+</body>
+</html>
diff --git 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
new file mode 100644
index 0000000000..658ef76bbe
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/parsing/transition-timing-function-valid.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Transitions: parsing transition-timing-function with valid values</title>
+<link rel="help" href="https://drafts.csswg.org/css-transitions/#propdef-transition-timing-function">
+<link rel="help" href="https://drafts.csswg.org/css-easing-1/#typedef-timing-function">
+<meta name="assert" content="transition-timing-function supports the full grammar '<timing-function> #'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+test_valid_value("transition-timing-function", "linear");
+test_valid_value("transition-timing-function", "linear(0 0%, 0.5 50%, 1 100%)");
+test_valid_value("transition-timing-function", "linear(0 0%, 10 10%, 10 50%, 25.4 75%, 100 100%)");
+test_valid_value("transition-timing-function", "linear(0 0%, 1 100%)");
+
+test_valid_value("transition-timing-function", "ease");
+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", "step-start", "steps(1, start)");
+test_valid_value("transition-timing-function", "step-end", "steps(1)");
+test_valid_value("transition-timing-function", "steps(4)");
+test_valid_value("transition-timing-function", "steps(4, start)");
+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>
diff --git a/testing/web-platform/tests/css/css-transitions/parsing/transition-valid.html b/testing/web-platform/tests/css/css-transitions/parsing/transition-valid.html
new file mode 100644
index 0000000000..ea4802f65c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/parsing/transition-valid.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Transitions: parsing transition with valid values</title>
+<link rel="help" href="https://drafts.csswg.org/css-transitions/#transition-shorthand-property">
+<meta name="assert" content="transition supports the full grammar '<single-transition> #'.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/parsing-testcommon.js"></script>
+</head>
+<body>
+<script>
+// <single-transition> = [ none | <single-transition-property> ] ||
+// <time> || <easing-function> || <time>
+test_valid_value("transition", "1s");
+test_valid_value("transition", "cubic-bezier(0, -2, 1, 3)");
+test_valid_value("transition", "1s -3s");
+test_valid_value("transition", "none");
+test_valid_value("transition", "top");
+
+test_valid_value("transition", "1s -3s cubic-bezier(0, -2, 1, 3) top", "top 1s cubic-bezier(0, -2, 1, 3) -3s");
+test_valid_value("transition", "1s -3s, cubic-bezier(0, -2, 1, 3) top", "1s -3s, top cubic-bezier(0, -2, 1, 3)");
+
+test_valid_value("transition", "all");
+test_valid_value("transition", "all 1s", "1s");
+
+test_valid_value("transition", "initial", "initial");
+
+// TODO: Add test with a single negative time.
+// TODO: Add test with a single timing-function keyword.
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-transitions/properties-value-001.html b/testing/web-platform/tests/css/css-transitions/properties-value-001.html
new file mode 100644
index 0000000000..54e84be2b0
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/properties-value-001.html
@@ -0,0 +1,133 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>CSS Transitions Test: Intermediate Property Values</title>
+ <meta name="timeout" content="long">
+ <meta name="assert" content="Test checks that value ranges between start and end while transitioning">
+ <link rel="help" href="http://www.w3.org/TR/css3-transitions/#transitions">
+ <link rel="help" href="https://drafts.csswg.org/web-animations-1/#animation-type">
+ <link rel="author" title="Rodney Rehm" href="http://rodneyrehm.de/en/">
+ <meta name="flags" content="dom">
+
+ <script src="/resources/testharness.js" type="text/javascript"></script>
+ <script src="/resources/testharnessreport.js" type="text/javascript"></script>
+
+ <script src="./support/vendorPrefix.js" type="text/javascript"></script>
+ <script src="./support/helper.js" type="text/javascript"></script>
+ <script src="./support/runParallelAsyncHarness.js" type="text/javascript"></script>
+ <script src="./support/generalParallelTest.js" type="text/javascript"></script>
+ <script src="./support/properties.js" type="text/javascript"></script>
+
+ <style type="text/css">
+ #offscreen {
+ position: absolute;
+ top: -100000px;
+ left: -100000px;
+ width: 100000px;
+ height: 100000px;
+ }
+ </style>
+ </head>
+ <body>
+ <!-- required by testharnessreport.js -->
+ <div id="log"></div>
+ <!-- elements used for testing -->
+ <div id="fixture" class="fixture">
+ <div class="container">
+ <div class="transition">Text sample</div>
+ </div>
+ </div>
+ <div id="offscreen"></div>
+
+ <!--
+ SEE ./support/README.md for an abstract explanation of the test procedure
+ http://test.csswg.org/source/contributors/rodneyrehm/submitted/css3-transitions/README.md
+ -->
+
+ <script>
+ // this test takes its time, give it a minute to run
+ var timeout = 60000;
+ setup({timeout: timeout});
+
+ var tests = getPropertyTests();
+ // for testing, limit to a couple of iterations
+ // tests = tests.slice(10, 30);
+ // or filter using one of:
+ // tests = filterPropertyTests(tests, "background-color color(rgba)");
+ // tests = filterPropertyTests(tests, ["background-color color(rgba)", ...]);
+ // tests = filterPropertyTests(tests, /^background-color/);
+
+ // general transition-duration
+ var duration = '2s';
+
+ runParallelAsyncHarness({
+ // array of test data
+ tests: tests,
+ // the number of tests to run in parallel
+ testsPerSlice: 50,
+ // milliseconds to wait before calling teardown and ending test
+ duration: parseFloat(duration) * 1000,
+ // prepare individual test
+ setup: function(data, options) {
+ var styles = {
+ '.fixture': {},
+
+ '.container': data.parentStyle,
+ '.container.to': {},
+ '.container.how': {},
+
+ '.transition': data.from,
+ '.transition.to' : data.to,
+ '.transition.how' : {transition: 'all ' + duration + ' linear 0s'}
+ };
+
+ generalParallelTest.setup(data, options);
+ generalParallelTest.addStyles(data, options, styles);
+ },
+ // cleanup after individual test
+ teardown: generalParallelTest.teardown,
+ // invoked prior to running a slice of tests
+ sliceStart: generalParallelTest.sliceStart,
+ // invoked after running a slice of tests
+ sliceDone: generalParallelTest.sliceDone,
+ // test cases, make them as granular as possible
+ cases: {
+ // test property values while transitioning
+ // values.start kicks off a transition
+ 'values': {
+ // run actual test, assertions can be used here!
+ start: function(test, data, options) {
+ // identify initial and target values
+ generalParallelTest.getStyle(data);
+ // make sure values differ, if they don't, the property could most likely not be parsed
+ assert_not_equals(data.transition.from, data.transition.to, "initial and target values may not match");
+ // kick off the transition
+ generalParallelTest.startTransition(data);
+
+ // make sure we didn't get the target value immediately.
+ // If we did, there wouldn't be a transition!
+ var current = data.transition.computedStyle(data.property);
+ assert_not_equals(current, data.transition.to, "must not be target value after start");
+ },
+ done: function(test, data, options) {
+ // make sure the property's value were neither initial nor target while transitioning
+ test.step(generalParallelTest.assertIntermediateValuesFunc(data, 'transition'));
+ }
+ },
+ // test TransitionEnd events
+ 'events': {
+ done: function(test, data, options) {
+ // make sure there were no events on parent
+ test.step(generalParallelTest.assertExpectedEventsFunc(data, 'container', ""));
+ // make sure we got the event for the tested property only
+ test.step(generalParallelTest.assertExpectedEventsFunc(data, 'transition', addVendorPrefix(data.property) + ":" + duration));
+ }
+ }
+ },
+ // called once all tests are done
+ done: generalParallelTest.done
+ });
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/css/css-transitions/properties-value-002.html b/testing/web-platform/tests/css/css-transitions/properties-value-002.html
new file mode 100644
index 0000000000..ed85b007d2
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/properties-value-002.html
@@ -0,0 +1,135 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>CSS Transitions Test: Intermediate Property Values of missing value types</title>
+ <meta name="assert" content="Test checks that expected value types that haven't been specified are transitionable">
+ <link rel="help" href="http://www.w3.org/TR/css3-transitions/#transitions">
+ <link rel="help" href="https://drafts.csswg.org/web-animations-1/#animation-type">
+ <link rel="author" title="Rodney Rehm" href="http://rodneyrehm.de/en/">
+ <meta name="flags" content="dom">
+
+ <script src="/resources/testharness.js" type="text/javascript"></script>
+ <script src="/resources/testharnessreport.js" type="text/javascript"></script>
+
+ <script src="./support/vendorPrefix.js" type="text/javascript"></script>
+ <script src="./support/helper.js" type="text/javascript"></script>
+ <script src="./support/runParallelAsyncHarness.js" type="text/javascript"></script>
+ <script src="./support/generalParallelTest.js" type="text/javascript"></script>
+ <script src="./support/properties.js" type="text/javascript"></script>
+
+ <style type="text/css">
+ #offscreen {
+ position: absolute;
+ top: -100000px;
+ left: -100000px;
+ width: 100000px;
+ height: 100000px;
+ }
+ </style>
+ </head>
+ <body>
+ <!-- required by testharnessreport.js -->
+ <div id="log"></div>
+ <!-- elements used for testing -->
+ <div id="fixture" class="fixture">
+ <div class="container">
+ <div class="transition">Text sample</div>
+ </div>
+ </div>
+ <div id="offscreen"></div>
+
+ <!--
+ SEE ./support/README.md for an abstract explanation of the test procedure
+ http://test.csswg.org/source/contributors/rodneyrehm/submitted/css3-transitions/README.md
+ -->
+
+ <script>
+ // this suite tests property value types that haven't been specified
+ // (like <percentage> for margin-bottom)
+
+ // this test takes its time, give it a minute to run
+ var timeout = 60000;
+ setup({timeout: timeout});
+
+ var tests = getMissingPropertyTests();
+ // for testing, limit to a couple of iterations
+ // tests = tests.slice(10, 30);
+ // or filter using one of:
+ // tests = filterPropertyTests(tests, "background-color color(rgba)");
+ // tests = filterPropertyTests(tests, ["background-color color(rgba)", ...]);
+ // tests = filterPropertyTests(tests, /^background-color/);
+
+ // general transition-duration
+ var duration = '2s';
+
+ runParallelAsyncHarness({
+ // array of test data
+ tests: tests,
+ // the number of tests to run in parallel
+ testsPerSlice: 50,
+ // milliseconds to wait before calling teardown and ending test
+ duration: parseFloat(duration) * 1000,
+ // prepare individual test
+ setup: function(data, options) {
+ var styles = {
+ '.fixture': {},
+
+ '.container': data.parentStyle,
+ '.container.to': {},
+ '.container.how': {},
+
+ '.transition': data.from,
+ '.transition.to' : data.to,
+ '.transition.how' : {transition: 'all ' + duration + ' linear 0s'}
+ };
+
+ generalParallelTest.setup(data, options);
+ generalParallelTest.addStyles(data, options, styles);
+ },
+ // cleanup after individual test
+ teardown: generalParallelTest.teardown,
+ // invoked prior to running a slice of tests
+ sliceStart: generalParallelTest.sliceStart,
+ // invoked after running a slice of tests
+ sliceDone: generalParallelTest.sliceDone,
+ // test cases, make them as granular as possible
+ cases: {
+ // test property values while transitioning
+ // values.start kicks off a transition
+ 'values': {
+ // run actual test, assertions can be used here!
+ start: function(test, data, options) {
+ // identify initial and target values
+ generalParallelTest.getStyle(data);
+ // make sure values differ, if they don't, the property could most likely not be parsed
+ assert_not_equals(data.transition.from, data.transition.to, "initial and target values may not match");
+ // kick off the transition
+ generalParallelTest.startTransition(data);
+
+ // make sure we didn't get the target value immediately.
+ // If we did, there wouldn't be a transition!
+ var current = data.transition.computedStyle(data.property);
+ assert_not_equals(current, data.transition.to, "must not be target value after start");
+ },
+ done: function(test, data, options) {
+ // make sure the property's value were neither initial nor target while transitioning
+ test.step(generalParallelTest.assertIntermediateValuesFunc(data, 'transition'));
+ }
+ },
+ // test TransitionEnd events
+ 'events': {
+ done: function(test, data, options) {
+ // make sure there were no events on parent
+ test.step(generalParallelTest.assertExpectedEventsFunc(data, 'container', ""));
+ // make sure we got the event for the tested property only
+ test.step(generalParallelTest.assertExpectedEventsFunc(data, 'transition', addVendorPrefix(data.property) + ":" + duration));
+ }
+ }
+ },
+ // called once all tests are done
+ done: generalParallelTest.done
+ });
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/css/css-transitions/properties-value-003.html b/testing/web-platform/tests/css/css-transitions/properties-value-003.html
new file mode 100644
index 0000000000..faf0258a60
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/properties-value-003.html
@@ -0,0 +1,137 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>CSS Transitions Test: Intermediate Property Values of unspecified properties</title>
+ <meta name="timeout" content="long">
+ <meta name="assert" content="Test checks that properties are transitionable that haven't been specified">
+ <link rel="help" href="http://www.w3.org/TR/css3-transitions/#transitions">
+ <link rel="help" href="https://drafts.csswg.org/web-animations-1/#animation-type">
+ <link rel="author" title="Rodney Rehm" href="http://rodneyrehm.de/en/">
+ <meta name="flags" content="dom">
+
+ <script src="/resources/testharness.js" type="text/javascript"></script>
+ <script src="/resources/testharnessreport.js" type="text/javascript"></script>
+
+ <script src="./support/vendorPrefix.js" type="text/javascript"></script>
+ <script src="./support/helper.js" type="text/javascript"></script>
+ <script src="./support/runParallelAsyncHarness.js" type="text/javascript"></script>
+ <script src="./support/generalParallelTest.js" type="text/javascript"></script>
+ <script src="./support/properties.js" type="text/javascript"></script>
+
+ <style type="text/css">
+ #offscreen {
+ position: absolute;
+ top: -100000px;
+ left: -100000px;
+ width: 100000px;
+ height: 100000px;
+ }
+ </style>
+ </head>
+ <body>
+ <!-- required by testharnessreport.js -->
+ <div id="log"></div>
+ <!-- elements used for testing -->
+ <div id="fixture" class="fixture">
+ <div class="container">
+ <div class="transition">Text sample</div>
+ </div>
+ </div>
+ <div id="offscreen"></div>
+
+ <!--
+ SEE ./support/README.md for an abstract explanation of the test procedure
+ http://test.csswg.org/source/contributors/rodneyrehm/submitted/css3-transitions/README.md
+ -->
+
+ <script>
+ // see README.md for an explanation of how this test suite works
+ // this suite tests properties that haven't been specified at all
+ // (like background-image and column-rule-width)
+
+ // this test takes its time, give it a minute to run
+ var timeout = 60000;
+ setup({timeout: timeout});
+
+ var tests = getUnspecifiedPropertyTests();
+ // for testing, limit to a couple of iterations
+ // tests = tests.slice(10, 30);
+ // or filter using one of:
+ // tests = filterPropertyTests(tests, "background-color color(rgba)");
+ // tests = filterPropertyTests(tests, ["background-color color(rgba)", ...]);
+ // tests = filterPropertyTests(tests, /^background-color/);
+
+ // general transition-duration
+ var duration = '2s';
+
+ runParallelAsyncHarness({
+ // array of test data
+ tests: tests,
+ // the number of tests to run in parallel
+ testsPerSlice: 50,
+ // milliseconds to wait before calling teardown and ending test
+ duration: parseFloat(duration) * 1000,
+ // prepare individual test
+ setup: function(data, options) {
+ var styles = {
+ '.fixture': {},
+
+ '.container': data.parentStyle,
+ '.container.to': {},
+ '.container.how': {},
+
+ '.transition': data.from,
+ '.transition.to' : data.to,
+ '.transition.how' : {transition: 'all ' + duration + ' linear 0s'}
+ };
+
+ generalParallelTest.setup(data, options);
+ generalParallelTest.addStyles(data, options, styles);
+ },
+ // cleanup after individual test
+ teardown: generalParallelTest.teardown,
+ // invoked prior to running a slice of tests
+ sliceStart: generalParallelTest.sliceStart,
+ // invoked after running a slice of tests
+ sliceDone: generalParallelTest.sliceDone,
+ // test cases, make them as granular as possible
+ cases: {
+ // test property values while transitioning
+ // values.start kicks off a transition
+ 'values': {
+ // run actual test, assertions can be used here!
+ start: function(test, data, options) {
+ // identify initial and target values
+ generalParallelTest.getStyle(data);
+ // make sure values differ, if they don't, the property could most likely not be parsed
+ assert_not_equals(data.transition.from, data.transition.to, "initial and target values may not match");
+ // kick off the transition
+ generalParallelTest.startTransition(data);
+
+ // make sure we didn't get the target value immediately.
+ // If we did, there wouldn't be a transition!
+ var current = data.transition.computedStyle(data.property);
+ assert_not_equals(current, data.transition.to, "must not be target value after start");
+ },
+ done: function(test, data, options) {
+ // make sure the property's value were neither initial nor target while transitioning
+ test.step(generalParallelTest.assertIntermediateValuesFunc(data, 'transition'));
+ }
+ },
+ // test TransitionEnd events
+ 'events': {
+ done: function(test, data, options) {
+ // make sure there were no events on parent
+ test.step(generalParallelTest.assertExpectedEventsFunc(data, 'container', ""));
+ // make sure we got the event for the tested property only
+ test.step(generalParallelTest.assertExpectedEventsFunc(data, 'transition', addVendorPrefix(data.property) + ":" + duration));
+ }
+ }
+ },
+ // called once all tests are done
+ done: generalParallelTest.done
+ });
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/css/css-transitions/properties-value-implicit-001.html b/testing/web-platform/tests/css/css-transitions/properties-value-implicit-001.html
new file mode 100644
index 0000000000..8500436c52
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/properties-value-implicit-001.html
@@ -0,0 +1,142 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>CSS Transitions Test: font-size-relative properties transition by implicit value change</title>
+ <meta name="timeout" content="long">
+ <meta name="assert" content="Test checks that font-size-relative properties (all em-lengths) run a transition when font-size is changed">
+ <link rel="help" title="2. Transitions" href="http://www.w3.org/TR/css3-transitions/#transitions">
+ <link rel="author" title="Rodney Rehm" href="http://rodneyrehm.de/en/">
+ <meta name="flags" content="dom ">
+
+ <script src="/resources/testharness.js" type="text/javascript"></script>
+ <script src="/resources/testharnessreport.js" type="text/javascript"></script>
+
+ <script src="./support/vendorPrefix.js" type="text/javascript"></script>
+ <script src="./support/helper.js" type="text/javascript"></script>
+ <script src="./support/runParallelAsyncHarness.js" type="text/javascript"></script>
+ <script src="./support/generalParallelTest.js" type="text/javascript"></script>
+ <script src="./support/properties.js" type="text/javascript"></script>
+
+ <style type="text/css">
+ #offscreen {
+ position: absolute;
+ top: -100000px;
+ left: -100000px;
+ width: 100000px;
+ height: 100000px;
+ }
+ </style>
+ </head>
+ <body>
+ <!-- required by testharnessreport.js -->
+ <div id="log"></div>
+ <!-- elements used for testing -->
+ <div id="fixture" class="fixture">
+ <div class="container">
+ <div class="transition">Text sample</div>
+ </div>
+ </div>
+ <div id="offscreen"></div>
+
+ <!--
+ SEE ./support/README.md for an abstract explanation of the test procedure
+ http://test.csswg.org/source/contributors/rodneyrehm/submitted/css3-transitions/README.md
+ -->
+
+ <script>
+ // see README.md for an explanation of how this test suite works
+ // this suite tests properties that haven't been specified at all
+ // (like background-image and column-rule-width)
+
+ // this test takes its time, give it a minute to run
+ var timeout = 60000;
+ setup({timeout: timeout});
+
+ var tests = getFontSizeRelativePropertyTests();
+ // for testing, limit to a couple of iterations
+ // tests = tests.slice(10, 30);
+ // or filter using one of:
+ // tests = filterPropertyTests(tests, "background-color color(rgba)");
+ // tests = filterPropertyTests(tests, ["background-color color(rgba)", ...]);
+ // tests = filterPropertyTests(tests, /^background-color/);
+
+ // general transition-duration
+ var duration = '2s';
+
+ runParallelAsyncHarness({
+ // array of test data
+ tests: tests,
+ // the number of tests to run in parallel
+ testsPerSlice: 50,
+ // milliseconds to wait before calling teardown and ending test
+ duration: parseFloat(duration) * 1000,
+ // prepare individual test
+ setup: function(data, options) {
+ // as we're dealing with em-based lengths, we need to define a font-size
+ data.from['font-size'] = '20px';
+ data.to['font-size'] = '30px';
+ // remove property from target style so it won't transition on its own
+ delete data.to[data.property];
+
+ var styles = {
+ '.fixture': {},
+
+ '.container': data.parentStyle,
+ '.container.to': {},
+ '.container.how': {},
+
+ '.transition': data.from,
+ '.transition.to' : data.to,
+ '.transition.how' : {transition: addVendorPrefix(data.property) + ' ' + duration + ' linear 0s'}
+ };
+
+ generalParallelTest.setup(data, options);
+ generalParallelTest.addStyles(data, options, styles);
+ },
+ // cleanup after individual test
+ teardown: generalParallelTest.teardown,
+ // invoked prior to running a slice of tests
+ sliceStart: generalParallelTest.sliceStart,
+ // invoked after running a slice of tests
+ sliceDone: generalParallelTest.sliceDone,
+ // test cases, make them as granular as possible
+ cases: {
+ // test property values while transitioning
+ // values.start kicks off a transition
+ 'values': {
+ // run actual test, assertions can be used here!
+ start: function(test, data, options) {
+ // identify initial and target values
+ generalParallelTest.getStyle(data);
+ // make sure values differ, if they don't, the property could most likely not be parsed
+ assert_not_equals(data.transition.from, data.transition.to, "initial and target values may not match");
+ // kick off the transition
+ generalParallelTest.startTransition(data);
+
+ // make sure we didn't get the target value immediately.
+ // If we did, there wouldn't be a transition!
+ var current = data.transition.computedStyle(data.property);
+ assert_not_equals(current, data.transition.to, "must not be target value after start");
+ },
+ done: function(test, data, options) {
+ // make sure the property's value were neither initial nor target while transitioning
+ test.step(generalParallelTest.assertIntermediateValuesFunc(data, 'transition'));
+ }
+ },
+ // test TransitionEnd events
+ 'events': {
+ done: function(test, data, options) {
+ // make sure there were no events on parent
+ test.step(generalParallelTest.assertExpectedEventsFunc(data, 'container', ""));
+ // make sure we got the event for the tested property only
+ test.step(generalParallelTest.assertExpectedEventsFunc(data, 'transition', addVendorPrefix(data.property) + ":" + duration));
+ }
+ }
+ },
+ // called once all tests are done
+ done: generalParallelTest.done
+ });
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/css/css-transitions/properties-value-inherit-001.html b/testing/web-platform/tests/css/css-transitions/properties-value-inherit-001.html
new file mode 100644
index 0000000000..abbdecdfae
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/properties-value-inherit-001.html
@@ -0,0 +1,143 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>CSS Transitions Test: transitioning inherited property values</title>
+ <meta name="timeout" content="long">
+ <meta name="assert" content="Test checks that inherited property values that are transitioned on a parent element don't start a transition">
+ <link rel="help" title="3. Starting of transitions" href="http://www.w3.org/TR/css3-transitions/#starting">
+ <link rel="author" title="Rodney Rehm" href="http://rodneyrehm.de/en/">
+ <meta name="flags" content="dom ">
+
+ <script src="/resources/testharness.js" type="text/javascript"></script>
+ <script src="/resources/testharnessreport.js" type="text/javascript"></script>
+
+ <script src="./support/vendorPrefix.js" type="text/javascript"></script>
+ <script src="./support/helper.js" type="text/javascript"></script>
+ <script src="./support/runParallelAsyncHarness.js" type="text/javascript"></script>
+ <script src="./support/generalParallelTest.js" type="text/javascript"></script>
+ <script src="./support/properties.js" type="text/javascript"></script>
+
+ <style type="text/css">
+ #offscreen {
+ position: absolute;
+ top: -100000px;
+ left: -100000px;
+ width: 100000px;
+ height: 100000px;
+ }
+ </style>
+ </head>
+ <body>
+ <!-- required by testharnessreport.js -->
+ <div id="log"></div>
+ <!-- elements used for testing -->
+ <div id="fixture" class="fixture">
+ <div class="container">
+ <div class="transition">Text sample</div>
+ </div>
+ </div>
+ <div id="offscreen"></div>
+
+ <!--
+ SEE ./support/README.md for an abstract explanation of the test procedure
+ http://test.csswg.org/source/contributors/rodneyrehm/submitted/css3-transitions/README.md
+ -->
+
+ <script>
+ // http://www.w3.org/TR/css3-transitions/#starting
+ // Implementations also must not start a transition when the computed value changes because
+ // it is inherited (directly or indirectly) from another element that is transitioning the same property.
+
+ // this test takes its time, give it a minute to run
+ var timeout = 60000;
+ setup({timeout: timeout});
+
+ var tests = getPropertyTests();
+ // for testing, limit to a couple of iterations
+ // tests = tests.slice(10, 30);
+ // or filter using one of:
+ // tests = filterPropertyTests(tests, "background-color color(rgba)");
+ // tests = filterPropertyTests(tests, ["background-color color(rgba)", ...]);
+ // tests = filterPropertyTests(tests, /^background-color/);
+
+ // general transition-duration
+ var duration = '2s';
+
+ runParallelAsyncHarness({
+ // array of test data
+ tests: tests,
+ // the number of tests to run in parallel
+ testsPerSlice: 50,
+ // milliseconds to wait before calling teardown and ending test
+ duration: parseFloat(duration) * 1000,
+ // prepare individual test
+ setup: function(data, options) {
+ // clone and overwrite initial styles to be
+ // applied to #transition
+ var inherited = extend({}, data.from);
+ inherited[data.property] = 'inherit';
+
+ var styles = {
+ // as we're testing inheritance, #fixture is our new parent
+ '.fixture': data.parentStyle,
+ // all styles including transition apply to to #container so they
+ // can inherit down to #transition
+ '.container': extend({}, data.parentStyle, data.from),
+ '.container.to': data.to,
+ '.container.how': {transition: addVendorPrefix(data.property) + ' ' + duration + ' linear 0s'},
+ // #transition only inherits and listens for transition events
+ '.transition': inherited,
+ '.transition.to' : {},
+ '.transition.how' : {transition: addVendorPrefix(data.property) + ' ' + duration + ' linear 0s'}
+ };
+
+ generalParallelTest.setup(data, options);
+ generalParallelTest.addStyles(data, options, styles);
+ },
+ // cleanup after individual test
+ teardown: generalParallelTest.teardown,
+ // invoked prior to running a slice of tests
+ sliceStart: generalParallelTest.sliceStart,
+ // invoked after running a slice of tests
+ sliceDone: generalParallelTest.sliceDone,
+ // test cases, make them as granular as possible
+ cases: {
+ // test property values while transitioning
+ // values.start kicks off a transition
+ 'values': {
+ // run actual test, assertions can be used here!
+ start: function(test, data, options) {
+ // identify initial and target values
+ generalParallelTest.getStyle(data);
+ // make sure values differ, if they don't, the property could most likely not be parsed
+ assert_not_equals(data.transition.from, data.transition.to, "initial and target values may not match");
+ // kick off the transition
+ generalParallelTest.startTransition(data);
+
+ // make sure we didn't get the target value immediately.
+ // If we did, there wouldn't be a transition!
+ var current = data.transition.computedStyle(data.property);
+ assert_not_equals(current, data.transition.to, "must not be target value after start");
+ },
+ done: function(test, data, options) {
+ // make sure the property's value were neither initial nor target while transitioning
+ test.step(generalParallelTest.assertIntermediateValuesFunc(data, 'transition'));
+ }
+ },
+ // test TransitionEnd events
+ 'events': {
+ done: function(test, data, options) {
+ // make sure there were no events on parent
+ test.step(generalParallelTest.assertExpectedEventsFunc(data, 'container', addVendorPrefix(data.property) + ":" + duration));
+ // make sure we got the event for the tested property only
+ test.step(generalParallelTest.assertExpectedEventsFunc(data, 'transition', ""));
+ }
+ }
+ },
+ // called once all tests are done
+ done: generalParallelTest.done
+ });
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/css/css-transitions/properties-value-inherit-002.html b/testing/web-platform/tests/css/css-transitions/properties-value-inherit-002.html
new file mode 100644
index 0000000000..9556cf7e23
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/properties-value-inherit-002.html
@@ -0,0 +1,144 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>CSS Transitions Test: transitioning inherited property values</title>
+ <meta name="timeout" content="long">
+ <meta name="assert" content="Test checks that inherited property values that are not transitioned on a parent element start a transition">
+ <link rel="help" title="3. Starting of transitions" href="http://www.w3.org/TR/css3-transitions/#starting">
+ <link rel="author" title="Rodney Rehm" href="http://rodneyrehm.de/en/">
+ <meta name="flags" content="dom ">
+
+ <script src="/resources/testharness.js" type="text/javascript"></script>
+ <script src="/resources/testharnessreport.js" type="text/javascript"></script>
+
+ <script src="./support/vendorPrefix.js" type="text/javascript"></script>
+ <script src="./support/helper.js" type="text/javascript"></script>
+ <script src="./support/runParallelAsyncHarness.js" type="text/javascript"></script>
+ <script src="./support/generalParallelTest.js" type="text/javascript"></script>
+ <script src="./support/properties.js" type="text/javascript"></script>
+
+ <style type="text/css">
+ #offscreen {
+ position: absolute;
+ top: -100000px;
+ left: -100000px;
+ width: 100000px;
+ height: 100000px;
+ }
+ </style>
+ </head>
+ <body>
+ <!-- required by testharnessreport.js -->
+ <div id="log"></div>
+ <!-- elements used for testing -->
+ <div id="fixture" class="fixture">
+ <div class="container">
+ <div class="transition">Text sample</div>
+ </div>
+ </div>
+ <div id="offscreen"></div>
+
+ <!--
+ SEE ./support/README.md for an abstract explanation of the test procedure
+ http://test.csswg.org/source/contributors/rodneyrehm/submitted/css3-transitions/README.md
+ -->
+
+ <script>
+ // http://www.w3.org/TR/css3-transitions/#starting
+ // Implementations also must not start a transition when the computed value changes because
+ // it is inherited (directly or indirectly) from another element that is transitioning the same property.
+ // Note: Parent element doesn't transition, so above quote doesn't apply!
+
+ // this test takes its time, give it a minute to run
+ var timeout = 60000;
+ setup({timeout: timeout});
+
+ var tests = getPropertyTests();
+ // for testing, limit to a couple of iterations
+ // tests = tests.slice(10, 30);
+ // or filter using one of:
+ // tests = filterPropertyTests(tests, "background-color color(rgba)");
+ // tests = filterPropertyTests(tests, ["background-color color(rgba)", ...]);
+ // tests = filterPropertyTests(tests, /^background-color/);
+
+ // general transition-duration
+ var duration = '2s';
+
+ runParallelAsyncHarness({
+ // array of test data
+ tests: tests,
+ // the number of tests to run in parallel
+ testsPerSlice: 50,
+ // milliseconds to wait before calling teardown and ending test
+ duration: parseFloat(duration) * 1000,
+ // prepare individual test
+ setup: function(data, options) {
+ // clone and overwrite initial styles to be
+ // applied to #transition
+ var inherited = extend({}, data.from);
+ inherited[data.property] = 'inherit';
+
+ var styles = {
+ // as we're testing inheritance, #fixture is our new parent
+ '.fixture': data.parentStyle,
+ // all styles including transition apply to to #container so they
+ // can inherit down to #transition
+ '.container': extend({}, data.parentStyle, data.from),
+ '.container.to': data.to,
+ '.container.how': {},
+ // #transition only inherits and listens for transition events
+ '.transition': inherited,
+ '.transition.to' : {},
+ '.transition.how' : {transition: addVendorPrefix(data.property) + ' ' + duration + ' linear 0s'}
+ };
+
+ generalParallelTest.setup(data, options);
+ generalParallelTest.addStyles(data, options, styles);
+ },
+ // cleanup after individual test
+ teardown: generalParallelTest.teardown,
+ // invoked prior to running a slice of tests
+ sliceStart: generalParallelTest.sliceStart,
+ // invoked after running a slice of tests
+ sliceDone: generalParallelTest.sliceDone,
+ // test cases, make them as granular as possible
+ cases: {
+ // test property values while transitioning
+ // values.start kicks off a transition
+ 'values': {
+ // run actual test, assertions can be used here!
+ start: function(test, data, options) {
+ // identify initial and target values
+ generalParallelTest.getStyle(data);
+ // make sure values differ, if they don't, the property could most likely not be parsed
+ assert_not_equals(data.transition.from, data.transition.to, "initial and target values may not match");
+ // kick off the transition
+ generalParallelTest.startTransition(data);
+
+ // make sure we didn't get the target value immediately.
+ // If we did, there wouldn't be a transition!
+ var current = data.transition.computedStyle(data.property);
+ assert_not_equals(current, data.transition.to, "must not be target value after start");
+ },
+ done: function(test, data, options) {
+ // make sure the property's value were neither initial nor target while transitioning
+ test.step(generalParallelTest.assertIntermediateValuesFunc(data, 'transition'));
+ }
+ },
+ // test TransitionEnd events
+ 'events': {
+ done: function(test, data, options) {
+ // make sure there were no events on parent
+ test.step(generalParallelTest.assertExpectedEventsFunc(data, 'container', ""));
+ // make sure we got the event for the tested property only
+ test.step(generalParallelTest.assertExpectedEventsFunc(data, 'transition', addVendorPrefix(data.property) + ":" + duration));
+ }
+ }
+ },
+ // called once all tests are done
+ done: generalParallelTest.done
+ });
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/css/css-transitions/properties-value-inherit-003.html b/testing/web-platform/tests/css/css-transitions/properties-value-inherit-003.html
new file mode 100644
index 0000000000..13a1613213
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/properties-value-inherit-003.html
@@ -0,0 +1,143 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>CSS Transitions Test: transitioning implicitly inherited property values</title>
+ <meta name="assert" content="Test checks that implicitly inherited property values that are transitioned on a parent element don't start a transition">
+ <link rel="help" title="3. Starting of transitions" href="http://www.w3.org/TR/css3-transitions/#starting">
+ <link rel="author" title="Rodney Rehm" href="http://rodneyrehm.de/en/">
+ <meta name="flags" content="dom ">
+
+ <script src="/resources/testharness.js" type="text/javascript"></script>
+ <script src="/resources/testharnessreport.js" type="text/javascript"></script>
+
+ <script src="./support/vendorPrefix.js" type="text/javascript"></script>
+ <script src="./support/helper.js" type="text/javascript"></script>
+ <script src="./support/runParallelAsyncHarness.js" type="text/javascript"></script>
+ <script src="./support/generalParallelTest.js" type="text/javascript"></script>
+ <script src="./support/properties.js" type="text/javascript"></script>
+
+ <style type="text/css">
+ #offscreen {
+ position: absolute;
+ top: -100000px;
+ left: -100000px;
+ width: 100000px;
+ height: 100000px;
+ }
+ </style>
+ </head>
+ <body>
+ <!-- required by testharnessreport.js -->
+ <div id="log"></div>
+ <!-- elements used for testing -->
+ <div id="fixture" class="fixture">
+ <div class="container">
+ <div class="transition">Text sample</div>
+ </div>
+ </div>
+ <div id="offscreen"></div>
+
+ <!--
+ SEE ./support/README.md for an abstract explanation of the test procedure
+ http://test.csswg.org/source/contributors/rodneyrehm/submitted/css3-transitions/README.md
+ -->
+
+ <script>
+ // http://www.w3.org/TR/css3-transitions/#starting
+ // Implementations also must not start a transition when the computed value changes because
+ // it is inherited (directly or indirectly) from another element that is transitioning the same property.
+ // Note: "indirectly" could mean "font-size" on parent, "em-based" on element
+
+ // this test takes its time, give it a minute to run
+ var timeout = 60000;
+ setup({timeout: timeout});
+
+ var tests = getFontSizeRelativePropertyTests();
+ // for testing, limit to a couple of iterations
+ // tests = tests.slice(10, 30);
+ // or filter using one of:
+ // tests = filterPropertyTests(tests, "background-color color(rgba)");
+ // tests = filterPropertyTests(tests, ["background-color color(rgba)", ...]);
+ // tests = filterPropertyTests(tests, /^background-color/);
+
+ // general transition-duration
+ var duration = '2s';
+
+ runParallelAsyncHarness({
+ // array of test data
+ tests: tests,
+ // the number of tests to run in parallel
+ testsPerSlice: 50,
+ // milliseconds to wait before calling teardown and ending test
+ duration: parseFloat(duration) * 1000,
+ // prepare individual test
+ setup: function(data, options) {
+ // have parent transition the font-size only
+ var from = extend({}, data.from, {'font-size': '20px'});
+ delete from[data.property];
+
+ var styles = {
+ // as we're testing inheritance, #fixture is our new parent
+ '.fixture': data.parentStyle,
+
+ '.container': from,
+ '.container.to': {'font-size': '30px'},
+ // transition font-size on parent
+ '.container.how': {transition: 'font-size ' + duration + ' linear 0s'},
+
+ '.transition': data.from,
+ '.transition.to' : {},
+ // transition font-size dependent property on child
+ '.transition.how' : {transition: addVendorPrefix(data.property) + ' ' + duration + ' linear 0s'}
+ };
+
+ generalParallelTest.setup(data, options);
+ generalParallelTest.addStyles(data, options, styles);
+ },
+ // cleanup after individual test
+ teardown: generalParallelTest.teardown,
+ // invoked prior to running a slice of tests
+ sliceStart: generalParallelTest.sliceStart,
+ // invoked after running a slice of tests
+ sliceDone: generalParallelTest.sliceDone,
+ // test cases, make them as granular as possible
+ cases: {
+ // test property values while transitioning
+ // values.start kicks off a transition
+ 'values': {
+ // run actual test, assertions can be used here!
+ start: function(test, data, options) {
+ // identify initial and target values
+ generalParallelTest.getStyle(data);
+ // make sure values differ, if they don't, the property could most likely not be parsed
+ assert_not_equals(data.transition.from, data.transition.to, "initial and target values may not match");
+ // kick off the transition
+ generalParallelTest.startTransition(data);
+
+ // make sure we didn't get the target value immediately.
+ // If we did, there wouldn't be a transition!
+ var current = data.transition.computedStyle(data.property);
+ assert_not_equals(current, data.transition.to, "must not be target value after start");
+ },
+ done: function(test, data, options) {
+ // make sure the property's value were neither initial nor target while transitioning
+ test.step(generalParallelTest.assertIntermediateValuesFunc(data, 'transition'));
+ }
+ },
+ // test TransitionEnd events
+ 'events': {
+ done: function(test, data, options) {
+ // make sure there were no events on parent
+ test.step(generalParallelTest.assertExpectedEventsFunc(data, 'container', "font-size:" + duration));
+ // make sure we got the event for the tested property only
+ test.step(generalParallelTest.assertExpectedEventsFunc(data, 'transition', ""));
+ }
+ }
+ },
+ // called once all tests are done
+ done: generalParallelTest.done
+ });
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/css/css-transitions/pseudo-elements-001.html b/testing/web-platform/tests/css/css-transitions/pseudo-elements-001.html
new file mode 100644
index 0000000000..146c533e23
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/pseudo-elements-001.html
@@ -0,0 +1,148 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>CSS Transitions Test: Transitioning Pseudo Elements</title>
+ <meta name="assert" content="Test checks that transitions are run on pseudo elements">
+ <link rel="help" title="2.1. The 'transition-property' Property" href="http://www.w3.org/TR/css3-transitions/#transition-property-property">
+ <link rel="help" title="CSS21 - 12.1 The :before and :after pseudo-elements" href="http://www.w3.org/TR/CSS21/generate.html#before-after-content">
+ <link rel="help" title="CSS3 Generated and Replaced Content Module" href="http://www.w3.org/TR/css3-content/">
+ <link rel="author" title="Rodney Rehm" href="http://rodneyrehm.de/en/">
+ <meta name="flags" content="dom">
+
+ <script src="/resources/testharness.js" type="text/javascript"></script>
+ <script src="/resources/testharnessreport.js" type="text/javascript"></script>
+
+ <script src="./support/vendorPrefix.js" type="text/javascript"></script>
+ <script src="./support/helper.js" type="text/javascript"></script>
+ <script src="./support/runParallelAsyncHarness.js" type="text/javascript"></script>
+ <script src="./support/generalParallelTest.js" type="text/javascript"></script>
+ <script src="./support/properties.js" type="text/javascript"></script>
+
+ <style type="text/css">
+ #offscreen {
+ position: absolute;
+ top: -100000px;
+ left: -100000px;
+ width: 100000px;
+ height: 100000px;
+ }
+ </style>
+ </head>
+ <body>
+ <!-- required by testharnessreport.js -->
+ <div id="log"></div>
+ <!-- elements used for testing -->
+ <div id="fixture" class="fixture">
+ <div class="container">
+ <div class="transition">Text sample</div>
+ </div>
+ </div>
+ <div id="offscreen"></div>
+
+ <!--
+ SEE ./support/README.md for an abstract explanation of the test procedure
+ http://test.csswg.org/source/contributors/rodneyrehm/submitted/css3-transitions/README.md
+ -->
+
+ <script>
+
+ // this test takes its time, give it a minute to run
+ var timeout = 60000;
+ setup({timeout: timeout});
+
+ var tests = [
+ {
+ name: "transition padding-left on :before",
+ pseudo: 'before',
+ property: 'padding-left',
+ flags: {},
+ from: {'padding-left': '1px', 'content': '""'},
+ to: {'padding-left': '10px'}
+ }, {
+ name: "transition padding-left on :after",
+ pseudo: 'after',
+ property: 'padding-left',
+ flags: {},
+ from: {'padding-left': '1px', 'content': '""'},
+ to: {'padding-left': '10px'}
+ }, {
+ name: "transition padding-left on :before, changing content",
+ pseudo: 'before',
+ property: 'padding-left',
+ flags: {},
+ from: {'padding-left': '1px', 'content': '"1"'},
+ to: {'padding-left': '10px', 'content': '"2"'}
+ }, {
+ name: "transition padding-left on :after, changing content",
+ pseudo: 'after',
+ property: 'padding-left',
+ flags: {},
+ from: {'padding-left': '1px', 'content': '"1"'},
+ to: {'padding-left': '10px', 'content': '"2"'}
+ }
+ ];
+
+ // general transition-duration
+ var duration = '2s';
+
+ runParallelAsyncHarness({
+ // array of test data
+ tests: tests,
+ // the number of tests to run in parallel
+ testsPerSlice: 50,
+ // milliseconds to wait before calling teardown and ending test
+ duration: parseFloat(duration) * 1000,
+ // prepare individual test
+ setup: function(data, options) {
+ generalParallelTest.setup(data, options);
+
+ var styles = {};
+ styles['.fixture'] = {};
+ styles['.container'] = data.parentStyle;
+ styles['.container.to'] = {};
+ styles['.container.how'] = {};
+ styles['.transition'] = {};
+ styles['.transition:' + data.pseudo.name] = data.from;
+ styles['.transition.how:' + data.pseudo.name] = {transition: 'all ' + duration + ' linear 0s'};
+ styles['.transition.to:' + data.pseudo.name] = data.to;
+
+ generalParallelTest.addStyles(data, options, styles);
+ },
+ // cleanup after individual test
+ teardown: generalParallelTest.teardown,
+ // invoked prior to running a slice of tests
+ sliceStart: generalParallelTest.sliceStart,
+ // invoked after running a slice of tests
+ sliceDone: generalParallelTest.sliceDone,
+ // test cases, make them as granular as possible
+ cases: {
+ // test property values while transitioning
+ // values.start kicks off a transition
+ 'values': {
+ // run actual test, assertions can be used here!
+ start: function(test, data, options) {
+ // identify initial and target values
+ generalParallelTest.getStyle(data);
+ // make sure values differ, if they don't, the property could most likely not be parsed
+ assert_not_equals(data.pseudo.from, data.pseudo.to, "initial and target values may not match");
+ // kick off the transition
+ generalParallelTest.startTransition(data);
+
+ // make sure we didn't get the target value immediately.
+ // If we did, there wouldn't be a transition!
+ var current = data.pseudo.computedStyle(data.property);
+ assert_not_equals(current, data.pseudo.to, "must not be target value after start");
+ },
+ done: function(test, data, options) {
+ // make sure the property's value were neither initial nor target while transitioning
+ test.step(generalParallelTest.assertIntermediateValuesFunc(data, 'pseudo'));
+ }
+ }
+ },
+ // called once all tests are done
+ done: generalParallelTest.done
+ });
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/css/css-transitions/pseudo-elements-002.html b/testing/web-platform/tests/css/css-transitions/pseudo-elements-002.html
new file mode 100644
index 0000000000..f84d64a794
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/pseudo-elements-002.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<title>CSS Transitions Test: Transition pseudo element with ancestor display change</title>
+<link rel="author" title="Rune Lillesveen" href="mailto:futhark@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css-transitions/#starting">
+<link rel="help" href="https://drafts.csswg.org/css-transitions/#transition-property-property">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+ #inner::before {
+ content: "This text should transition from red to green.";
+ height: 100px;
+ transition: height steps(2, start) 1s;
+ }
+ .flex #inner::before {
+ height: 300px;
+ }
+ .flex { display: flex }
+</style>
+<div id="outer">
+ <div id="inner"></div>
+</div>
+<script>
+ test(() => {
+ assert_equals(getComputedStyle(inner, "::before").height, "100px");
+ outer.className = "flex";
+ assert_equals(getComputedStyle(inner, "::before").height, "200px");
+ }, "Check that transitions run on a pseudo element whose ancestor changes display type.");
+</script>
diff --git a/testing/web-platform/tests/css/css-transitions/reference/transition-test-ref.html b/testing/web-platform/tests/css/css-transitions/reference/transition-test-ref.html
new file mode 100644
index 0000000000..d9d91ec9da
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/reference/transition-test-ref.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>CSS Transition Reference File</title>
+ <link rel="author" title="Oleg Janeiko" href="mailto:oleg@the-incredible.me">
+ <style type="text/css">
+ .container {
+ background-color: red;
+ height: 200px;
+ width: 200px;
+ }
+ .box {
+ width: 100px;
+ height: 100px;
+ background-color: green;
+
+ transition-property: width;
+ transition-duration: 0;
+ }
+ .box.transition {
+ width: 200px;
+ height: 200px;
+ }
+ </style>
+ <script type="text/javascript" charset="utf-8">
+ function ready(){
+ var box = document.querySelector('.box');
+ box.className = 'box transition';
+ }
+ </script>
+</head>
+<body onload="ready();">
+ <div>
+ <p>You should not see a red background during the transition. Note: if the test passes transition is instant.</p>
+ </div>
+ <div class="container">
+ <div class="box"></div>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-transitions/render-blocking/no-transition-from-ua-to-blocking-stylesheet-ref.html b/testing/web-platform/tests/css/css-transitions/render-blocking/no-transition-from-ua-to-blocking-stylesheet-ref.html
new file mode 100644
index 0000000000..93b4ae982e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/render-blocking/no-transition-from-ua-to-blocking-stylesheet-ref.html
@@ -0,0 +1,3 @@
+<!DOCTYPE html>
+<title>CSS Transitions Test: Reference</title>
+<div style="color:green">This text should be green on load.</div>
diff --git a/testing/web-platform/tests/css/css-transitions/render-blocking/no-transition-from-ua-to-blocking-stylesheet.html b/testing/web-platform/tests/css/css-transitions/render-blocking/no-transition-from-ua-to-blocking-stylesheet.html
new file mode 100644
index 0000000000..d59118c66f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/render-blocking/no-transition-from-ua-to-blocking-stylesheet.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<title>CSS Transitions Test: No color transition from initial to blocking stylesheet value</title>
+<link rel="help" href="https://drafts.csswg.org/css-transitions/#style-change-event">
+<link rel="match" href="no-transition-from-ua-to-blocking-stylesheet-ref.html">
+<link rel="stylesheet" href="../support/a-green-transition.css">
+<div class="a">This text should be green on load.</div>
diff --git a/testing/web-platform/tests/css/css-transitions/retargetted-transition-with-box-sizing.html b/testing/web-platform/tests/css/css-transitions/retargetted-transition-with-box-sizing.html
new file mode 100644
index 0000000000..ef5b116cb9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/retargetted-transition-with-box-sizing.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<link rel=help href="https://bugs.chromium.org/p/chromium/issues/detail?id=571437">
+<link rel=help href="https://drafts.csswg.org/css-transforms-2/#interpolation-of-transform-functions">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+#target {
+ width: 100px;
+ height: 200px;
+ transition-properties: transform;
+ transition-duration: 1s;
+ transition-delay: -0.5s;
+ transition-timing-function: linear;
+}
+</style>
+<div id="target"></div>
+<script>
+test(() => {
+ target.style.transform = 'translate(50%, 50%)';
+ assert_equals(getComputedStyle(target).transform, 'matrix(1, 0, 0, 1, 50, 100)');
+ target.style.transform = 'translate3D(50%, 50%, 100px)';
+ assert_equals(getComputedStyle(target).transform, 'matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 50, 100, 50, 1)');
+}, 'Retargeting transitions on box size relative transitions should work.');
+</script>
diff --git a/testing/web-platform/tests/css/css-transitions/root-color-transition-ref.html b/testing/web-platform/tests/css/css-transitions/root-color-transition-ref.html
new file mode 100644
index 0000000000..c9cf126296
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/root-color-transition-ref.html
@@ -0,0 +1,4 @@
+<!DOCTYPE html>
+<html>
+ <h1 style="color:green">PASS if green</h1>
+</html>
diff --git a/testing/web-platform/tests/css/css-transitions/root-color-transition.html b/testing/web-platform/tests/css/css-transitions/root-color-transition.html
new file mode 100644
index 0000000000..c9f2ca4ba7
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/root-color-transition.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<html id=html class="reftest-wait">
+ <title>Verifies that 'color' stays the color it's transitioned to on :root</title>
+ <link rel="help" href="https://crbug.com/1087188">
+ <link rel="match" href="root-color-transition-ref.html">
+ <script src="support/helper.js"></script>
+ <h1 id=h1>PASS if green</h1>
+ <style>
+ html {
+ color: red;
+ transition: color 1s linear;
+ }
+ html.green {
+ color: green;
+ }
+ </style>
+ <script>
+ getComputedStyle(h1).color;
+
+ async function run() {
+ let transitionEnd = new Promise((resolve) => {
+ html.addEventListener('transitionend', resolve);
+ });
+ // Trigger transition:
+ html.classList.toggle('green');
+
+ const transition = html.getAnimations()[0];
+ await transition.ready;
+ await waitForFrame();
+
+ // Expedite transition, but let it finish naturally.
+ transition.currentTime = transition.effect.getTiming().duration - 1;
+ await transitionEnd;
+
+ await waitForFrame();
+ }
+
+ run().then(() => html.classList.toggle('reftest-wait'));
+ </script>
+</html>
diff --git a/testing/web-platform/tests/css/css-transitions/starting-of-transitions-001.html b/testing/web-platform/tests/css/css-transitions/starting-of-transitions-001.html
new file mode 100644
index 0000000000..f80d813436
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/starting-of-transitions-001.html
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Transitions Test: behavior when transition-property changes while transitioning</title>
+<meta name="assert" content="Checks a change to the transition-duration
+property does not affect an in-flight transition">
+<link rel="help" title="3. Starting of transitions" href="https://drafts.csswg.org/css-transitions/#starting">
+
+<script src="/resources/testharness.js" type="text/javascript"></script>
+<script src="/resources/testharnessreport.js" type="text/javascript"></script>
+<script src="./support/helper.js" type="text/javascript"></script>
+
+</head>
+<body>
+<div id="log"></div>
+<script>
+test(t => {
+ // Start a 100s transition 50% of the way through
+ const div = addDiv(t, {
+ style: 'transition: height 100s -50s linear; height: 0px',
+ });
+ getComputedStyle(div).height;
+ div.style.height = '100px';
+ assert_equals(
+ getComputedStyle(div).height,
+ '50px',
+ 'Transition should be initially 50% complete'
+ );
+
+ // Change the transition-property and flush the style change
+ div.style.transitionProperty = 'width';
+ getComputedStyle(div).transitionProperty;
+
+ // The transition on the height property should have been canceled
+ assert_equals(
+ getComputedStyle(div).height,
+ '100px',
+ 'Transition should have been canceled'
+ );
+}, 'changes to transition-property should cancel in-flight transitions');
+</script>
+
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-transitions/starting-style-cascade.html b/testing/web-platform/tests/css/css-transitions/starting-style-cascade.html
new file mode 100644
index 0000000000..cef3e88b65
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/starting-style-cascade.html
@@ -0,0 +1,101 @@
+<!DOCTYPE html>
+<title>CSS Transitions Test: Cascading @starting-style</title>
+<link rel="help" href="https://drafts.csswg.org/css-transitions-2/#defining-before-change-style-the-starting-style-rule">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/css-transitions/support/helper.js"></script>
+<style>
+ .color-transition {
+ transition: color 100s steps(2, start);
+ }
+
+ @starting-style {
+ #t1 { color: red; }
+ }
+ #t1 { color: green; }
+
+ @starting-style {
+ div#t2 { color: lime; }
+ }
+ #t2 { color: green; }
+
+ #t3 { color: green; }
+ @starting-style {
+ #t3 { color: red; }
+ }
+ #t3 > div { color: green; }
+
+ #t4 { color: green; }
+ #t4[hidden] { color: red; }
+ #t4 > div { color: lime; }
+ @starting-style {
+ #t4 > div { color: inherit; }
+ }
+
+ #t5 { color: green; }
+ @starting-style {
+ #t5 { color: black; }
+ }
+ #t5 > div { color: lime; }
+ @starting-style {
+ #t5 > div { color: inherit; }
+ }
+</style>
+<div id="t1" hidden class="color-transition"></div>
+<div id="t2" hidden class="color-transition"></div>
+<div id="t3" hidden>
+ <div class="color-transition"></div>
+</div>
+<div id="t4" hidden>
+ <div class="color-transition"></div>
+</div>
+<div id="t5" hidden class="color-transition">
+ <div class="color-transition"></div>
+</div>
+<script>
+ setup(() => {
+ assert_true(supportsStartingStyle(), "Prerequisite: @starting-style parses");
+ });
+
+ promise_test(async t => {
+ await waitForAnimationFrames(2);
+ t1.removeAttribute("hidden");
+ await waitForAnimationFrames(2);
+ assert_equals(getComputedStyle(t1).color, "rgb(0, 128, 0)",
+ "No transition of color");
+ }, "Overridden @starting-style - order of appearance");
+
+ promise_test(async t => {
+ t2.removeAttribute("hidden");
+ await waitForAnimationFrames(2);
+ assert_equals(getComputedStyle(t2).color, "rgb(0, 192, 0)",
+ "Transition of color");
+ }, "@starting-style with higher specificity");
+
+ promise_test(async t => {
+ t3.removeAttribute("hidden");
+ await waitForAnimationFrames(2);
+ assert_equals(getComputedStyle(t3.firstElementChild).color, "rgb(0, 128, 0)",
+ "No transition of color");
+ }, "Starting style does not inherit from parent starting style");
+
+ promise_test(async t => {
+ assert_equals(getComputedStyle(t4).color, "rgb(255, 0, 0)",
+ "Parent transition started");
+ t4.removeAttribute("hidden");
+ await waitForAnimationFrames(2);
+ assert_equals(getComputedStyle(t4).color, "rgb(0, 128, 0)",
+ "Parent changed to green");
+ assert_equals(getComputedStyle(t4.firstElementChild).color, "rgb(0, 192, 0)",
+ "Transition started from parent's after-change style color");
+ }, "Starting style inheriting from parent's after-change style");
+
+ promise_test(async t => {
+ t5.removeAttribute("hidden");
+ await waitForAnimationFrames(2);
+ assert_equals(getComputedStyle(t5).color, "rgb(0, 64, 0)",
+ "Parent transition started");
+ assert_equals(getComputedStyle(t5.firstElementChild).color, "rgb(0, 192, 0)",
+ "Transition started from parent's after-change style color");
+ }, "Starting style inheriting from parent's after-change style while parent transitioning");
+</script>
diff --git a/testing/web-platform/tests/css/css-transitions/starting-style-name-defining-rules.html b/testing/web-platform/tests/css/css-transitions/starting-style-name-defining-rules.html
new file mode 100644
index 0000000000..3d1b0b3c83
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/starting-style-name-defining-rules.html
@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<title>CSS Transitions Test: Name defining @-rules in @starting-style</title>
+<link rel="help" href="https://drafts.csswg.org/css-transitions-2/#defining-before-change-style-the-starting-style-rule">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+ @starting-style {
+ @keyframes anim {
+ from { color: green; }
+ to { color: red; }
+ }
+ @font-face {
+ font-family: web-font;
+ src: url('/fonts/Ahem.ttf');
+ }
+ @layer first;
+ }
+
+ @layer second {
+ #target.not_start {
+ background-color: green;
+ }
+ }
+ @layer first {
+ #target.not_start {
+ background-color: red;
+ }
+ }
+
+ #target.not_start {
+ animation-name: anim;
+ animation-duration: 60s;
+ animation-timing-function: step-end;
+ font-family: web-font;
+ font-size: 20px;
+ }
+
+ #target {
+ /* For measuring text width */
+ display: inline-block;
+ }
+</style>
+<span id="target">XXXX</span>
+<script>
+ test(() => {
+ // Force style update to ensure before-change style is defined.
+ target.offsetTop;
+ target.className = "not_start";
+ let target_style = getComputedStyle(target);
+ assert_equals(target_style.color, "rgb(0, 128, 0)", "@keyframes applied");
+ assert_equals(target_style.backgroundColor, "rgb(0, 128, 0)", "@layer applied");
+ }, "@keyframes and @layer in @starting-style apply");
+
+ promise_test(async () => {
+ await document.fonts.load("20px/1 web-font");
+ assert_equals(getComputedStyle(target).width, "80px");
+ }, "Load @font-face from @starting-style rule");
+</script>
diff --git a/testing/web-platform/tests/css/css-transitions/starting-style-rule-basic.html b/testing/web-platform/tests/css/css-transitions/starting-style-rule-basic.html
new file mode 100644
index 0000000000..7ed5880146
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/starting-style-rule-basic.html
@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<title>CSS Transitions Test: Basic tests for @starting-style</title>
+<link rel="help" href="https://drafts.csswg.org/css-transitions-2/#defining-before-change-style-the-starting-style-rule">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/css-transitions/support/helper.js"></script>
+<div id="target" class="trans"></div>
+<style>
+ #target {
+ transition-property: background-color, color;
+ transition-duration: 100s;
+ transition-timing-function: steps(2, start);
+ color: green;
+ background-color: white;
+ }
+ @starting-style {
+ #target {
+ background-color: black;
+ }
+ }
+ #target.red {
+ background-color: red;
+ }
+</style>
+<script>
+ promise_test(async t => {
+ await waitForAnimationFrames(2);
+ assert_equals(getComputedStyle(target).color, "rgb(0, 128, 0)",
+ "No transition of color");
+ assert_equals(getComputedStyle(target).backgroundColor, "rgb(128, 128, 128)",
+ "Background transition from @starting-style value black to white");
+ }, "Triggered transition from first style update");
+
+ promise_test(async t => {
+ target.style.display = "none";
+ target.className = "red";
+ assert_equals(getComputedStyle(target).backgroundColor, "rgb(255, 0, 0)",
+ "Overridden with red. No transition while display:none");
+ target.className = "";
+ assert_equals(getComputedStyle(target).backgroundColor, "rgb(255, 255, 255)",
+ "Removing class while display:none. Still no transition");
+ await waitForAnimationFrames(2);
+ target.style.display = "block";
+ await waitForAnimationFrames(2);
+ assert_equals(getComputedStyle(target).backgroundColor, "rgb(128, 128, 128)",
+ "Background transition from @starting-style value black to white");
+ }, "Triggered transition from display:none to display:block");
+
+ promise_test(async t => {
+ let removed = target;
+ removed.remove();
+ await waitForAnimationFrames(2);
+ document.body.appendChild(removed);
+ await waitForAnimationFrames(2);
+ assert_equals(getComputedStyle(target).backgroundColor, "rgb(128, 128, 128)",
+ "Background transition from @starting-style value black to white");
+ }, "Triggered transition on DOM insertion");
+</script>
diff --git a/testing/web-platform/tests/css/css-transitions/starting-style-rule-none.html b/testing/web-platform/tests/css/css-transitions/starting-style-rule-none.html
new file mode 100644
index 0000000000..91e4fe3534
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/starting-style-rule-none.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<title>CSS Transitions Test: No transition if @starting-style display value is none</title>
+<link rel="help" href="https://drafts.csswg.org/css-transitions-2/#defining-before-change-style-the-starting-style-rule">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/css-transitions/support/helper.js"></script>
+<div id="target"></div>
+<style>
+ #target {
+ transition-property: background-color;
+ transition-duration: 100s;
+ transition-timing-function: steps(2, start);
+ background-color: green;
+ }
+ @starting-style {
+ #target {
+ display: none;
+ background-color: red;
+ }
+ }
+</style>
+<script>
+ setup(() => {
+ assert_true(supportsStartingStyle(), "Prerequisite: @starting-style parses");
+ });
+
+ promise_test(async t => {
+ await waitForAnimationFrames(2);
+ assert_equals(getComputedStyle(target).backgroundColor, "rgb(0, 128, 0)",
+ "No transition of background-color when @starting-style display is 'none'");
+ }, "@starting-style with display:none");
+</script>
diff --git a/testing/web-platform/tests/css/css-transitions/starting-style-rule-pseudo-elements.html b/testing/web-platform/tests/css/css-transitions/starting-style-rule-pseudo-elements.html
new file mode 100644
index 0000000000..a21faba8bb
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/starting-style-rule-pseudo-elements.html
@@ -0,0 +1,59 @@
+<!DOCTYPE html>
+<title>CSS Transitions Test: @starting-style for pseudo elements</title>
+<link rel="help" href="https://drafts.csswg.org/css-transitions-2/#defining-before-change-style-the-starting-style-rule">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/css-transitions/support/helper.js"></script>
+<div id="target" class="trans"></div>
+<style>
+ #target::before {
+ transition-property: background-color, color;
+ transition-duration: 100s;
+ transition-timing-function: steps(2, start);
+ color: green;
+ background-color: white;
+ content: "";
+ }
+ @starting-style {
+ #target::before {
+ background-color: black;
+ }
+ }
+ #target.red::before {
+ background-color: red;
+ }
+</style>
+<script>
+ promise_test(async t => {
+ await waitForAnimationFrames(2);
+ assert_equals(getComputedStyle(target, "::before").color, "rgb(0, 128, 0)",
+ "No transition of color");
+ assert_equals(getComputedStyle(target, "::before").backgroundColor, "rgb(128, 128, 128)",
+ "Background transition from @starting-style value black to white");
+ }, "Triggered transition from first style update");
+
+ promise_test(async t => {
+ target.style.display = "none";
+ target.className = "red";
+ assert_equals(getComputedStyle(target, "::before").backgroundColor, "rgb(255, 0, 0)",
+ "Overridden with red. No transition while display:none");
+ target.className = "";
+ assert_equals(getComputedStyle(target, "::before").backgroundColor, "rgb(255, 255, 255)",
+ "Removing class while display:none. Still no transition");
+ await waitForAnimationFrames(2);
+ target.style.display = "block";
+ await waitForAnimationFrames(2);
+ assert_equals(getComputedStyle(target, "::before").backgroundColor, "rgb(128, 128, 128)",
+ "Background transition from @starting-style value black to white");
+ }, "Triggered transition from display:none to display:block");
+
+ promise_test(async t => {
+ let removed = target;
+ removed.remove();
+ await waitForAnimationFrames(2);
+ document.body.appendChild(removed);
+ await waitForAnimationFrames(2);
+ assert_equals(getComputedStyle(target, "::before").backgroundColor, "rgb(128, 128, 128)",
+ "Background transition from @starting-style value black to white");
+ }, "Triggered transition on DOM insertion");
+</script>
diff --git a/testing/web-platform/tests/css/css-transitions/starting-style-size-container.html b/testing/web-platform/tests/css/css-transitions/starting-style-size-container.html
new file mode 100644
index 0000000000..92ad6e6125
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/starting-style-size-container.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<title>CSS Transitions Test: @starting-style inside size @container</title>
+<link rel="help" href="https://drafts.csswg.org/css-transitions-2/#defining-before-change-style-the-starting-style-rule">
+<link rel="help" href="https://drafts.csswg.org/css-contain-3/#animated-containers">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/css-transitions/support/helper.js"></script>
+<div id="container" style="width: 200px">
+ <div id="target" style="display: none"></div>
+</div>
+<style>
+ #container {
+ container-type: inline-size;
+ }
+ #target {
+ transition-property: background-color;
+ transition-duration: 100s;
+ transition-timing-function: steps(2, start);
+ background-color: lime;
+ }
+ @container (width > 300px) {
+ @starting-style {
+ #target { background-color: white; }
+ }
+ }
+ @container (width < 300px) {
+ @starting-style {
+ #target { background-color: red; }
+ }
+ }
+</style>
+<script>
+ promise_test(async t => {
+ await waitForAnimationFrames(2);
+ assert_equals(getComputedStyle(target).backgroundColor, "rgb(0, 255, 0)",
+ "No transition while display:none");
+ container.style.width = "400px";
+ target.style.display = "block";
+ await waitForAnimationFrames(2);
+ assert_equals(getComputedStyle(target).backgroundColor, "rgb(128, 255, 128)",
+ "@starting-style based on the size query evaluation from the same frame");
+ }, "Triggered transition from first style update based on up-to-date container query");
+</script>
diff --git a/testing/web-platform/tests/css/css-transitions/support/1x1-green.png b/testing/web-platform/tests/css/css-transitions/support/1x1-green.png
new file mode 100644
index 0000000000..b98ca0ba0a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/support/1x1-green.png
Binary files differ
diff --git a/testing/web-platform/tests/css/css-transitions/support/1x1-lime.png b/testing/web-platform/tests/css/css-transitions/support/1x1-lime.png
new file mode 100644
index 0000000000..cb397fb090
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/support/1x1-lime.png
Binary files differ
diff --git a/testing/web-platform/tests/css/css-transitions/support/1x1-maroon.png b/testing/web-platform/tests/css/css-transitions/support/1x1-maroon.png
new file mode 100644
index 0000000000..3f86b07219
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/support/1x1-maroon.png
Binary files differ
diff --git a/testing/web-platform/tests/css/css-transitions/support/1x1-navy.png b/testing/web-platform/tests/css/css-transitions/support/1x1-navy.png
new file mode 100644
index 0000000000..9b9a03955b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/support/1x1-navy.png
Binary files differ
diff --git a/testing/web-platform/tests/css/css-transitions/support/1x1-red.png b/testing/web-platform/tests/css/css-transitions/support/1x1-red.png
new file mode 100644
index 0000000000..6bd73ac101
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/support/1x1-red.png
Binary files differ
diff --git a/testing/web-platform/tests/css/css-transitions/support/1x1-white.png b/testing/web-platform/tests/css/css-transitions/support/1x1-white.png
new file mode 100644
index 0000000000..dd43faec54
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/support/1x1-white.png
Binary files differ
diff --git a/testing/web-platform/tests/css/css-transitions/support/60x60-gg-rr.png b/testing/web-platform/tests/css/css-transitions/support/60x60-gg-rr.png
new file mode 100644
index 0000000000..84f5b2a4f1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/support/60x60-gg-rr.png
Binary files differ
diff --git a/testing/web-platform/tests/css/css-transitions/support/60x60-green.png b/testing/web-platform/tests/css/css-transitions/support/60x60-green.png
new file mode 100644
index 0000000000..b3c8cf3eb4
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/support/60x60-green.png
Binary files differ
diff --git a/testing/web-platform/tests/css/css-transitions/support/README b/testing/web-platform/tests/css/css-transitions/support/README
new file mode 100644
index 0000000000..2e5f2ad073
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/support/README
@@ -0,0 +1,28 @@
+CSS Global Support Directory
+============================
+
+This directory contains common support files (such as images and external
+style sheets). These are sync'ed into the support directories of all our
+test suites. If you have test-suite-specific support files, please add
+them to the appropriate test-suite-specific support/ directory.
+
+If you add to a support/ directory, please run the tools/supportprop.py
+script from the top of the repository to cascade support files into the
+lower-level support directories.
+
+Description of the Common Support File Collection
+-------------------------------------------------
+
+The 1x1-* images are all exactly one pixel.
+
+The swatch-* images all use 15x15 cells.
+
+The square-* images all use 15x15 cells with one pixel borders.
+
+The pattern-* images use cells of various sizes:
+
+ pattern-grg-rgr-grg.png 20x20
+ pattern-rgr-grg-rgr.png 20x20
+ pattern-tr.png 15x15
+ pattern-grg-rrg-rgg.png 15x15
+
diff --git a/testing/web-platform/tests/css/css-transitions/support/a-green-transition.css b/testing/web-platform/tests/css/css-transitions/support/a-green-transition.css
new file mode 100644
index 0000000000..3f68e53cd6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/support/a-green-transition.css
@@ -0,0 +1 @@
+.a { color: green; transition: 10s; transition-timing-function: step-end; }
diff --git a/testing/web-platform/tests/css/css-transitions/support/a-green.css b/testing/web-platform/tests/css/css-transitions/support/a-green.css
new file mode 100644
index 0000000000..b0dbb071d5
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/support/a-green.css
@@ -0,0 +1 @@
+.a { color: green; }
diff --git a/testing/web-platform/tests/css/css-transitions/support/b-green.css b/testing/web-platform/tests/css/css-transitions/support/b-green.css
new file mode 100644
index 0000000000..a0473f5ca2
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/support/b-green.css
@@ -0,0 +1 @@
+.b { color: green; } \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-transitions/support/c-red.css b/testing/web-platform/tests/css/css-transitions/support/c-red.css
new file mode 100644
index 0000000000..d4ba5c64e9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/support/c-red.css
@@ -0,0 +1 @@
+.c { color: red; } \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-transitions/support/cat.png b/testing/web-platform/tests/css/css-transitions/support/cat.png
new file mode 100644
index 0000000000..85dd732481
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/support/cat.png
Binary files differ
diff --git a/testing/web-platform/tests/css/css-transitions/support/generalParallelTest.js b/testing/web-platform/tests/css/css-transitions/support/generalParallelTest.js
new file mode 100644
index 0000000000..f6e14128fc
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/support/generalParallelTest.js
@@ -0,0 +1,231 @@
+(function(root) {
+'use strict';
+//
+var index = 0;
+var suite = root.generalParallelTest = {
+ // prepare individual test
+ setup: function(data, options) {
+ suite._setupDom(data, options);
+ suite._setupEvents(data, options);
+ },
+ // clone fixture and prepare data containers
+ _setupDom: function(data, options) {
+ // clone fixture into off-viewport test-canvas
+ data.fixture = document.getElementById('fixture').cloneNode(true);
+ data.fixture.id = 'test-' + (index++);
+ (document.getElementById('offscreen') || document.body).appendChild(data.fixture);
+
+ // data container for #fixture > .container > .transition
+ data.transition = {
+ node: data.fixture.querySelector('.transition'),
+ values: [],
+ events: [],
+ computedStyle: function(property) {
+ return computedStyle(data.transition.node, property);
+ }
+ };
+
+ // data container for #fixture > .container
+ data.container = {
+ node: data.transition.node.parentNode,
+ values: [],
+ events: [],
+ computedStyle: function(property) {
+ return computedStyle(data.container.node, property);
+ }
+ };
+
+ // data container for #fixture > .container > .transition[:before | :after]
+ if (data.pseudo) {
+ data.pseudo = {
+ name: data.pseudo,
+ values: [],
+ computedStyle: function(property) {
+ return computedStyle(data.transition.node, property, ':' + data.pseudo.name);
+ }
+ };
+ }
+ },
+ // bind TransitionEnd event listeners
+ _setupEvents: function(data, options) {
+ ['transition', 'container'].forEach(function(elem) {
+ var handler = function(event) {
+ event.stopPropagation();
+ var name = event.propertyName;
+ var time = Math.round(event.elapsedTime * 1000) / 1000;
+ var pseudo = event.pseudoElement ? (':' + event.pseudoElement) : '';
+ data[elem].events.push(name + pseudo + ":" + time + "s");
+ };
+ data[elem].node.addEventListener('transitionend', handler, false);
+ data[elem]._events = {'transitionend': handler};
+ });
+ },
+ // cleanup after individual test
+ teardown: function(data, options) {
+ // data.fixture.remove();
+ if (data.fixture.parentNode) {
+ data.fixture.parentNode.removeChild(data.fixture);
+ }
+ },
+ // invoked prior to running a slice of tests
+ sliceStart: function(options, tests) {
+ // inject styles into document
+ setStyle(options.styles);
+ // kick off value collection loop
+ generalParallelTest.startValueCollection(options);
+ },
+ // invoked after running a slice of tests
+ sliceDone: function(options, tests) {
+ // stop value collection loop
+ generalParallelTest.stopValueCollection(options);
+ // reset styles cache
+ options.styles = {};
+ },
+ // called once all tests are done
+ done: function(options) {
+ // reset document styles
+ setStyle();
+ reflow();
+ },
+ // add styles of individual test to slice cache
+ addStyles: function(data, options, styles) {
+ if (!options.styles) {
+ options.styles = {};
+ }
+
+ Object.keys(styles).forEach(function(key) {
+ var selector = '#' + data.fixture.id
+ // fixture must become #fixture.fixture rather than a child selector
+ + (key.substring(0, 8) === '.fixture' ? '' : ' ')
+ + key;
+
+ options.styles[selector] = styles[key];
+ });
+ },
+ // set style and compute values for container and transition
+ getStyle: function(data) {
+ reflow();
+ // grab current styles: "initial state"
+ suite._getStyleFor(data, 'from');
+ // apply target state
+ suite._addClass(data, 'to', true);
+ // grab current styles: "target state"
+ suite._getStyleFor(data, 'to');
+ // remove target state
+ suite._removeClass(data, 'to', true);
+
+ // clean up the mess created for value collection
+ data.container._values = [];
+ data.transition._values = [];
+ if (data.pseudo) {
+ data.pseudo._values = [];
+ }
+ },
+ // grab current styles and store in respective element's data container
+ _getStyleFor: function(data, key) {
+ data.container[key] = data.container.computedStyle(data.property);
+ data.transition[key] = data.transition.computedStyle(data.property);
+ if (data.pseudo) {
+ data.pseudo[key] = data.pseudo.computedStyle(data.property);
+ }
+ },
+ // add class to test's elements and possibly reflow
+ _addClass: function(data, className, forceReflow) {
+ data.container.node.classList.add(className);
+ data.transition.node.classList.add(className);
+ if (forceReflow) {
+ reflow();
+ }
+ },
+ // remove class from test's elements and possibly reflow
+ _removeClass: function(data, className, forceReflow) {
+ data.container.node.classList.remove(className);
+ data.transition.node.classList.remove(className);
+ if (forceReflow) {
+ reflow();
+ }
+ },
+ // add transition and to classes to container and transition
+ startTransition: function(data) {
+ // add transition-defining class
+ suite._addClass(data, 'how', true);
+ // add target state (without reflowing)
+ suite._addClass(data, 'to', false);
+ },
+ // requestAnimationFrame runLoop to collect computed values
+ startValueCollection: function(options) {
+ var raf = window.requestAnimationFrame || function(callback){
+ setTimeout(callback, 20);
+ };
+
+ // flag denoting if the runLoop should continue (true) or exit (false)
+ options._collectValues = true;
+
+ function runLoop() {
+ if (!options._collectValues) {
+ // test's are done, stop annoying the CPU
+ return;
+ }
+
+ // collect current style for test's elements
+ options.tests.forEach(function(data) {
+ if (!data.property) {
+ return;
+ }
+
+ ['transition', 'container', 'pseudo'].forEach(function(elem) {
+ var pseudo = null;
+ if (!data[elem] || (elem === 'pseudo' && !data.pseudo)) {
+ return;
+ }
+
+ var current = data[elem].computedStyle(data.property);
+ var values = data[elem].values;
+ var length = values.length;
+ if (!length || values[length - 1] !== current) {
+ values.push(current);
+ }
+ });
+ });
+
+ // rinse and repeat
+ raf(runLoop);
+ }
+
+ runLoop();
+ },
+ // stop requestAnimationFrame runLoop collecting computed values
+ stopValueCollection: function(options) {
+ options._collectValues = false;
+ },
+
+ // generate test.step function asserting collected events match expected
+ assertExpectedEventsFunc: function(data, elem, expected) {
+ return function() {
+ var _result = data[elem].events.sort().join(" ");
+ var _expected = typeof expected === 'string' ? expected : expected.sort().join(" ");
+ assert_equals(_result, _expected, "Expected TransitionEnd events triggered on ." + elem);
+ };
+ },
+ // generate test.step function asserting collected values are neither initial nor target
+ assertIntermediateValuesFunc: function(data, elem) {
+ return function() {
+ // the first value (index: 0) is always going to be the initial value
+ // the last value is always going to be the target value
+ var values = data[elem].values;
+ if (data.flags.discrete) {
+ // a discrete value will just switch from one state to another without having passed intermediate states.
+ assert_equals(values[0], data[elem].from, "must be initial value while transitioning on ." + elem);
+ assert_equals(values[1], data[elem].to, "must be target value after transitioning on ." + elem);
+ assert_equals(values.length, 2, "discrete property only has 2 values ." + elem);
+ } else {
+ assert_not_equals(values[1], data[elem].from, "may not be initial value while transitioning on ." + elem);
+ assert_not_equals(values[1], data[elem].to, "may not be target value while transitioning on ." + elem);
+ }
+
+ // TODO: first value must be initial, last value must be target
+ };
+ }
+};
+
+})(window);
diff --git a/testing/web-platform/tests/css/css-transitions/support/helper.js b/testing/web-platform/tests/css/css-transitions/support/helper.js
new file mode 100644
index 0000000000..a37aae9183
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/support/helper.js
@@ -0,0 +1,326 @@
+//
+// Simple Helper Functions For Testing CSS
+//
+
+(function(root) {
+'use strict';
+
+// serialize styles object and dump to dom
+// appends <style id="dynamic-style"> to <head>
+// setStyle("#some-selector", {"some-style" : "value"})
+// setStyle({"#some-selector": {"some-style" : "value"}})
+root.setStyle = function(selector, styles) {
+ var target = document.getElementById('dynamic-style');
+ if (!target) {
+ target = document.createElement('style');
+ target.id = 'dynamic-style';
+ target.type = "text/css";
+ document.getElementsByTagName('head')[0].appendChild(target);
+ }
+
+ var data = [];
+ // single selector/styles
+ if (typeof selector === 'string' && styles !== undefined) {
+ data = [selector, '{', serializeStyles(styles), '}'];
+ target.textContent = data.join("\n");
+ return;
+ }
+ // map of selector/styles
+ for (var key in selector) {
+ if (Object.prototype.hasOwnProperty.call(selector, key)) {
+ var _data = [key, '{', serializeStyles(selector[key]), '}'];
+ data.push(_data.join('\n'));
+ }
+ }
+
+ target.textContent = data.join("\n");
+};
+
+function serializeStyles(styles) {
+ var data = [];
+ for (var property in styles) {
+ if (Object.prototype.hasOwnProperty.call(styles, property)) {
+ var prefixedProperty = addVendorPrefix(property);
+ data.push(prefixedProperty + ":" + styles[property] + ";");
+ }
+ }
+
+ return data.join('\n');
+}
+
+
+// shorthand for computed style
+root.computedStyle = function(element, property, pseudo) {
+ var prefixedProperty = addVendorPrefix(property);
+ return window
+ .getComputedStyle(element, pseudo || null)
+ .getPropertyValue(prefixedProperty);
+};
+
+// flush rendering buffer
+root.reflow = function() {
+ document.body.offsetWidth;
+};
+
+// merge objects
+root.extend = function(target /*, ..rest */) {
+ Array.prototype.slice.call(arguments, 1).forEach(function(obj) {
+ Object.keys(obj).forEach(function(key) {
+ target[key] = obj[key];
+ });
+ });
+
+ return target;
+};
+
+// dom fixture helper ("resetting dom test elements")
+var _domFixture;
+var _domFixtureSelector;
+root.domFixture = function(selector) {
+ var fixture = document.querySelector(selector || _domFixtureSelector);
+ if (!fixture) {
+ throw new Error('fixture ' + (selector || _domFixtureSelector) + ' not found!');
+ }
+ if (!_domFixture && selector) {
+ // save a copy
+ _domFixture = fixture.cloneNode(true);
+ _domFixtureSelector = selector;
+ } else if (_domFixture) {
+ // restore the copy
+ var tmp = _domFixture.cloneNode(true);
+ fixture.parentNode.replaceChild(tmp, fixture);
+ } else {
+ throw new Error('domFixture must be initialized first!');
+ }
+};
+
+root.MS_PER_SEC = 1000;
+
+/*
+ * The recommended minimum precision to use for time values.
+ *
+ * Based on Web Animations:
+ * https://w3c.github.io/web-animations/#precision-of-time-values
+ */
+const TIME_PRECISION = 0.0005; // ms
+
+/*
+ * Allow implementations to substitute an alternative method for comparing
+ * times based on their precision requirements.
+ */
+root.assert_times_equal = function(actual, expected, description) {
+ assert_approx_equals(actual, expected, TIME_PRECISION, description);
+};
+
+/*
+ * Compare a time value based on its precision requirements with a fixed value.
+ */
+root.assert_time_equals_literal = (actual, expected, description) => {
+ assert_approx_equals(actual, expected, TIME_PRECISION, description);
+};
+
+/**
+ * Assert that CSSTransition event, |evt|, has the expected property values
+ * defined by |propertyName|, |elapsedTime|, and |pseudoElement|.
+ */
+root.assert_end_events_equal = function(evt, propertyName, elapsedTime,
+ pseudoElement = '') {
+ assert_equals(evt.propertyName, propertyName);
+ assert_times_equal(evt.elapsedTime, elapsedTime);
+ assert_equals(evt.pseudoElement, pseudoElement);
+};
+
+/**
+ * Assert that array of simultaneous CSSTransition events, |evts|, have the
+ * corresponding property names listed in |propertyNames|, and the expected
+ * |elapsedTimes| and |pseudoElement| members.
+ *
+ * |elapsedTimes| may be a single value if all events are expected to have the
+ * same elapsedTime, or an array parallel to |propertyNames|.
+ */
+root.assert_end_event_batch_equal = function(evts, propertyNames, elapsedTimes,
+ pseudoElement = '') {
+ assert_equals(
+ evts.length,
+ propertyNames.length,
+ 'Test harness error: should have waited for the correct number of events'
+ );
+ assert_true(
+ typeof elapsedTimes === 'number' ||
+ (Array.isArray(elapsedTimes) &&
+ elapsedTimes.length === propertyNames.length),
+ 'Test harness error: elapsedTimes must either be a number or an array of' +
+ ' numbers with the same length as propertyNames'
+ );
+
+ if (typeof elapsedTimes === 'number') {
+ elapsedTimes = Array(propertyNames.length).fill(elapsedTimes);
+ }
+ const testPairs = propertyNames.map((propertyName, index) => ({
+ propertyName,
+ elapsedTime: elapsedTimes[index]
+ }));
+
+ const sortByPropertyName = (a, b) =>
+ a.propertyName.localeCompare(b.propertyName);
+ evts.sort(sortByPropertyName);
+ testPairs.sort(sortByPropertyName);
+
+ for (let evt of evts) {
+ const expected = testPairs.shift();
+ assert_end_events_equal(
+ evt,
+ expected.propertyName,
+ expected.elapsedTime,
+ pseudoElement
+ );
+ }
+}
+
+/**
+ * Appends a div to the document body.
+ *
+ * @param t The testharness.js Test object. If provided, this will be used
+ * to register a cleanup callback to remove the div when the test
+ * finishes.
+ *
+ * @param attrs A dictionary object with attribute names and values to set on
+ * the div.
+ */
+root.addDiv = function(t, attrs) {
+ var div = document.createElement('div');
+ if (attrs) {
+ for (var attrName in attrs) {
+ div.setAttribute(attrName, attrs[attrName]);
+ }
+ }
+ document.body.appendChild(div);
+ if (t && typeof t.add_cleanup === 'function') {
+ t.add_cleanup(function() {
+ if (div.parentNode) {
+ div.remove();
+ }
+ });
+ }
+ return div;
+};
+
+/**
+ * Appends a style div to the document head.
+ *
+ * @param t The testharness.js Test object. If provided, this will be used
+ * to register a cleanup callback to remove the style element
+ * when the test finishes.
+ *
+ * @param rules A dictionary object with selector names and rules to set on
+ * the style sheet.
+ */
+root.addStyle = (t, rules) => {
+ const extraStyle = document.createElement('style');
+ document.head.appendChild(extraStyle);
+ if (rules) {
+ const sheet = extraStyle.sheet;
+ for (const selector in rules) {
+ sheet.insertRule(selector + '{' + rules[selector] + '}',
+ sheet.cssRules.length);
+ }
+ }
+
+ if (t && typeof t.add_cleanup === 'function') {
+ t.add_cleanup(() => {
+ extraStyle.remove();
+ });
+ }
+ return extraStyle;
+};
+
+/**
+ * Promise wrapper for requestAnimationFrame.
+ */
+root.waitForFrame = () => {
+ return new Promise(resolve => {
+ window.requestAnimationFrame(resolve);
+ });
+};
+
+/**
+ * Returns a Promise that is resolved after the given number of consecutive
+ * animation frames have occured (using requestAnimationFrame callbacks).
+ *
+ * @param frameCount The number of animation frames.
+ * @param onFrame An optional function to be processed in each animation frame.
+ */
+root.waitForAnimationFrames = (frameCount, onFrame) => {
+ const timeAtStart = document.timeline.currentTime;
+ return new Promise(resolve => {
+ function handleFrame() {
+ if (onFrame && typeof onFrame === 'function') {
+ onFrame();
+ }
+ if (timeAtStart != document.timeline.currentTime &&
+ --frameCount <= 0) {
+ resolve();
+ } else {
+ window.requestAnimationFrame(handleFrame); // wait another frame
+ }
+ }
+ window.requestAnimationFrame(handleFrame);
+ });
+};
+
+/**
+ * Wrapper that takes a sequence of N animations and returns:
+ *
+ * Promise.all([animations[0].ready, animations[1].ready, ... animations[N-1].ready]);
+ */
+root.waitForAllAnimations = animations =>
+ Promise.all(animations.map(animation => animation.ready));
+
+/**
+ * Utility that takes a Promise and a maximum number of frames to wait and
+ * returns a new Promise that behaves as follows:
+ *
+ * - If the provided Promise resolves _before_ the specified number of frames
+ * have passed, resolves with the result of the provided Promise.
+ * - If the provided Promise rejects _before_ the specified number of frames
+ * have passed, rejects with the error result of the provided Promise.
+ * - Otherwise, rejects with a 'Timed out' error message. If |message| is
+ * provided, it will be appended to the error message.
+ */
+root.frameTimeout = (promiseToWaitOn, framesToWait, message) => {
+ let framesRemaining = framesToWait;
+ let aborted = false;
+
+ const timeoutPromise = new Promise(function waitAFrame(resolve, reject) {
+ if (aborted) {
+ resolve();
+ return;
+ }
+ if (framesRemaining-- > 0) {
+ requestAnimationFrame(() => {
+ waitAFrame(resolve, reject);
+ });
+ return;
+ }
+ let errorMessage = 'Timed out waiting for Promise to resolve';
+ if (message) {
+ errorMessage += `: ${message}`;
+ }
+ reject(new Error(errorMessage));
+ });
+
+ const wrappedPromiseToWaitOn = promiseToWaitOn.then(result => {
+ aborted = true;
+ return result;
+ });
+
+ return Promise.race([timeoutPromise, wrappedPromiseToWaitOn]);
+};
+
+root.supportsStartingStyle = () => {
+ let sheet = new CSSStyleSheet();
+ sheet.replaceSync("@starting-style{}");
+ return sheet.cssRules.length == 1;
+};
+
+})(window);
diff --git a/testing/web-platform/tests/css/css-transitions/support/import-green.css b/testing/web-platform/tests/css/css-transitions/support/import-green.css
new file mode 100644
index 0000000000..537104e663
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/support/import-green.css
@@ -0,0 +1 @@
+.import { color: green; }
diff --git a/testing/web-platform/tests/css/css-transitions/support/import-red.css b/testing/web-platform/tests/css/css-transitions/support/import-red.css
new file mode 100644
index 0000000000..9945ef4711
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/support/import-red.css
@@ -0,0 +1 @@
+.import { color: red; }
diff --git a/testing/web-platform/tests/css/css-transitions/support/one.gif b/testing/web-platform/tests/css/css-transitions/support/one.gif
new file mode 100644
index 0000000000..74cf7839c9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/support/one.gif
Binary files differ
diff --git a/testing/web-platform/tests/css/css-transitions/support/pattern-grg-rgr-grg.png b/testing/web-platform/tests/css/css-transitions/support/pattern-grg-rgr-grg.png
new file mode 100644
index 0000000000..9b88fbd811
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/support/pattern-grg-rgr-grg.png
Binary files differ
diff --git a/testing/web-platform/tests/css/css-transitions/support/pattern-grg-rrg-rgg.png b/testing/web-platform/tests/css/css-transitions/support/pattern-grg-rrg-rgg.png
new file mode 100644
index 0000000000..fcf4f3fd7d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/support/pattern-grg-rrg-rgg.png
Binary files differ
diff --git a/testing/web-platform/tests/css/css-transitions/support/pattern-rgr-grg-rgr.png b/testing/web-platform/tests/css/css-transitions/support/pattern-rgr-grg-rgr.png
new file mode 100644
index 0000000000..d454e3a630
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/support/pattern-rgr-grg-rgr.png
Binary files differ
diff --git a/testing/web-platform/tests/css/css-transitions/support/pattern-tr.png b/testing/web-platform/tests/css/css-transitions/support/pattern-tr.png
new file mode 100644
index 0000000000..8b4b25364e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/support/pattern-tr.png
Binary files differ
diff --git a/testing/web-platform/tests/css/css-transitions/support/properties.js b/testing/web-platform/tests/css/css-transitions/support/properties.js
new file mode 100644
index 0000000000..0c0057b39e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/support/properties.js
@@ -0,0 +1,410 @@
+(function(root){
+
+/*
+ * General Value Types definition
+ * they return an object of arrays of type { <name>: [<start-value>, <end-value>], ... }
+ */
+var values = {
+ 'length' : function() {
+ // http://www.w3.org/TR/css3-values/#lengths
+ return {
+ // CSS Values and Module Level 3
+ // ch: ['1ch', '10ch'],
+ // rem: ['1rem', '10rem'],
+ // vw: ['1vw', '10vw'],
+ // vh: ['1vh', '10vh'],
+ // vmin: ['1vmin', '10vmin'],
+ // vmax: ['1vmax', '10vmax'],
+ // CSS Values and Module Level 2
+ pt: ['1pt', '10pt'],
+ pc: ['1pc', '10pc'],
+ px: ['1px', '10px'],
+ // CSS Values and Module Level 1
+ em: ['1em', '10em'],
+ ex: ['1ex', '10ex'],
+ mm: ['1mm', '10mm'],
+ cm: ['1cm', '10cm'],
+ 'in': ['1in', '10in']
+ };
+ },
+ 'length-em': function() {
+ return {
+ em: ['1.1em', '1.5em']
+ };
+ },
+ 'percentage': function() {
+ // http://www.w3.org/TR/css3-values/#percentages
+ return {
+ '%': ['33%', '80%']
+ };
+ },
+ 'color': function() {
+ // http://www.w3.org/TR/css3-values/#colors
+ // http://www.w3.org/TR/css3-color/
+ return {
+ rgba: ['rgba(100,100,100,1)', 'rgba(10,10,10,0.4)']
+ };
+ },
+ 'rectangle': function() {
+ // http://www.w3.org/TR/CSS2/visufx.html#value-def-shape
+ return {
+ rectangle: ['rect(10px,10px,10px,10px)', 'rect(15px,15px,5px,5px)']
+ };
+ },
+ 'font-weight': function() {
+ // http://www.w3.org/TR/css3-fonts/#font-weight-prop
+ return {
+ keyword: ["normal", "bold"],
+ numeric: ["100", "900"]
+ };
+ },
+ 'number': function() {
+ // http://www.w3.org/TR/css3-values/#number
+ return {
+ integer: ["1", "10"],
+ decimal: ["1.1", "9.55"]
+ };
+ },
+ 'number[0,1]': function() {
+ // http://www.w3.org/TR/css3-values/#number
+ // applies to [0,1]-ranged properties like opacity
+ return {
+ "zero-to-one": ["0.2", "0.9"]
+ };
+ },
+ 'integer': function() {
+ // http://www.w3.org/TR/css3-values/#integer
+ return {
+ integer: ["1", "10"]
+ };
+ },
+ 'shadow': function() {
+ // http://www.w3.org/TR/css-text-decor-3/#text-shadow-property
+ return {
+ shadow: ['rgba(0,0,0,0.1) 5px 6px 7px', 'rgba(10,10,10,0.9) 5px 6px 7px']
+ };
+ },
+ 'visibility': function() {
+ // http://www.w3.org/TR/CSS2/visufx.html#visibility
+ return {
+ keyword: ['visible', 'hidden', {discrete: true}]
+ };
+ },
+ // types reqired for non-specified properties
+ 'border-radius': function() {
+ return {
+ px: ['1px', '10px'],
+ "px-px": ['1px 3px', '10px 13px']
+ };
+ },
+ 'image' : function() {
+ var prefix = getValueVendorPrefix('background-image', 'linear-gradient(top, hsl(0, 80%, 70%), #bada55)');
+ return {
+ // Chrome implements this
+ url: ['url(support/one.gif)', 'url(support/two.gif)'],
+ data: ['url(data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=)', 'url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==)'],
+ // A hunch, as from the spec:
+ // http://www.w3.org/TR/css3-transitions/#animatable-types
+ // gradient: interpolated via the positions and colors of each stop. They must have the same type (radial or linear) and same number of stops in order to be animated. Note: [CSS3-IMAGES] may extend this definition.
+ gradient: [prefix + 'linear-gradient(top, hsl(0, 80%, 70%), #bada55)', prefix + 'linear-gradient(top, #bada55, hsl(0, 80%, 70%))']
+ };
+ },
+ 'background-size': function() {
+ return {
+ keyword: ['cover', 'contain']
+ };
+ },
+ 'box-shadow': function() {
+ // http://www.w3.org/TR/css3-background/#ltshadowgt
+ return {
+ shadow: ['60px -16px teal', '60px -16px red']
+ };
+ },
+ 'vertical': function() {
+ return {
+ keyword: ['top', 'bottom']
+ };
+ },
+ 'horizontal': function() {
+ return {
+ keyword: ['left', 'right']
+ };
+ },
+ 'font-stretch': function() {
+ return {
+ keyword: ['condensed', 'expanded']
+ };
+ },
+ 'transform': function() {
+ return {
+ rotate: ['rotate(10deg)', 'rotate(20deg)']
+ };
+ },
+ 'position': function() {
+ return {
+ 'static to absolute': ['static', 'absolute', {discrete: true}],
+ 'relative to absolute': ['relative', 'absolute', {discrete: true}],
+ 'absolute to fixed': ['absolute', 'fixed', {discrete: true}]
+ };
+ },
+ 'display': function() {
+ return {
+ 'static to absolute': ['none', 'block', {discrete: true}],
+ 'block to inline-block': ['block', 'inline-block', {discrete: true}]
+ };
+ },
+ 'object-view-box': function() {
+ return {
+ inset: ['inset(10% 10% 20% 20%)', 'inset(20% 20% 30% 30%)'],
+ rect: ['rect(10px 20px 30px 40px)', 'rect(20px 30px 40px 50px)'],
+ xywh: ['xywh(10px 20px 30px 40px)', 'xywh(20px 30px 40px 50px)'],
+ };
+ }
+};
+
+/*
+ * Property to Type table
+ * (as stated in specification)
+ */
+var properties = {
+ 'background-color': ['color'],
+ 'background-position': ['length', 'percentage'],
+
+ 'border-top-width': ['length'],
+ 'border-right-width': ['length'],
+ 'border-bottom-width': ['length'],
+ 'border-left-width': ['length'],
+
+ 'border-top-color': ['color'],
+ 'border-right-color': ['color'],
+ 'border-bottom-color': ['color'],
+ 'border-left-color': ['color'],
+
+ 'padding-bottom': ['length'],
+ 'padding-left': ['length'],
+ 'padding-right': ['length'],
+ 'padding-top': ['length'],
+
+ 'margin-bottom': ['length'],
+ 'margin-left': ['length'],
+ 'margin-right': ['length'],
+ 'margin-top': ['length'],
+
+ 'height': ['length', 'percentage'],
+ 'width': ['length', 'percentage'],
+ 'min-height': ['length', 'percentage'],
+ 'min-width': ['length', 'percentage'],
+ 'max-height': ['length', 'percentage'],
+ 'max-width': ['length', 'percentage'],
+
+ 'top': ['length', 'percentage'],
+ 'right': ['length', 'percentage'],
+ 'bottom': ['length', 'percentage'],
+ 'left': ['length', 'percentage'],
+
+ 'color': ['color'],
+ 'font-size': ['length', 'percentage'],
+ 'font-weight': ['font-weight'],
+ 'line-height': ['number', 'length', 'percentage'],
+ 'letter-spacing': ['length'],
+ // Note: percentage is Level3 and not implemented anywhere yet
+ // https://drafts.csswg.org/css3-text/#word-spacing
+ 'word-spacing': ['length', 'percentage'],
+ 'text-indent': ['length', 'percentage'],
+ 'text-shadow': ['shadow'],
+
+ 'outline-color': ['color'],
+ // outline-offset <integer> used to be an error in the spec
+ 'outline-offset': ['length'],
+ 'outline-width': ['length'],
+
+ 'clip': ['rectangle'],
+
+ 'vertical-align': ['length', 'percentage'],
+ 'opacity': ['number[0,1]'],
+ 'visibility': ['visibility'],
+ 'z-index': ['integer']
+};
+
+/*
+ * Property to Type table
+ * (missing value-types of specified properties)
+ */
+var missing_properties = {
+ 'margin-bottom': ['percentage'],
+ 'margin-left': ['percentage'],
+ 'margin-right': ['percentage'],
+ 'margin-top': ['percentage'],
+ 'padding-bottom': ['percentage'],
+ 'padding-left': ['percentage'],
+ 'padding-right': ['percentage'],
+ 'padding-top': ['percentage'],
+ 'vertical-align': ['vertical']
+};
+
+/*
+ * Property to Type table
+ * (properties that haven't been specified but implemented)
+ */
+var unspecified_properties = {
+ // http://oli.jp/2010/css-animatable-properties/
+ 'border-top-left-radius': ['border-radius'],
+ 'border-top-right-radius': ['border-radius'],
+ 'border-bottom-left-radius': ['border-radius'],
+ 'border-bottom-right-radius': ['border-radius'],
+ 'background-image': ['image'],
+ 'background-size': ['background-size'],
+ // https://drafts.csswg.org/css3-background/#the-box-shadow
+ // Animatable: yes, except between inner and outer shadows (Transition to/from an absent shadow is a transition to/from ‘0 0 transparent’ or ‘0 0 transparent inset’, as appropriate.)
+ 'box-shadow': ['box-shadow'],
+ 'font-size-adjust': ['number'],
+ 'font-stretch': ['font-stretch'],
+ 'text-decoration-color': ['color'],
+ 'column-count': ['integer'],
+ 'column-gap': ['length'],
+ 'column-rule-color': ['color'],
+ 'column-rule-width': ['length'],
+ 'column-width': ['length'],
+ 'transform': ['transform'],
+ 'transform-origin': ['horizontal'],
+ 'display': ['display'],
+ 'position': ['position'],
+ 'object-view-box': ['object-view-box']
+};
+
+/*
+ * additional styles required to actually render
+ * (different browsers expect different environment)
+ */
+var additional_styles = {
+ // all browsers
+ 'border-top-width': {'border-top-style' : 'solid'},
+ 'border-right-width': {'border-right-style' : 'solid'},
+ 'border-bottom-width': {'border-bottom-style' : 'solid'},
+ 'border-left-width': {'border-left-style' : 'solid'},
+ 'top': {'position': 'absolute'},
+ 'right': {'position': 'absolute'},
+ 'bottom': {'position': 'absolute'},
+ 'left': {'position': 'absolute'},
+ 'z-index': {'position': 'absolute'},
+ 'outline-offset': {'outline-style': 'solid'},
+ 'outline-width': {'outline-style': 'solid'},
+ 'word-spacing': {'width': '100px', 'height': '100px'},
+ // unspecified properties
+ 'column-rule-width': {'column-rule-style': 'solid'},
+ 'position': {'width': '50px', 'height': '50px', top: '10px', left: '50px'}
+};
+
+/*
+ * additional styles required *on the parent* to actually render
+ * (different browsers expect different environment)
+ */
+var parent_styles = {
+ 'border-top-width': {'border-top-style' : 'solid'},
+ 'border-right-width': {'border-right-style' : 'solid'},
+ 'border-bottom-width': {'border-bottom-style' : 'solid'},
+ 'border-left-width': {'border-left-style' : 'solid'},
+ 'height': {'width': '100px', 'height': '100px'},
+ 'min-height': {'width': '100px', 'height': '100px'},
+ 'max-height': {'width': '100px', 'height': '100px'},
+ 'width': {'width': '100px', 'height': '100px'},
+ 'min-width': {'width': '100px', 'height': '100px'},
+ 'max-width': {'width': '100px', 'height': '100px'},
+ // unspecified properties
+ 'position': {'position': 'relative', 'width': '100px', 'height': '100px'},
+ // inheritance tests
+ 'top': {'width': '100px', 'height': '100px', 'position': 'relative'},
+ 'right': {'width': '100px', 'height': '100px', 'position': 'relative'},
+ 'bottom': {'width': '100px', 'height': '100px', 'position': 'relative'},
+ 'left': {'width': '100px', 'height': '100px', 'position': 'relative'}
+};
+
+
+function assemble(props) {
+ var tests = [];
+
+ // assemble tests
+ for (var property in props) {
+ props[property].forEach(function(type) {
+ var _values = values[type](property);
+ Object.keys(_values).forEach(function(unit) {
+ var data = {
+ name: property + ' ' + type + '(' + unit + ')',
+ property: property,
+ valueType : type,
+ unit : unit,
+ parentStyle: extend({}, parent_styles[property] || {}),
+ from: extend({}, additional_styles[property] || {}),
+ to: {}
+ };
+
+ data.from[property] = _values[unit][0];
+ data.to[property] = _values[unit][1];
+ data.flags = _values[unit][2] || {};
+
+ tests.push(data);
+ });
+ });
+ }
+
+ return tests;
+}
+
+root.getPropertyTests = function() {
+ return assemble(properties);
+};
+
+root.getMissingPropertyTests = function() {
+ return assemble(missing_properties);
+};
+
+root.getUnspecifiedPropertyTests = function() {
+ return assemble(unspecified_properties);
+};
+
+root.getFontSizeRelativePropertyTests = function() {
+ var accepted = {};
+
+ for (var key in properties) {
+ if (!Object.prototype.hasOwnProperty.call(properties, key) || key === "font-size") {
+ continue;
+ }
+
+ if (properties[key].indexOf('length') > -1) {
+ accepted[key] = ['length-em'];
+ }
+ }
+
+ return assemble(accepted);
+};
+
+root.filterPropertyTests = function(tests, names) {
+ var allowed = {};
+ var accepted = [];
+
+ if (typeof names === "string") {
+ names = [names];
+ }
+
+ if (!(names instanceof RegExp)) {
+ names.forEach(function(name) {
+ allowed[name] = true;
+ });
+ }
+
+ tests.forEach(function(test) {
+ if (names instanceof RegExp) {
+ if (!test.name.match(names)) {
+ return;
+ }
+ } else if (!allowed[test.name]) {
+ return;
+ }
+
+ accepted.push(test);
+ });
+
+ return accepted;
+};
+
+})(window);
diff --git a/testing/web-platform/tests/css/css-transitions/support/ruler-h-50%.png b/testing/web-platform/tests/css/css-transitions/support/ruler-h-50%.png
new file mode 100644
index 0000000000..cf2eea6b43
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/support/ruler-h-50%.png
Binary files differ
diff --git a/testing/web-platform/tests/css/css-transitions/support/ruler-h-50px.png b/testing/web-platform/tests/css/css-transitions/support/ruler-h-50px.png
new file mode 100644
index 0000000000..9f46583665
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/support/ruler-h-50px.png
Binary files differ
diff --git a/testing/web-platform/tests/css/css-transitions/support/ruler-v-100px.png b/testing/web-platform/tests/css/css-transitions/support/ruler-v-100px.png
new file mode 100644
index 0000000000..a837eca222
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/support/ruler-v-100px.png
Binary files differ
diff --git a/testing/web-platform/tests/css/css-transitions/support/ruler-v-50px.png b/testing/web-platform/tests/css/css-transitions/support/ruler-v-50px.png
new file mode 100644
index 0000000000..8414102802
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/support/ruler-v-50px.png
Binary files differ
diff --git a/testing/web-platform/tests/css/css-transitions/support/runParallelAsyncHarness.js b/testing/web-platform/tests/css/css-transitions/support/runParallelAsyncHarness.js
new file mode 100644
index 0000000000..de9b783790
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/support/runParallelAsyncHarness.js
@@ -0,0 +1,148 @@
+(function(root){
+'use strict';
+// testharness doesn't know about async test queues,
+// so this wrapper takes care of that
+
+/* USAGE:
+ runParallelAsyncHarness({
+ // list of data to test, must be array of objects.
+ // each object must contain a "name" property to describe the test
+ // besides name, the object can contain whatever data you need
+ tests: [
+ {name: "name of test 1", custom: "data"},
+ {name: "name of test 2", custom: "data"},
+ // ...
+ ],
+
+ // number of tests (tests, not test-cases!) to run concurrently
+ testsPerSlice: 100,
+
+ // time in milliseconds a test-run takes
+ duration: 1000,
+
+ // test-cases to run for for the test - there must be at least one
+ // each case creates its separate async_test() instance
+ cases: {
+ // test case named "test1"
+ test1: {
+ // run as a async_test.step() this callback contains your primary assertions
+ start: function(testCaseKey, data, options){},
+ // run as a async_test.step() this callback contains assertions to be run
+ // when the test ended, immediately before teardown
+ done: function(testCaseKey, data, options){}
+ },
+ // ...
+ }
+
+ // all callbacks are optional:
+
+ // invoked for individual test before it starts so you can setup the environment
+ // like DOM, CSS, adding event listeners and such
+ setup: function(data, options){},
+
+ // invoked after a test ended, so you can clean up the environment
+ // like DOM, CSS, removing event listeners and such
+ teardown: function(data, options){},
+
+ // invoked before a batch of tests ("slice") are run concurrently
+ // tests is an array of test data objects
+ sliceStart: function(options, tests)
+
+ // invoked after a batch of tests ("slice") were run concurrently
+ // tests is an array of test data objects
+ sliceDone: function(options, tests)
+
+ // invoked once all tests are done
+ done: function(options){}
+ })
+*/
+root.runParallelAsyncHarness = function(options) {
+ if (!options.cases) {
+ throw new Error("Options don't contain test cases!");
+ }
+
+ var noop = function(){};
+
+ // add a 100ms buffer to the test timeout, just in case
+ var duration = Math.ceil(options.duration + 100);
+
+ // names of individual tests
+ var cases = Object.keys(options.cases);
+
+ // run tests in a batch of slices
+ // primarily not to overload weak devices (tablets, phones, …)
+ // with too many tests running simultaneously
+ var iteration = -1;
+ var testPerSlice = options.testsPerSlice || 100;
+ var slices = Math.ceil(options.tests.length / testPerSlice);
+
+ // initialize all async test cases
+ // Note: satisfying testharness.js needs to know all async tests before load-event
+ options.tests.forEach(function(data, index) {
+ data.cases = {};
+ cases.forEach(function(name) {
+ data.cases[name] = async_test(data.name + " / " + name);
+ });
+ });
+
+ function runLoop() {
+ iteration++;
+ if (iteration >= slices) {
+ // no more slice, we're done
+ (options.done || noop)(options);
+ return;
+ }
+
+ // grab a slice of testss and initialize them
+ var offset = iteration * testPerSlice;
+ var tests = options.tests.slice(offset, offset + testPerSlice);
+ tests.forEach(function(data) {
+ (options.setup || noop)(data, options);
+
+ });
+
+ // kick off the current slice of tests
+ (options.sliceStart || noop)(options, tests);
+
+ // perform individual "start" test-case
+ tests.forEach(function(data) {
+ cases.forEach(function(name) {
+ data.cases[name].step(function() {
+ (options.cases[name].start || noop)(data.cases[name], data, options);
+ });
+ });
+ });
+
+ // conclude slice (possibly abort)
+ var concludeSlice = function() {
+ tests.forEach(function(data) {
+ // perform individual "done" test-case
+ cases.forEach(function(name) {
+ data.cases[name].step(function() {
+ (options.cases[name].done || noop)(data.cases[name], data, options);
+ });
+ });
+ // clean up after individual test
+ (options.teardown || noop)(data, options);
+ // tell harness we're done with individual test-cases
+ cases.forEach(function(name) {
+ data.cases[name].done();
+ });
+ });
+
+ // finish the test for current slice of tests
+ (options.sliceDone || noop)(options, tests);
+
+ // next test please, give the browser 50ms to do catch its breath
+ setTimeout(runLoop, 50);
+ }
+
+ // wait on RAF before cleanup to make sure all queued event handlers have run
+ setTimeout(function() {requestAnimationFrame(concludeSlice)},duration);
+ }
+
+ // allow DOMContentLoaded before actually doing something
+ setTimeout(runLoop, 100);
+};
+
+})(window);
diff --git a/testing/web-platform/tests/css/css-transitions/support/square-purple.png b/testing/web-platform/tests/css/css-transitions/support/square-purple.png
new file mode 100644
index 0000000000..0f522d7872
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/support/square-purple.png
Binary files differ
diff --git a/testing/web-platform/tests/css/css-transitions/support/square-teal.png b/testing/web-platform/tests/css/css-transitions/support/square-teal.png
new file mode 100644
index 0000000000..e567f51b91
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/support/square-teal.png
Binary files differ
diff --git a/testing/web-platform/tests/css/css-transitions/support/square-white.png b/testing/web-platform/tests/css/css-transitions/support/square-white.png
new file mode 100644
index 0000000000..5853cbb238
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/support/square-white.png
Binary files differ
diff --git a/testing/web-platform/tests/css/css-transitions/support/support/README b/testing/web-platform/tests/css/css-transitions/support/support/README
new file mode 100644
index 0000000000..ea8cb9ef35
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/support/support/README
@@ -0,0 +1,4 @@
+The swatch-green.png file in this directory is really a RED swatch,
+and the swatch-red.png file is really a green swatch.
+
+This directory is used to test relative URIs. \ No newline at end of file
diff --git a/testing/web-platform/tests/css/css-transitions/support/support/swatch-green.png b/testing/web-platform/tests/css/css-transitions/support/support/swatch-green.png
new file mode 100644
index 0000000000..1caf25c992
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/support/support/swatch-green.png
Binary files differ
diff --git a/testing/web-platform/tests/css/css-transitions/support/support/swatch-red.png b/testing/web-platform/tests/css/css-transitions/support/support/swatch-red.png
new file mode 100644
index 0000000000..0aa79b0c86
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/support/support/swatch-red.png
Binary files differ
diff --git a/testing/web-platform/tests/css/css-transitions/support/swatch-blue.png b/testing/web-platform/tests/css/css-transitions/support/swatch-blue.png
new file mode 100644
index 0000000000..bf2759634d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/support/swatch-blue.png
Binary files differ
diff --git a/testing/web-platform/tests/css/css-transitions/support/swatch-green.png b/testing/web-platform/tests/css/css-transitions/support/swatch-green.png
new file mode 100644
index 0000000000..0aa79b0c86
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/support/swatch-green.png
Binary files differ
diff --git a/testing/web-platform/tests/css/css-transitions/support/swatch-lime.png b/testing/web-platform/tests/css/css-transitions/support/swatch-lime.png
new file mode 100644
index 0000000000..55fd7fdaed
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/support/swatch-lime.png
Binary files differ
diff --git a/testing/web-platform/tests/css/css-transitions/support/swatch-orange.png b/testing/web-platform/tests/css/css-transitions/support/swatch-orange.png
new file mode 100644
index 0000000000..d3cd498b52
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/support/swatch-orange.png
Binary files differ
diff --git a/testing/web-platform/tests/css/css-transitions/support/swatch-red.png b/testing/web-platform/tests/css/css-transitions/support/swatch-red.png
new file mode 100644
index 0000000000..1caf25c992
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/support/swatch-red.png
Binary files differ
diff --git a/testing/web-platform/tests/css/css-transitions/support/swatch-teal.png b/testing/web-platform/tests/css/css-transitions/support/swatch-teal.png
new file mode 100644
index 0000000000..0293ce89de
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/support/swatch-teal.png
Binary files differ
diff --git a/testing/web-platform/tests/css/css-transitions/support/swatch-white.png b/testing/web-platform/tests/css/css-transitions/support/swatch-white.png
new file mode 100644
index 0000000000..1a7d4323d7
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/support/swatch-white.png
Binary files differ
diff --git a/testing/web-platform/tests/css/css-transitions/support/swatch-yellow.png b/testing/web-platform/tests/css/css-transitions/support/swatch-yellow.png
new file mode 100644
index 0000000000..1591aa0e2e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/support/swatch-yellow.png
Binary files differ
diff --git a/testing/web-platform/tests/css/css-transitions/support/test-bl.png b/testing/web-platform/tests/css/css-transitions/support/test-bl.png
new file mode 100644
index 0000000000..904e24e996
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/support/test-bl.png
Binary files differ
diff --git a/testing/web-platform/tests/css/css-transitions/support/test-br.png b/testing/web-platform/tests/css/css-transitions/support/test-br.png
new file mode 100644
index 0000000000..f413ff5c1a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/support/test-br.png
Binary files differ
diff --git a/testing/web-platform/tests/css/css-transitions/support/test-inner-half-size.png b/testing/web-platform/tests/css/css-transitions/support/test-inner-half-size.png
new file mode 100644
index 0000000000..e473bf80ef
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/support/test-inner-half-size.png
Binary files differ
diff --git a/testing/web-platform/tests/css/css-transitions/support/test-outer.png b/testing/web-platform/tests/css/css-transitions/support/test-outer.png
new file mode 100644
index 0000000000..82eeace7fc
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/support/test-outer.png
Binary files differ
diff --git a/testing/web-platform/tests/css/css-transitions/support/test-tl.png b/testing/web-platform/tests/css/css-transitions/support/test-tl.png
new file mode 100644
index 0000000000..f6ac0ef7e8
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/support/test-tl.png
Binary files differ
diff --git a/testing/web-platform/tests/css/css-transitions/support/test-tr.png b/testing/web-platform/tests/css/css-transitions/support/test-tr.png
new file mode 100644
index 0000000000..59843ae54b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/support/test-tr.png
Binary files differ
diff --git a/testing/web-platform/tests/css/css-transitions/support/two.gif b/testing/web-platform/tests/css/css-transitions/support/two.gif
new file mode 100644
index 0000000000..01435c8020
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/support/two.gif
Binary files differ
diff --git a/testing/web-platform/tests/css/css-transitions/support/vendorPrefix.js b/testing/web-platform/tests/css/css-transitions/support/vendorPrefix.js
new file mode 100644
index 0000000000..1e7eed0481
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/support/vendorPrefix.js
@@ -0,0 +1,86 @@
+//
+// Vendor-Prefix Helper Functions For Testing CSS
+//
+
+(function(root) {
+'use strict';
+
+var prefixCache = {};
+
+// convert "foo-bar" to "fooBar"
+function camelCase(str) {
+ return str.replace(/\-(\w)/g, function(match, letter){
+ return letter.toUpperCase();
+ });
+}
+
+// vendor-prefix a css property
+root.addVendorPrefix = function (name) {
+ var prefix = getVendorPrefix(name);
+ if (prefix === false) {
+ // property unknown to browser
+ return name;
+ }
+
+ return prefix + name;
+};
+
+// vendor-prefix a css property value
+root.addValueVendorPrefix = function (property, value) {
+ var prefix = getValueVendorPrefix(property, value);
+ if (prefix === false) {
+ // property unknown to browser
+ return name;
+ }
+
+ return prefix + value;
+};
+
+// identify vendor-prefix for css property
+root.getVendorPrefix = function(name) {
+ if (prefixCache[name] !== undefined) {
+ return prefixCache[name];
+ }
+
+ var elem = document.createElement("div");
+ name = camelCase(name);
+
+ if (name in elem.style) {
+ return prefixCache[name] = "";
+ }
+
+ var prefixes = ["Webkit", "Moz", "O", "ms"];
+ var styles = ["-webkit-", "-moz-", "-o-", "-ms-"];
+ var _name = name.substring(0, 1).toUpperCase() + name.substring(1);
+
+ for (var i = 0, length = prefixes.length; i < length; i++) {
+ if (prefixes[i] + _name in elem.style) {
+ return prefixCache[name] = styles[i];
+ }
+ }
+
+ return prefixCache[name] = name in elem.style ? "" : false;
+};
+
+// identify vendor-prefix for css property value
+root.getValueVendorPrefix = function(property, value) {
+ var elem = document.createElement("div");
+ // note: webkit needs the element to be attached to the dom
+ document.body.appendChild(elem);
+ var styles = ["-webkit-", "-moz-", "-o-", "-ms-", ""];
+ var _property = getVendorPrefix(property) + property;
+ for (var i=0, length = styles.length; i < length; i++) {
+ var _value = styles[i] + value;
+ elem.setAttribute('style', _property + ": " + _value);
+ var _computed = computedStyle(elem, _property);
+ if (_computed && _computed !== 'none') {
+ document.body.removeChild(elem);
+ return styles[i];
+ }
+ }
+ document.body.removeChild(elem);
+ return false;
+};
+
+
+})(window);
diff --git a/testing/web-platform/tests/css/css-transitions/transition-001.html b/testing/web-platform/tests/css/css-transitions/transition-001.html
new file mode 100644
index 0000000000..492b443747
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-001.html
@@ -0,0 +1,63 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>CSS Transitions Test: Parsing transition shorthand</title>
+ <meta name="assert" content="Test checks that transition shorthand values are parsed properly">
+ <link rel="help" title="2.5. The 'transition' Shorthand Property" href="http://www.w3.org/TR/css3-transitions/#transition-shorthand-property">
+ <link rel="author" title="Rodney Rehm" href="http://rodneyrehm.de/en/">
+ <meta name="flags" content="dom">
+
+ <script src="/resources/testharness.js" type="text/javascript"></script>
+ <script src="/resources/testharnessreport.js" type="text/javascript"></script>
+
+ <script src="./support/vendorPrefix.js" type="text/javascript"></script>
+ <script src="./support/helper.js" type="text/javascript"></script>
+ </head>
+ <body>
+ <!-- required by testharnessreport.js -->
+ <div id="log"></div>
+ <!-- elements used for testing -->
+ <div id="container">
+ <div id="transition"></div>
+ </div>
+
+ <script>
+ var transition = document.getElementById('transition');
+ // Note that order is important in this property. The first value that can be parsed as a time is assigned to
+ // the transition-duration. The second value that can be parsed as a time is assigned to transition-delay.
+ // [<‘transition-property’> || <‘transition-duration’> || <‘transition-timing-function’> || <‘transition-delay’> [, [<‘transition-property’> || <‘transition-duration’> || <‘transition-timing-function’> || <‘transition-delay’>]]*
+ var values = {
+ // [property, duration, timing, delay]
+ // random order
+ '1s' : ["all", "1s", "ease", "0s"],
+ '1s 2s' : ["all", "1s", "ease", "2s"],
+ '1s 2s ease-in' : ["all", "1s", "ease-in", "2s"],
+ '1s ease-in 2s' : ["all", "1s", "ease-in", "2s"],
+ 'ease-in 1s 2s' : ["all", "1s", "ease-in", "2s"],
+ '1s width' : ["width", "1s", "ease", "0s"],
+ 'width 1s' : ["width", "1s", "ease", "0s"],
+ '1s width 2s' : ["width", "1s", "ease", "2s"],
+ '1s 2s width ease-in' : ["width", "1s", "ease-in", "2s"],
+ '1s ease-in 2s width' : ["width", "1s", "ease-in", "2s"],
+ 'width ease-in 1s 2s' : ["width", "1s", "ease-in", "2s"],
+ 'width .1s ease-in .2s' : ["width", "0.1s", "ease-in", "0.2s"],
+ '1s width linear(0, .5 10% 20%, 1, .5 50%, 1) 2s' : ["width", "1s", "linear(0 0%, 0.5 10%, 0.5 20%, 1 35%, 0.5 50%, 1 100%)", "2s"]};
+
+ for (var key in values) {
+ if (Object.prototype.hasOwnProperty.call(values, key)) {
+ test(function() {
+ setStyle('#transition', {
+ 'transition': key
+ });
+ // WET much?
+ assert_equals(computedStyle(transition, 'transition-property'), values[key][0], "transition-property");
+ assert_equals(computedStyle(transition, 'transition-duration'), values[key][1], "transition-duration");
+ assert_equals(computedStyle(transition, 'transition-timing-function'), values[key][2], "transition-timing-function");
+ assert_equals(computedStyle(transition, 'transition-delay'), values[key][3], "transition-delay");
+ }, "parse '" + key + "'");
+ }
+ }
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-after-animation-001.html b/testing/web-platform/tests/css/css-transitions/transition-after-animation-001.html
new file mode 100644
index 0000000000..13f9f0800b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-after-animation-001.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<title>Starting transition after animation has ended</title>
+<link rel="help" href="https://drafts.csswg.org/css-transitions/">
+<link rel="help" href="https://crbug.com/1261155">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="./support/helper.js"></script>
+<style>
+ @keyframes anim {
+ from { left: 100px }
+ to { left: 200px }
+ }
+ #div {
+ left: 0px;
+ position: relative;
+ width: 50px;
+ height: 50px;
+ background-color: green;
+ }
+ #div.animate {
+ animation: anim 0.1s linear;
+ }
+ #div.transition {
+ left: 300px;
+ transition: left 1000s steps(2, start);
+ }
+</style>
+<div id=div>
+</div>
+<script>
+
+promise_test(async t => {
+ const watcher = new EventWatcher(t, div, ['animationend']);
+
+ assert_equals(getComputedStyle(div).left, '0px');
+
+ div.classList.toggle('animate');
+ assert_equals(getComputedStyle(div).left, '100px');
+
+ await watcher.wait_for('animationend');
+ assert_equals(getComputedStyle(div).left, '0px');
+
+ div.classList.toggle('transition');
+ assert_equals(getComputedStyle(div).left, '150px');
+}, 'Starting transition after animation has ended');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-background-position-with-edge-offset.html b/testing/web-platform/tests/css/css-transitions/transition-background-position-with-edge-offset.html
new file mode 100644
index 0000000000..4ac115e17d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-background-position-with-edge-offset.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Transitions Test: transition-property - background-position</title>
+<link rel="author" title="Zhuoyu Qian" href="mailto:zhuoyu.qian@samsung.com">
+<link rel="help" href="https://drafts.csswg.org/web-animations-1/#animation-type">
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#background-position">
+<meta name="assert" content="Test checks that the 'background-position' property with edge offset is animatable.">
+<script src="/resources/testharness.js" type="text/javascript"></script>
+<script src="/resources/testharnessreport.js" type="text/javascript"></script>
+<style>
+ #test {
+ border: 1px solid;
+ background-image: url("support/cat.png");
+ background-repeat: no-repeat;
+ height: 200px;
+ transition-duration: 100s;
+ transition-property: background-position;
+ transition-timing-function: step-end;
+ }
+</style>
+<body>
+ <div id="test"></div>
+</body>
+<script>
+var startValue = "left 10px top 10px";
+var endValue = "right 10px bottom 10px";
+var div = document.getElementById("test");
+
+// getComputedStyle helper
+function gCS(aProperty) {
+ return document.defaultView
+ .getComputedStyle(div, "")
+ .getPropertyValue(aProperty);
+}
+
+(function() {
+ div.style.backgroundPosition = startValue;
+
+ // flush styles
+ gCS("background-position");
+
+ // set property to endValue
+ div.setAttribute("style", "background-position: " + endValue);
+
+ test(function() {
+ assert_true(gCS("background-position") != endValue);
+ }, "background-position not equals to end value");
+})();
+</script>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-base-response-001.html b/testing/web-platform/tests/css/css-transitions/transition-base-response-001.html
new file mode 100644
index 0000000000..b4188985ac
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-base-response-001.html
@@ -0,0 +1,74 @@
+<!DOCTYPE html>
+<title>Test that non-transitioned style is responsive to transitioning properties</title>
+<link rel="help" href="https://drafts.csswg.org/css-transitions/">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+ #target1 {
+ transition: font-size steps(2, start) 1000s;
+ font-size: 10px;
+ width: 1em;
+ }
+ #target1.change {
+ font-size: 20px;
+ }
+ #ref1 {
+ width: 15px;
+ }
+
+ #target2 {
+ transition: font-size steps(2, start) 1000s;
+ font-size: 10px;
+ width: 1ex;
+ }
+ #target2.change {
+ font-size: 20px;
+ }
+ #ref2 {
+ font-size: 15px;
+ width: 1ex;
+ }
+
+ #target3 {
+ transition: --x steps(2, start) 1000s;
+ --x: 10px;
+ width: var(--x);
+ }
+ #target3.change {
+ --x: 20px;
+ font-size: 20px;
+ }
+ #ref3 {
+ width: 20px;
+ }
+
+</style>
+<div id="targets">
+ <div id="target1"></div>
+ <div id="target2"></div>
+ <div id="target3"></div>
+</div>
+<div id="refs">
+ <div id="ref1"></div>
+ <div id="ref2"></div>
+ <div id="ref3"></div>
+</div>
+<script>
+
+// Test that the computed value of the given property is equal on
+// 'target' and 'ref', after applying the transition to 'target'.
+function test_ref(target, ref, property, description) {
+ test(() => {
+ let unused = getComputedStyle(target).getPropertyValue(property);
+ target.className = 'change';
+ let actual = getComputedStyle(target).getPropertyValue(property);
+ let expected = getComputedStyle(ref).getPropertyValue(property);
+ assert_equals(actual, expected);
+ }, description);
+}
+
+test_ref(target1, ref1, 'width', 'em units respond to font-size transition');
+test_ref(target2, ref2, 'width', 'ex units respond to font-size transition');
+test_ref(target3, ref3, 'width', 'var() references respond to custom property transition');
+
+</script>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-base-response-002.html b/testing/web-platform/tests/css/css-transitions/transition-base-response-002.html
new file mode 100644
index 0000000000..028723559c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-base-response-002.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<title>Test that rem units are responsive to transitioning font-size on root</title>
+<link rel="help" href="https://drafts.csswg.org/css-transitions/">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+ :root {
+ font-size: 20px;
+ }
+ :root.change {
+ transition: font-size steps(2, start) 10s;
+ font-size: 30px;
+ }
+
+ #target1 {
+ width: 1rem;
+ }
+</style>
+<div id="target1"></div>
+<output id=output></output>
+<script>
+test(() => {
+ let unused = getComputedStyle(document.documentElement).getPropertyValue('font-size');
+ document.documentElement.className = 'change';
+ assert_equals(getComputedStyle(target1).getPropertyValue('width'), '25px');
+}, 'Transitioning font-size on root affects rem units');
+</script>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-base-response-003.html b/testing/web-platform/tests/css/css-transitions/transition-base-response-003.html
new file mode 100644
index 0000000000..045da5dbde
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-base-response-003.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<title>Tests that identical elements in the base style responds to font-size transition</title>
+<link rel="help" href="https://drafts.csswg.org/css-animations/">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+ div {
+ font-size: 10px;
+ min-width: 1em;
+ transition: font-size steps(2, start) 10s;
+ }
+ .change {
+ font-size: 20px;
+ }
+</style>
+<div></div>
+<div></div>
+<div></div>
+<script>
+test(() => {
+ let divs = document.querySelectorAll('div');
+ for (let div of divs) {
+ let unused = getComputedStyle(div).getPropertyValue('min-width');
+ div.className = 'change';
+ assert_equals(getComputedStyle(div).getPropertyValue('min-width'), '15px');
+ }
+}, 'Identical elements are all responsive to font-size transition');
+</script>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-delay-000-manual.html b/testing/web-platform/tests/css/css-transitions/transition-delay-000-manual.html
new file mode 100644
index 0000000000..b205085997
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-delay-000-manual.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Transition Test: transition-delay - positive number</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<link rel="author" title="Shiyou Tan" href="mailto:shiyoux.tan@intel.com">
+<link rel="help" title="2.4. The 'transition-delay' Property" href="http://www.w3.org/TR/css3-transitions/#transition-delay-property">
+<meta name="assert" content="The 'transition-delay' property set positive number to delay the execution of transition">
+<style>
+ #test {
+ background-color: blue;
+ height: 100px;
+ transition-delay: 3s;
+ transition-property: background-color;
+ width: 100px;
+ }
+</style>
+<body>
+ <p>Click the blue square below. Test passes if the <strong>color</strong> of square is changed to <strong>green</strong> immediately
+ when the number inside square is <strong>3</strong>.</p>
+ <div id="test">0</div>
+ <script>
+ var clicked = 0;
+ var div = document.getElementById("test");
+ div.addEventListener("click", function(evt) {
+ if (clicked == 0) {
+ div.setAttribute("style", "background-color: green;");
+ setInterval(function() {
+ clicked++;
+ div.innerHTML = clicked;
+ }, 1000);
+ }
+ }, false);
+ </script>
+</body>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-delay-001.html b/testing/web-platform/tests/css/css-transitions/transition-delay-001.html
new file mode 100644
index 0000000000..8fa5f5825a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-delay-001.html
@@ -0,0 +1,77 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>CSS Transitions Test: Parsing transition-delay</title>
+ <meta name="assert" content="Test checks that transition-delay values are parsed properly">
+ <link rel="help" title="2.4. The 'transition-delay' Property" href="http://www.w3.org/TR/css3-transitions/#transition-delay-property">
+ <link rel="help" title="CSS Values and Units Module Level 3 - 6.2. Times: the ‘<time>’ type and ‘s’, ‘ms’ units" href="http://www.w3.org/TR/css3-values/#time">
+ <link rel="author" title="Rodney Rehm" href="http://rodneyrehm.de/en/">
+ <meta name="flags" content="dom">
+
+ <script src="/resources/testharness.js" type="text/javascript"></script>
+ <script src="/resources/testharnessreport.js" type="text/javascript"></script>
+
+ <script src="./support/vendorPrefix.js" type="text/javascript"></script>
+ <script src="./support/helper.js" type="text/javascript"></script>
+ </head>
+ <body>
+ <!-- required by testharnessreport.js -->
+ <div id="log"></div>
+ <!-- elements used for testing -->
+ <div id="container">
+ <div id="transition"></div>
+ </div>
+
+ <script>
+ var transition = document.getElementById('transition');
+ // <time> [, <time>]*
+ var values = {
+ // seconds
+ '10.2s': '10.2s',
+ '1s': '1s',
+ '0.1s': '0.1s',
+ '0.01s': '0.01s',
+ '0.001s': '0.001s',
+ '0.009s': '0.009s',
+ '0s': '0s',
+ '0s': '0s',
+ '.0s': '0s',
+ '0.0s': '0s',
+ '.3s': '0.3s',
+ '-5s' : '-5s',
+ // milliseconds
+ '10200ms': '10.2s',
+ '1000ms': '1s',
+ '100ms': '0.1s',
+ '10ms': '0.01s',
+ '9ms': '0.009s',
+ '1ms': '0.001s',
+ '0ms': '0s',
+ '-500ms' : '-0.5s',
+ // combination
+ '1s, 0.1s, 10ms': '1s, 0.1s, 0.01s',
+ // invalid
+ 'foobar': '0s'
+ };
+
+ // these tests are supposed to fail and
+ // possibly make the engine issue a parser warning
+ var invalidTests = {
+ 'foobar': true
+ };
+
+ for (var key in values) {
+ if (Object.prototype.hasOwnProperty.call(values, key)) {
+ test(function() {
+ setStyle('#transition', {
+ 'transition-delay': key
+ });
+ var result = computedStyle(transition, 'transition-delay');
+ assert_equals(result, values[key], "Expected computed value");
+ }, "parse '" + key + "'");
+ }
+ }
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-delay-002-manual.html b/testing/web-platform/tests/css/css-transitions/transition-delay-002-manual.html
new file mode 100644
index 0000000000..168f94b9c0
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-delay-002-manual.html
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Transition Test: transition-delay - 0s</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<link rel="author" title="Shiyou Tan" href="mailto:shiyoux.tan@intel.com">
+<link rel="help" title="2.4. The 'transition-delay' Property" href="http://www.w3.org/TR/css3-transitions/#transition-delay-property">
+<meta name="assert" content="Test checks that the 'transition-delay' property set 0 will not delay the execution of transition">
+<style>
+ div {
+ height: 100px;
+ transition-property: background-color;
+ width: 100px;
+ }
+ #ref {
+ background-color: gray;
+ transition-delay: 3s;
+ }
+ #test {
+ background-color: blue;
+ transition-delay: 0s;
+ }
+</style>
+<body>
+ <p>Click the blue square below. Test passes if the <strong>color</strong> of blue and gray squares is all changed to <strong>green</strong> immediately
+ when the number inside blue square is 3.</p>
+ <div id="ref"></div>
+ <div id="test">0</div>
+ <script>
+ var clicked = 0;
+ var ref = document.getElementById("ref");
+ var test = document.getElementById("test");
+ test.addEventListener("click", function(evt) {
+ if (clicked == 0) {
+ ref.setAttribute("style", "background-color: green;");
+ setInterval(function() {
+ if (clicked == 2) {
+ test.setAttribute("style", "background-color: green;");
+ }
+ clicked++;
+ test.innerHTML = clicked;
+ }, 1000);
+ }
+ }, false);
+ </script>
+</body>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-delay-003-manual.html b/testing/web-platform/tests/css/css-transitions/transition-delay-003-manual.html
new file mode 100644
index 0000000000..e3680ca261
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-delay-003-manual.html
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Transition Test: transition-delay - negative number</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<link rel="author" title="Shiyou Tan" href="mailto:shiyoux.tan@intel.com">
+<link rel="help" title="2.4. The 'transition-delay' Property" href="http://www.w3.org/TR/css3-transitions/#transition-delay-property">
+<meta name="assert" content="Test checks that the 'transition-delay' property set negative number will not delay the execution of transition">
+<style>
+ div {
+ height: 100px;
+ transition-property: background-color;
+ width: 100px;
+ }
+ #ref {
+ background-color: gray;
+ transition-delay: 3s;
+ }
+ #test {
+ background-color: blue;
+ transition-delay: -3s;
+ }
+</style>
+<body>
+ <p>Click the blue square below. Test passes if the <strong>color</strong> of blue and gray squares is all changed to <strong>green</strong> immediately
+ when the number inside blue square is 3.</p>
+ <div id="ref"></div>
+ <div id="test">0</div>
+ <script>
+ var clicked = 0;
+ var ref = document.getElementById("ref");
+ var test = document.getElementById("test");
+ test.addEventListener("click", function(evt) {
+ if (clicked == 0) {
+ ref.setAttribute("style", "background-color: green;");
+ setInterval(function() {
+ if (clicked == 2) {
+ test.setAttribute("style", "background-color: green;");
+ }
+ clicked++;
+ test.innerHTML = clicked;
+ }, 1000);
+ }
+ }, false);
+ </script>
+</body>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-duration-001.html b/testing/web-platform/tests/css/css-transitions/transition-duration-001.html
new file mode 100644
index 0000000000..60b9f5fc5c
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-duration-001.html
@@ -0,0 +1,78 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>CSS Transitions Test: Parsing transition-duration</title>
+ <meta name="assert" content="Test checks that transition-duration values are parsed properly">
+ <link rel="help" title="2.2. The 'transition-duration' Property" href="http://www.w3.org/TR/css3-transitions/#transition-duration-property">
+ <link rel="help" title="CSS Values and Units Module Level 3 - 6.2. Times: the ‘<time>’ type and ‘s’, ‘ms’ units" href="http://www.w3.org/TR/css3-values/#time">
+ <link rel="author" title="Rodney Rehm" href="http://rodneyrehm.de/en/">
+ <meta name="flags" content="dom">
+
+ <script src="/resources/testharness.js" type="text/javascript"></script>
+ <script src="/resources/testharnessreport.js" type="text/javascript"></script>
+
+ <script src="./support/vendorPrefix.js" type="text/javascript"></script>
+ <script src="./support/helper.js" type="text/javascript"></script>
+ </head>
+ <body>
+ <!-- required by testharnessreport.js -->
+ <div id="log"></div>
+ <!-- elements used for testing -->
+ <div id="container">
+ <div id="transition"></div>
+ </div>
+
+ <script>
+ var transition = document.getElementById('transition');
+ // <time> [, <time>]*
+ var values = {
+ // seconds
+ '10.2s': '10.2s',
+ '1s': '1s',
+ '0.1s': '0.1s',
+ '0.01s': '0.01s',
+ '0.001s': '0.001s',
+ '0.009s': '0.009s',
+ '0s': '0s',
+ '.0s': '0s',
+ '0.0s': '0s',
+ '.3s': '0.3s',
+ '-5s' : '0s',
+ // milliseconds
+ '10200ms': '10.2s',
+ '1000ms': '1s',
+ '100ms': '0.1s',
+ '10ms': '0.01s',
+ '9ms': '0.009s',
+ '1ms': '0.001s',
+ '0ms': '0s',
+ '-500ms' : '0s',
+ // combination
+ '1s, 0.1s, 10ms': '1s, 0.1s, 0.01s',
+ // invalid
+ 'foobar': '0s'
+ };
+
+ // these tests are supposed to fail and
+ // possibly make the engine issue a parser warning
+ var invalidTests = {
+ '-5s': true,
+ '-500ms': true,
+ 'foobar': true
+ };
+
+ for (var key in values) {
+ if (Object.prototype.hasOwnProperty.call(values, key)) {
+ test(function() {
+ setStyle('#transition', {
+ 'transition-duration': key
+ });
+ var result = computedStyle(transition, 'transition-duration');
+ assert_equals(result, values[key], "Expected computed value");
+ }, "parse '" + key + "'");
+ }
+ }
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-duration-002-manual.html b/testing/web-platform/tests/css/css-transitions/transition-duration-002-manual.html
new file mode 100644
index 0000000000..03f514d365
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-duration-002-manual.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Transitions Test: transition-duration - positive number</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<link rel="author" title="Shiyou Tan" href="mailto:shiyoux.tan@intel.com">
+<link rel="help" title="2.2. The 'transition-duration' Property" href="http://www.w3.org/TR/css3-transitions/#transition-duration-property">
+<meta name="assert" content="The 'transition-duration' property set positive number specifies the time that transition from the old value to the new value should take.">
+<style>
+ div {
+ background-color: yellow;
+ height: 100px;
+ transition-duration: 2s;
+ transition-property: width;
+ transition-timing-function: linear;
+ width: 100px;
+ }
+</style>
+<body>
+ <p>Click the yellow square below. Test passes if the width of square stops growing when the number inside square is '2'.</p>
+ <div>0</div>
+ <script>
+ (function() {
+ var div = document.querySelector("div");
+ div.addEventListener("click", function(evt) {
+ div.setAttribute("style", "width: 200px;");
+ setInterval(function() {
+ var timer = parseInt(div.textContent, 10);
+ timer++;
+ div.textContent = timer;
+ }, 1000);
+ }, false);
+ })();
+ </script>
+</body>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-duration-003-manual.html b/testing/web-platform/tests/css/css-transitions/transition-duration-003-manual.html
new file mode 100644
index 0000000000..cb56100883
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-duration-003-manual.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Transitions Test: transition-duration - 0s(initial value)</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<link rel="author" title="Shiyou Tan" href="mailto:shiyoux.tan@intel.com">
+<link rel="help" title="2.2. The 'transition-duration' Property" href="http://www.w3.org/TR/css3-transitions/#transition-duration-property">
+<meta name="assert" content="Test checks that the initial value of 'transition-duration' property is '0s' which means the transition is immediate.">
+<style>
+ div {
+ height: 100px;
+ transition-property: width;
+ transition-timing-function: linear;
+ width: 100px;
+ }
+ #ref1 {
+ background-color: yellow;
+ transition-duration: 2s;
+ }
+ #ref2 {
+ background-color: gray;
+ transition-duration: 0s;
+ }
+ #test {
+ background-color: blue;
+ }
+</style>
+<body>
+ <p>Click the 'Start' button below. Test passes if the width of yellow square grows smoothly but the gray and blue grow immediately.</p>
+ <div id="ref1"></div>
+ <div id="ref2"></div>
+ <div id="test"></div>
+ <button>Start</button>
+ <script>
+ (function() {
+ var button = document.querySelector("button"),
+ test = document.querySelector("#test"),
+ ref1 = document.querySelector("#ref1"),
+ ref2 = document.querySelector("#ref2")
+ button.addEventListener("click", function(evt) {
+ test.setAttribute("style", "width: 300px;");
+ ref1.setAttribute("style", "width: 300px;");
+ ref2.setAttribute("style", "width: 300px;");
+ }, false);
+ })();
+ </script>
+</body>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-duration-004-manual.html b/testing/web-platform/tests/css/css-transitions/transition-duration-004-manual.html
new file mode 100644
index 0000000000..b93904bb76
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-duration-004-manual.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Transitions Test: transition-duration - negative number</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<link rel="author" title="Shiyou Tan" href="mailto:shiyoux.tan@intel.com">
+<link rel="help" title="2.2. The 'transition-duration' Property" href="http://www.w3.org/TR/css3-transitions/#transition-duration-property">
+<meta name="assert" content="A negative value for 'transition-duration renders the declaration invalid which means the transition is immediate.">
+<style>
+ div {
+ height: 100px;
+ transition-property: width;
+ transition-timing-function: linear;
+ width: 100px;
+ }
+ #ref {
+ background-color: yellow;
+ transition-duration: 2s;
+ }
+ #test {
+ background-color: blue;
+ transition-duration: -2s;
+ }
+</style>
+<body>
+ <p>Click the 'Start' button below. Test passes if the width of yellow square grows smoothly but the blue grows immediately.</p>
+ <div id="ref"></div>
+ <div id="test"></div>
+ <button>Start</button>
+ <script>
+ (function() {
+ var button = document.querySelector("button"),
+ test = document.querySelector("#test"),
+ ref = document.querySelector("#ref");
+ button.addEventListener("click", function(evt) {
+ test.setAttribute("style", "width: 200px;");
+ ref.setAttribute("style", "width: 200px;");
+ }, false);
+ })();
+ </script>
+</body>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-duration-shorthand.html b/testing/web-platform/tests/css/css-transitions/transition-duration-shorthand.html
new file mode 100644
index 0000000000..181d52b388
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-duration-shorthand.html
@@ -0,0 +1,39 @@
+<!doctype html>
+<link rel="help" href="https://drafts.csswg.org/css-transitions/#transition-duration-property">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1650189">
+<link rel="author" href="http://mellthas.de" title="Till Berger">
+<link rel="author" href="https://mozilla.org" title="Mozilla">
+<link rel="author" href="mailto:emilio@crisal.io" title="Emilio Cobos Álvarez">
+<script src="/resources/testharness.js" type="text/javascript"></script>
+<script src="/resources/testharnessreport.js" type="text/javascript"></script>
+<title>transition-duration when looking at shorthand properties should be correct</title>
+<style>
+ div {
+ width: 100px;
+ height: 100px;
+ background-color: green;
+ transition: all 100s, height 0s;
+ }
+ div.trigger {
+ width: 200px;
+ height: 200px;
+ }
+</style>
+<div></div>
+<script>
+ promise_test(async function (t) {
+ let div = document.querySelector("div");
+ let cs = getComputedStyle(div);
+ assert_equals(cs.width, "100px", "Width should start off correct");
+ assert_equals(cs.height, "100px", "Height should start off correct");
+
+ div.classList.add("trigger");
+
+ await new Promise(resolve => {
+ requestAnimationFrame(() => requestAnimationFrame(resolve));
+ });
+
+ assert_not_equals(cs.width, "200px", "Width should not have advanced to the end of the transition right away");
+ assert_equals(cs.height, "200px", "Height should have advanced to the end of the transition right away");
+ });
+</script>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-events-with-document-change.html b/testing/web-platform/tests/css/css-transitions/transition-events-with-document-change.html
new file mode 100644
index 0000000000..fdc8b9340e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-events-with-document-change.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<title>CSS Transitions: transition events for an element changing document</title>
+<link rel="help" href="https://drafts.csswg.org/css-transitions">
+<script src="/resources/testharness.js" type="text/javascript"></script>
+<script src="/resources/testharnessreport.js" type="text/javascript"></script>
+<div id="target"></div>
+<iframe src="about:blank"></iframe>
+<script>
+promise_test(async () => {
+ await new Promise(r => window.addEventListener("load", r));
+
+ const target = document.getElementById("target");
+ target.style.transition = "margin-left 100ms";
+
+ const transitionMarginLeft = async value => {
+ getComputedStyle(target).marginLeft;
+ target.style.marginLeft = value;
+ await target.getAnimations()[0].ready;
+ }
+
+ // start an initial transition.
+ await transitionMarginLeft("100px");
+
+ // move the target to new frame, this should cancel the transition.
+ const transitionWasCanceled = new Promise(resolve => target.addEventListener("transitioncancel", resolve, { once: true }));
+ document.querySelector("iframe").contentDocument.body.appendChild(target);
+ await transitionWasCanceled;
+
+ // Start a new transition and ensure it triggers a transitionend event.
+ const transitionEnded = new Promise(resolve => target.addEventListener("transitionend", resolve, { once: true }));
+ await transitionMarginLeft("0px");
+ await transitionEnded;
+}, "transition events for an element changing document");
+</script>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-important.html b/testing/web-platform/tests/css/css-transitions/transition-important.html
new file mode 100644
index 0000000000..cae14369ba
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-important.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<title>CSS Transitions Test: !important property</title>
+<link rel="help" href="https://drafts.csswg.org/css-cascade-5/#cascade-sort">
+<script src="/resources/testharness.js" type="text/javascript"></script>
+<script src="/resources/testharnessreport.js" type="text/javascript"></script>
+<style>
+#target {
+ width: 200px;
+ height: 200px;
+ background-color: green;
+ transition: background-color 100s;
+}
+.red {
+ background-color: red !important;
+}
+</style>
+<div id="target"></div>
+<script>
+test(t => {
+ assert_equals(getComputedStyle(target).backgroundColor, "rgb(0, 128, 0)");
+ target.className = "red";
+ assert_equals(getComputedStyle(target).backgroundColor, "rgb(0, 128, 0)");
+}, "!important should not override transition");
+</script>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-property-001.html b/testing/web-platform/tests/css/css-transitions/transition-property-001.html
new file mode 100644
index 0000000000..47a1417070
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-property-001.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>CSS Transitions Test: Parsing transition-property</title>
+ <meta name="assert" content="Test checks that transition-property values are parsed properly">
+ <link rel="help" title="2.1. The 'transition-property' Property" href="http://www.w3.org/TR/css3-transitions/#transition-property-property">
+ <link rel="author" title="Rodney Rehm" href="http://rodneyrehm.de/en/">
+ <meta name="flags" content="dom">
+
+ <script src="/resources/testharness.js" type="text/javascript"></script>
+ <script src="/resources/testharnessreport.js" type="text/javascript"></script>
+
+ <script src="./support/vendorPrefix.js" type="text/javascript"></script>
+ <script src="./support/helper.js" type="text/javascript"></script>
+ </head>
+ <body>
+ <!-- required by testharnessreport.js -->
+ <div id="log"></div>
+ <!-- elements used for testing -->
+ <div id="container">
+ <div id="transition"></div>
+ </div>
+
+ <script>
+ var transition = document.getElementById('transition');
+
+ // syntax: none | [ all | <IDENT> ] [ ‘,’ [ all | <IDENT> ] ]*
+ var values = [
+ 'none', 'all', 'width', 'all, width', 'width, all'
+ ];
+
+ for (var i = 0, value; value = values[i]; i++) {
+ test(function() {
+ setStyle('#transition', {
+ 'transition-property': value
+ });
+ var result = computedStyle(transition, 'transition-property');
+ assert_equals(result, value);
+ }, "parse '" + value + "'");
+ }
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-property-002.html b/testing/web-platform/tests/css/css-transitions/transition-property-002.html
new file mode 100644
index 0000000000..2a46b3e284
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-property-002.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>CSS Transitions Test: Parsing invalid transition-property</title>
+ <meta name="assert" content="Test checks that unrecognized or non-animatable properties must be kept in the list to preserve the matching of indices.">
+ <link rel="help" title="2.1. The 'transition-property' Property" href="http://www.w3.org/TR/css3-transitions/#transition-property-property">
+ <link rel="author" title="Rodney Rehm" href="http://rodneyrehm.de/en/">
+ <meta name="flags" content="dom ">
+
+ <script src="/resources/testharness.js" type="text/javascript"></script>
+ <script src="/resources/testharnessreport.js" type="text/javascript"></script>
+
+ <script src="./support/vendorPrefix.js" type="text/javascript"></script>
+ <script src="./support/helper.js" type="text/javascript"></script>
+ </head>
+ <body>
+ <!-- required by testharnessreport.js -->
+ <div id="log"></div>
+ <!-- elements used for testing -->
+ <div id="container">
+ <div id="transition"></div>
+ </div>
+
+ <script>
+ var transition = document.getElementById('transition');
+
+ // syntax: none | [ all | <IDENT> ] [ ‘,’ [ all | <IDENT> ] ]*
+ var values = {
+ 'none, all' : 'all',
+ 'all, none' : 'all',
+ 'foobar' : 'foobar',
+ 'all, foobar' : 'all, foobar',
+ 'foobar, all' : 'foobar, all',
+ 'inherit' : 'padding',
+ 'initial' : 'all'
+ };
+
+ for (var key in values) {
+ test(function() {
+ setStyle({
+ '#container': {'transition-property': 'padding'},
+ '#transition': {'transition-property': key}
+ });
+ var result = computedStyle(transition, 'transition-property');
+ assert_equals(result, values[key]);
+ }, "parse '" + key + "'");
+ }
+ </script>
+ </body>
+</html>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-property-003-manual.html b/testing/web-platform/tests/css/css-transitions/transition-property-003-manual.html
new file mode 100644
index 0000000000..291204d575
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-property-003-manual.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Transitions Test: transition-property - none</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<link rel="author" title="Shiyou Tan" href="mailto:shiyoux.tan@intel.com">
+<link rel="help" title="2.1. The 'transition-property' Property" href="http://www.w3.org/TR/css3-transitions/#transition-property-property">
+<meta name="assert" content="The 'transition-duration' property set 'none' means that no property will be transitioned.">
+<style>
+ div {
+ height: 100px;
+ transition-timing-function: linear;
+ width: 100px;
+ }
+ #ref {
+ background-color: yellow;
+ transition-duration: 2s;
+ transition-property: width;
+ }
+ #test {
+ background-color: blue;
+ transition-property: none;
+ }
+</style>
+<body>
+ <p>Click the 'Start' button below. Test passes if the width of yellow square grows smoothly but the blue grows immediately.</p>
+ <div id="ref"></div>
+ <div id="test"></div>
+ <button>Start</button>
+ <script>
+ (function() {
+ var button = document.querySelector("button"),
+ test = document.querySelector("#test"),
+ ref = document.querySelector("#ref");
+ button.addEventListener("click", function(evt) {
+ test.setAttribute("style", "width: 200px;");
+ ref.setAttribute("style", "width: 200px;");
+ }, false);
+ })();
+ </script>
+</body>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-property-004-manual.html b/testing/web-platform/tests/css/css-transitions/transition-property-004-manual.html
new file mode 100644
index 0000000000..d2e84c99d6
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-property-004-manual.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Transitions Test: transition-property - all</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<link rel="author" title="Shiyou Tan" href="mailto:shiyoux.tan@intel.com">
+<link rel="help" title="2.1. The 'transition-property' Property" href="http://www.w3.org/TR/css3-transitions/#transition-property-property">
+<meta name="assert" content="The 'transition-duration' property set 'all' means that all properties are transitioned.">
+<style>
+ #test {
+ background-color: blue;
+ height: 100px;
+ transition-duration: 2s;
+ transition-property: all;
+ transition-timing-function: linear;
+ width: 100px;
+ }
+</style>
+<body>
+ <p>Click the blue square below. Test passes if both height and width of blue square grow smoothly.</p>
+ <div id="test"></div>
+ <script>
+ (function() {
+ var div = document.querySelector("#test");
+ div.addEventListener("click", function(evt) {
+ div.setAttribute("style", "height: 200px; width: 200px;");
+ }, false);
+ })();
+ </script>
+</body>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-property-005-manual.html b/testing/web-platform/tests/css/css-transitions/transition-property-005-manual.html
new file mode 100644
index 0000000000..e69941001b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-property-005-manual.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Transitions Test: transition-property - height width(more than one properties specified)</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<link rel="author" title="Shiyou Tan" href="mailto:shiyoux.tan@intel.com">
+<link rel="help" title="2.1. The 'transition-property' Property" href="http://www.w3.org/TR/css3-transitions/#transition-property-property">
+<meta name="assert" content="The 'transition-duration' property set more than one properties like 'height, width'
+means only the specified properties will be transitioned.">
+<style>
+ #test {
+ background-color: red;
+ height: 100px;
+ transition-duration: 2s;
+ transition-property: height, width;
+ transition-timing-function: linear;
+ width: 100px;
+ }
+</style>
+<body>
+ <p>Click the red square below. Test passes if both height and width of square grow smoothly but the color changed to green immediately.</p>
+ <div id="test"></div>
+ <script>
+ (function() {
+ var div = document.querySelector("#test");
+ div.addEventListener("click", function(evt) {
+ div.setAttribute("style", "background-color: green; height: 200px; width: 200px;");
+ }, false);
+ })();
+ </script>
+</body>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-property-006-manual.html b/testing/web-platform/tests/css/css-transitions/transition-property-006-manual.html
new file mode 100644
index 0000000000..b6fa3a67a1
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-property-006-manual.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Transitions Test: transition-property - background-position</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<link rel="author" title="Shiyou Tan" href="mailto:shiyoux.tan@intel.com">
+<link rel="help" href="https://drafts.csswg.org/web-animations-1/#animation-type">
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#background-position">
+<meta name="assert" content="Test checks that the 'background-position' property is animatable.">
+<style>
+ #test {
+ border: 1px solid;
+ background-image: url("support/cat.png");
+ background-position: left;
+ background-repeat: no-repeat;
+ height: 200px;
+ transition-duration: 8s;
+ transition-property: background-position;
+ transition-timing-function: linear;
+ }
+</style>
+<body>
+ <p>Click the image inside of box below. Test passes if the image moves gradually but not immediately from left to right until it stops.</p>
+ <div id="test"></div>
+ <script>
+ (function() {
+ var div = document.querySelector("#test");
+ div.addEventListener("click", function(evt) {
+ div.setAttribute("style", "background-position: right;");
+ }, false);
+ })();
+ </script>
+</body>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-property-007-manual.html b/testing/web-platform/tests/css/css-transitions/transition-property-007-manual.html
new file mode 100644
index 0000000000..e62038e264
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-property-007-manual.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Transitions Test: transition-property - border-bottom-color</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<link rel="author" title="Shiyou Tan" href="mailto:shiyoux.tan@intel.com">
+<link rel="help" href="https://drafts.csswg.org/web-animations-1/#animation-type">
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#border-color">
+<meta name="assert" content="Test checks that the 'border-bottom-color' property animatable.">
+<style>
+ #test {
+ border: 10px solid red;
+ height: 90px;
+ transition-duration: 2s;
+ transition-property: border-bottom-color;
+ transition-timing-function: linear;
+ width: 90px;
+ }
+</style>
+<body>
+ <p>Click the square with red border below. Test passes if the color of bottom border transforms to green gradually not immediately.</p>
+ <div id="test"></div>
+ <script>
+ (function() {
+ var div = document.querySelector("#test");
+ div.addEventListener("click", function(evt) {
+ div.setAttribute("style", "border-bottom-color: green;");
+ }, false);
+ })();
+ </script>
+</body>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-property-008-manual.html b/testing/web-platform/tests/css/css-transitions/transition-property-008-manual.html
new file mode 100644
index 0000000000..e668b06eff
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-property-008-manual.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Transitions Test: transition-property - border-bottom-width</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<link rel="author" title="Shiyou Tan" href="mailto:shiyoux.tan@intel.com">
+<link rel="help" href="https://drafts.csswg.org/web-animations-1/#animation-type">
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#the-border-width">
+<meta name="assert" content="Test checks that the 'border-bottom-width' property animatable.">
+<style>
+ #test {
+ border: 5px solid blue;
+ height: 90px;
+ transition-duration: 2s;
+ transition-property: border-bottom-width;
+ transition-timing-function: linear;
+ width: 90px;
+ }
+</style>
+<body>
+ <p>Click the square with blue border below. Test passes if the height of bottom border grows gradually not immediately until it stops.</p>
+ <div id="test"></div>
+ <script>
+ (function() {
+ var div = document.querySelector("#test");
+ div.addEventListener("click", function(evt) {
+ div.setAttribute("style", "border-bottom-width: 20px;");
+ }, false);
+ })();
+ </script>
+</body>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-property-009-manual.html b/testing/web-platform/tests/css/css-transitions/transition-property-009-manual.html
new file mode 100644
index 0000000000..9a556282f8
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-property-009-manual.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Transitions Test: transition-property - border-left-color</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<link rel="author" title="Shiyou Tan" href="mailto:shiyoux.tan@intel.com">
+<link rel="help" href="https://drafts.csswg.org/web-animations-1/#animation-type">
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#border-color">
+<meta name="assert" content="Test checks that the 'border-left-color' property is animatable.">
+<style>
+ #test {
+ border: 10px solid red;
+ height: 90px;
+ transition-duration: 2s;
+ transition-property: border-left-color;
+ transition-timing-function: linear;
+ width: 90px;
+ }
+</style>
+<body>
+ <p>Click the square with red border below. Test passes if the color of left border transforms to green gradually not immediately.</p>
+ <div id="test"></div>
+ <script>
+ (function() {
+ var div = document.querySelector("#test");
+ div.addEventListener("click", function(evt) {
+ div.setAttribute("style", "border-left-color: green;");
+ }, false);
+ })();
+ </script>
+</body>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-property-010-manual.html b/testing/web-platform/tests/css/css-transitions/transition-property-010-manual.html
new file mode 100644
index 0000000000..66d499b57f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-property-010-manual.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Transitions Test: transition-property - border-left-width</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<link rel="author" title="Shiyou Tan" href="mailto:shiyoux.tan@intel.com">
+<link rel="help" href="https://drafts.csswg.org/web-animations-1/#animation-type">
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#the-border-width">
+<meta name="assert" content="Test checks that the 'border-left-width' property is animatable.">
+<style>
+ #test {
+ border: 5px solid blue;
+ height: 90px;
+ transition-duration: 2s;
+ transition-property: border-left-width;
+ transition-timing-function: linear;
+ width: 90px;
+ }
+</style>
+<body>
+ <p>Click the square with blue border below. Test passes if the width of left border grows gradually not immediately until it stops.</p>
+ <div id="test"></div>
+ <script>
+ (function() {
+ var div = document.querySelector("#test");
+ div.addEventListener("click", function(evt) {
+ div.setAttribute("style", "border-left-width: 20px;");
+ }, false);
+ })();
+ </script>
+</body>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-property-011-manual.html b/testing/web-platform/tests/css/css-transitions/transition-property-011-manual.html
new file mode 100644
index 0000000000..d84f88d3e9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-property-011-manual.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Transitions Test: transition-property - border-right-color</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<link rel="author" title="Shiyou Tan" href="mailto:shiyoux.tan@intel.com">
+<link rel="help" href="https://drafts.csswg.org/web-animations-1/#animation-type">
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#border-color">
+<meta name="assert" content="Test checks that the 'border-right-color' property is animatable.">
+<style>
+ #test {
+ border: 10px solid red;
+ height: 90px;
+ transition-duration: 2s;
+ transition-property: border-right-color;
+ transition-timing-function: linear;
+ width: 90px;
+ }
+</style>
+<body>
+ <p>Click the square with red border below. Test passes if the color of right border transforms to green gradually not immediately.</p>
+ <div id="test"></div>
+ <script>
+ (function() {
+ var div = document.querySelector("#test");
+ div.addEventListener("click", function(evt) {
+ div.setAttribute("style", "border-right-color: green;");
+ }, false);
+ })();
+ </script>
+</body>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-property-012-manual.html b/testing/web-platform/tests/css/css-transitions/transition-property-012-manual.html
new file mode 100644
index 0000000000..642c6ca624
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-property-012-manual.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Transitions Test: transition-property - border-right-width</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<link rel="author" title="Shiyou Tan" href="mailto:shiyoux.tan@intel.com">
+<link rel="help" href="https://drafts.csswg.org/web-animations-1/#animation-type">
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#the-border-width">
+<meta name="assert" content="Test checks that the 'border-right-width' property is animatable.">
+<style>
+ #test {
+ border: 5px solid blue;
+ height: 90px;
+ transition-duration: 2s;
+ transition-property: border-right-width;
+ transition-timing-function: linear;
+ width: 90px;
+ }
+</style>
+<body>
+ <p>Click the square with blue border below. Test passes if the width of right border grows gradually not immediately until it stops.</p>
+ <div id="test"></div>
+ <script>
+ (function() {
+ var div = document.querySelector("#test");
+ div.addEventListener("click", function(evt) {
+ div.setAttribute("style", "border-right-width: 20px;");
+ }, false);
+ })();
+ </script>
+</body>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-property-013-manual.html b/testing/web-platform/tests/css/css-transitions/transition-property-013-manual.html
new file mode 100644
index 0000000000..61c33b006a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-property-013-manual.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Transitions Test: transition-property - border-top-color</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<link rel="author" title="Shiyou Tan" href="mailto:shiyoux.tan@intel.com">
+<link rel="help" href="https://drafts.csswg.org/web-animations-1/#animation-type">
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#border-color">
+<meta name="assert" content="Test checks that the 'border-top-color' property is animatable.">
+<style>
+ #test {
+ border: 10px solid red;
+ height: 90px;
+ transition-duration: 2s;
+ transition-property: border-top-color;
+ transition-timing-function: linear;
+ width: 90px;
+ }
+</style>
+<body>
+ <p>Click the square with red border below. Test passes if the color of top border transforms to green gradually not immediately.</p>
+ <div id="test"></div>
+ <script>
+ (function() {
+ var div = document.querySelector("#test");
+ div.addEventListener("click", function(evt) {
+ div.setAttribute("style", "border-top-color: green;");
+ }, false);
+ })();
+ </script>
+</body>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-property-014-manual.html b/testing/web-platform/tests/css/css-transitions/transition-property-014-manual.html
new file mode 100644
index 0000000000..824b633c90
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-property-014-manual.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Transitions Test: transition-property - border-top-width</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<link rel="author" title="Shiyou Tan" href="mailto:shiyoux.tan@intel.com">
+<link rel="help" href="https://drafts.csswg.org/web-animations-1/#animation-type">
+<link rel="help" href="https://drafts.csswg.org/css-backgrounds-3/#the-border-width">
+<meta name="assert" content="Test checks that the 'border-top-width' property is animatable.">
+<style>
+ #test {
+ border: 5px solid blue;
+ height: 90px;
+ transition-duration: 2s;
+ transition-property: border-top-width;
+ transition-timing-function: linear;
+ width: 90px;
+ }
+</style>
+<body>
+ <p>Click the square with blue border below. Test passes if the height of top border grows gradually not immediately until it stops.</p>
+ <div id="test"></div>
+ <script>
+ (function() {
+ var div = document.querySelector("#test");
+ div.addEventListener("click", function(evt) {
+ div.setAttribute("style", "border-top-width: 20px;");
+ }, false);
+ })();
+ </script>
+</body>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-property-015-manual.html b/testing/web-platform/tests/css/css-transitions/transition-property-015-manual.html
new file mode 100644
index 0000000000..55f0000bd8
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-property-015-manual.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Transitions Test: transition-property - border-spacing</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<link rel="author" title="Shiyou Tan" href="mailto:shiyoux.tan@intel.com">
+<link rel="help" href="https://drafts.csswg.org/web-animations-1/#animation-type">
+<link rel="help" href="https://www.w3.org/TR/CSS22/tables.html#separated-borders">
+<meta name="assert" content="Test checks that the 'border-spacing' property is animatable.">
+<style>
+ #test {
+ border-spacing: 10px;
+ transition-duration: 2s;
+ transition-property: border-spacing;
+ transition-timing-function: linear;
+ }
+</style>
+<body>
+ <p>Click the 'FillerText' below. Test passes if the outermost border of 'FillerText' grows gradually not immediately until it stops.</p>
+ <table id="test" border="1">
+ <tr><td>FillerText</td></tr>
+ </table>
+ <script>
+ (function() {
+ var test = document.querySelector("#test");
+ test.addEventListener("click", function(evt) {
+ test.setAttribute("style", "border-spacing: 40px;");
+ }, false);
+ })();
+ </script>
+</body>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-property-016-manual.html b/testing/web-platform/tests/css/css-transitions/transition-property-016-manual.html
new file mode 100644
index 0000000000..3ba94fb299
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-property-016-manual.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Transitions Test: transition-property - bottom</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<link rel="author" title="Shiyou Tan" href="mailto:shiyoux.tan@intel.com">
+<link rel="help" href="https://drafts.csswg.org/web-animations-1/#animation-type">
+<link rel="help" href="https://www.w3.org/TR/CSS22/visuren.html#position-props">
+<meta name="assert" content="Test checks that the 'bottom' property is animatable.">
+<style>
+ #test {
+ background-color: blue;
+ bottom: -100px;
+ height: 100px;
+ position: relative;
+ transition-duration: 2s;
+ transition-property: bottom;
+ transition-timing-function: linear;
+ width: 100px;
+ }
+</style>
+<body>
+ <p>Click the blue square below. Test passes if blue square moves up gradually not immediately until it stops.</p>
+ <div id="test"></div>
+ <script>
+ (function() {
+ var div = document.querySelector("#test");
+ div.addEventListener("click", function(evt) {
+ div.setAttribute("style", "bottom: 10px;");
+ }, false);
+ })();
+ </script>
+</body>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-property-017-manual.html b/testing/web-platform/tests/css/css-transitions/transition-property-017-manual.html
new file mode 100644
index 0000000000..0847a2eba9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-property-017-manual.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Transitions Test: transition-property - clip</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<link rel="author" title="Shiyou Tan" href="mailto:shiyoux.tan@intel.com">
+<link rel="help" href="https://drafts.csswg.org/web-animations-1/#animation-type">
+<link rel="help" href="https://www.w3.org/TR/CSS22/visufx.html#clipping">
+<meta name="assert" content="Test checks that the 'clip' property is animatable.">
+<style>
+ #test {
+ clip: rect(0px, 60px, 60px, 0px);
+ position: absolute;
+ transition-duration: 2s;
+ transition-property: clip;
+ transition-timing-function: linear;
+ }
+</style>
+<body>
+ <p>Click the image(half green and half red) below. Test passes if the half red condenses gradually not immediately until only half green left.</p>
+ <image id="test" src="support/60x60-gg-rr.png"></image>
+ <script>
+ (function() {
+ var image = document.querySelector("#test");
+ image.addEventListener("click", function(evt) {
+ image.setAttribute("style", "clip: rect(0px, 60px, 30px, 0px);");
+ }, false);
+ })();
+ </script>
+</body>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-property-018-manual.html b/testing/web-platform/tests/css/css-transitions/transition-property-018-manual.html
new file mode 100644
index 0000000000..bdab973612
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-property-018-manual.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Transitions Test: transition-property - color</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<link rel="author" title="Shiyou Tan" href="mailto:shiyoux.tan@intel.com">
+<link rel="help" href="https://drafts.csswg.org/web-animations-1/#animation-type">
+<link rel="help" href="https://drafts.csswg.org/css-color/#the-color-property">
+<meta name="assert" content="Test checks that the 'color' property is animatable.">
+<style>
+ #test {
+ color: red;
+ transition-duration: 2s;
+ transition-property: color;
+ transition-timing-function: linear;
+ }
+</style>
+<body>
+ <p>Click the 'FillerText' whose color is red below. Test passes if the color transforms to green gradually not immediately.</p>
+ <div id="test">
+ FillerTextFillerTextFillerTextFillerText
+ </div>
+ <script>
+ (function() {
+ var test = document.querySelector("#test");
+ test.addEventListener("click", function(evt) {
+ test.setAttribute("style", "color: green;");
+ }, false);
+ })();
+ </script>
+</body>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-property-019-manual.html b/testing/web-platform/tests/css/css-transitions/transition-property-019-manual.html
new file mode 100644
index 0000000000..b15386b282
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-property-019-manual.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Transitions Test: transition-property - font-size</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<link rel="author" title="Shiyou Tan" href="mailto:shiyoux.tan@intel.com">
+<link rel="help" href="https://drafts.csswg.org/web-animations-1/#animation-type">
+<link rel="help" href="https://drafts.csswg.org/css-fonts-3/#font-size-prop">
+<meta name="assert" content="Test checks that the 'font-size' property is animatable.">
+<style>
+ #test {
+ font-size: 20px;
+ transition-duration: 2s;
+ transition-property: font-size;
+ transition-timing-function: linear;
+ }
+</style>
+<body>
+ <p>Click the 'FillerText' below. Test passes if the size of 'FillerText' increases gradually not immediately until it stops.</p>
+ <div id="test">
+ FillerTextFillerTextFillerTextFillerText
+ </div>
+ <script>
+ (function() {
+ var test = document.querySelector("#test");
+ test.addEventListener("click", function(evt) {
+ test.setAttribute("style", "font-size: 40px;");
+ }, false);
+ })();
+ </script>
+</body>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-property-020-manual.html b/testing/web-platform/tests/css/css-transitions/transition-property-020-manual.html
new file mode 100644
index 0000000000..cbf929d8c2
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-property-020-manual.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Transitions Test: transition-property - font-weight</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<link rel="author" title="Shiyou Tan" href="mailto:shiyoux.tan@intel.com">
+<link rel="help" href="https://drafts.csswg.org/web-animations-1/#animation-type">
+<link rel="help" href="https://drafts.csswg.org/web-animations-1/#animation-types">
+<meta name="assert" content="Test checks that the 'font-weight' property is animatable.">
+<style>
+ #test {
+ font-weight: 100;
+ transition-duration: 2s;
+ transition-property: font-weight;
+ transition-timing-function: linear;
+ }
+</style>
+<body>
+ <p>Click the 'FillerText' below. Test passes if the weight of 'FillerText' increases gradually not immediately until it stops.</p>
+ <div id="test">
+ FillerTextFillerTextFillerTextFillerText
+ </div>
+ <script>
+ (function() {
+ var test = document.querySelector("#test");
+ test.addEventListener("click", function(evt) {
+ test.setAttribute("style", "font-weight: 900;");
+ }, false);
+ })();
+ </script>
+</body>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-property-021-manual.html b/testing/web-platform/tests/css/css-transitions/transition-property-021-manual.html
new file mode 100644
index 0000000000..c79b607b55
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-property-021-manual.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Transitions Test: transition-property - left</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<link rel="author" title="Shiyou Tan" href="mailto:shiyoux.tan@intel.com">
+<link rel="help" href="https://drafts.csswg.org/web-animations-1/#animation-type">
+<link rel="help" href="https://www.w3.org/TR/CSS22/visuren.html#position-props">
+<meta name="assert" content="Test checks that the 'left' property is animatable.">
+<style>
+ #test {
+ background-color: blue;
+ height: 100px;
+ left: 10px;
+ position: relative;
+ transition-duration: 4s;
+ transition-property: left;
+ transition-timing-function: linear;
+ width: 100px;
+ }
+</style>
+<body>
+ <p>Click the blue square inside the box with black border below. Test passes if the blue square moves gradually not immediately from left to right until it stops.</p>
+ <div id="test"></div>
+ <script>
+ (function() {
+ var test = document.querySelector("#test");
+ test.addEventListener("click", function(evt) {
+ test.setAttribute("style", "left: 400px;");
+ }, false);
+ })();
+ </script>
+</body>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-property-022-manual.html b/testing/web-platform/tests/css/css-transitions/transition-property-022-manual.html
new file mode 100644
index 0000000000..cb92e5ff88
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-property-022-manual.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Transitions Test: transition-property - letter-spacing</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<link rel="author" title="Shiyou Tan" href="mailto:shiyoux.tan@intel.com">
+<link rel="help" href="https://drafts.csswg.org/web-animations-1/#animation-type">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#letter-spacing-property">
+<meta name="flags" content="ahem">
+<meta name="assert" content="Test checks that the 'letter-spacing' property is animatable.">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+ #test {
+ font-family: ahem;
+ letter-spacing: 0px;
+ transition-duration: 4s;
+ transition-property: letter-spacing;
+ transition-timing-function: linear;
+ }
+</style>
+<body>
+ <p>Click the black rectangle below. Test passes if the black rectangle splits into ten little squares and the spacing between little squares increases gradually not immediately until it stops.</p>
+ <div id="test">FillerText</div>
+ <script>
+ (function() {
+ var test = document.querySelector("#test");
+ test.addEventListener("click", function(evt) {
+ test.setAttribute("style", "letter-spacing: 20px;");
+ }, false);
+ })();
+ </script>
+</body>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-property-023-manual.html b/testing/web-platform/tests/css/css-transitions/transition-property-023-manual.html
new file mode 100644
index 0000000000..8311067044
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-property-023-manual.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Transitions Test: transition-property - line-height</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<link rel="author" title="Shiyou Tan" href="mailto:shiyoux.tan@intel.com">
+<link rel="help" href="https://drafts.csswg.org/web-animations-1/#animation-type">
+<link rel="help" href="https://drafts.csswg.org/css-inline/#line-height-property">
+<meta name="assert" content="Test checks that the 'line-height' property is animatable.">
+<style>
+ #test {
+ line-height: 10px;
+ transition-duration: 4s;
+ transition-property: line-height;
+ transition-timing-function: linear;
+ }
+</style>
+<body>
+ <p>Click the 'FillerText' below. Test passes if the 'FillerText' moves down gradually not immediately until it stops.</p>
+ <div id="test">FillerTextFillerText</div>
+ <script>
+ (function() {
+ var test = document.querySelector("#test");
+ test.addEventListener("click", function(evt) {
+ test.setAttribute("style", "line-height: 100px;");
+ }, false);
+ })();
+ </script>
+</body>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-property-024-manual.html b/testing/web-platform/tests/css/css-transitions/transition-property-024-manual.html
new file mode 100644
index 0000000000..ca0f5fbd37
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-property-024-manual.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Transitions Test: transition-property - margin-bottom</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<link rel="author" title="Shiyou Tan" href="mailto:shiyoux.tan@intel.com">
+<link rel="help" href="https://drafts.csswg.org/web-animations-1/#animation-type">
+<link rel="help" href="https://drafts.csswg.org/css-box-3/#margin-physical">
+<meta name="assert" content="Test checks that the 'margin-bottom' property is animatable.">
+<style>
+ #ref {
+ background-color: blue;
+ height: 100px;
+ width: 100px;
+ }
+ #test {
+ margin-bottom: 1px;
+ transition-duration: 4s;
+ transition-property: margin-bottom;
+ transition-timing-function: linear;
+ }
+</style>
+<body>
+ <p id="test">Click blue square below. Test passes if the blue square moves down gradually not immediately until it stops.</p>
+ <div id="ref"></div>
+ <script>
+ (function() {
+ var ref = document.querySelector("#ref");
+ ref.addEventListener("click", function(evt) {
+ document.querySelector("#test").setAttribute("style", "margin-bottom: 100px;");
+ }, false);
+ })();
+ </script>
+</body>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-property-025-manual.html b/testing/web-platform/tests/css/css-transitions/transition-property-025-manual.html
new file mode 100644
index 0000000000..ee510786d9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-property-025-manual.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Transitions Test: transition-property - margin-left</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<link rel="author" title="Shiyou Tan" href="mailto:shiyoux.tan@intel.com">
+<link rel="help" href="https://drafts.csswg.org/web-animations-1/#animation-type">
+<link rel="help" href="https://drafts.csswg.org/css-box-3/#margin-physical">
+<meta name="assert" content="Test checks that the 'margin-left' property is animatable.">
+<style>
+ #test {
+ background-color: blue;
+ height: 100px;
+ margin-left: 1px;
+ transition-duration: 4s;
+ transition-property: margin-left;
+ transition-timing-function: linear;
+ width: 100px;
+ }
+</style>
+<body>
+ <p>Click the blue square below. Test passes if the blue square moves gradually not immediately from left to right until it stops.</p>
+ <div id="test"></div>
+ <script>
+ (function() {
+ var test = document.querySelector("#test");
+ test.addEventListener("click", function(evt) {
+ test.setAttribute("style", "margin-left: 200px;");
+ }, false);
+ })();
+ </script>
+</body>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-property-026-manual.html b/testing/web-platform/tests/css/css-transitions/transition-property-026-manual.html
new file mode 100644
index 0000000000..594a90971a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-property-026-manual.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Transitions Test: transition-property - margin-right</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<link rel="author" title="Shiyou Tan" href="mailto:shiyoux.tan@intel.com">
+<link rel="help" href="https://drafts.csswg.org/web-animations-1/#animation-type">
+<link rel="help" href="https://drafts.csswg.org/css-box-3/#margin-physical">
+<meta name="assert" content="Test checks that the 'margin-right' property is animatable.">
+<style>
+ div {
+ float: left;
+ }
+ #ref {
+ height: 100px;
+ margin-right: 1px;
+ transition-duration: 4s;
+ transition-property: margin-right;
+ transition-timing-function: linear;
+ width: 1px;
+ }
+ #test {
+ background-color: blue;
+ height: 100px;
+ width: 100px;
+ }
+</style>
+<body>
+ <p>Click the blue square below. Test passes if the blue square moves gradually not immediately from left to right until it stops.</p>
+ <div id="ref"></div>
+ <div id="test"></div>
+ <script>
+ (function() {
+ var test = document.querySelector("#test");
+ test.addEventListener("click", function(evt) {
+ document.querySelector("#ref").setAttribute("style", "margin-right: 200px;");
+ }, false);
+ })();
+ </script>
+</body>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-property-027-manual.html b/testing/web-platform/tests/css/css-transitions/transition-property-027-manual.html
new file mode 100644
index 0000000000..9995156e4a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-property-027-manual.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Transitions Test: transition-property - max-height</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<link rel="author" title="Shiyou Tan" href="mailto:shiyoux.tan@intel.com">
+<link rel="help" href="https://drafts.csswg.org/web-animations-1/#animation-type">
+<link rel="help" href="https://drafts.csswg.org/css-sizing-3/#max-size-properties">
+<meta name="assert" content="Test checks that the 'max-height' property is animatable.">
+<style>
+ #test {
+ background-color: blue;
+ height: 200px;
+ max-height: 200px;
+ transition-duration: 4s;
+ transition-property: max-height;
+ transition-timing-function: linear;
+ width: 100px;
+ }
+</style>
+<body>
+ <p>Click the blue rectangle below. Test passes if the height of blue rectangle narrows gradually not immediately until it stops.</p>
+ <div id="test"></div>
+ <script>
+ (function() {
+ var test = document.querySelector("#test");
+ test.addEventListener("click", function(evt) {
+ test.setAttribute("style", "max-height: 100px;");
+ }, false);
+ })();
+ </script>
+</body>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-property-028-manual.html b/testing/web-platform/tests/css/css-transitions/transition-property-028-manual.html
new file mode 100644
index 0000000000..05db8f15dc
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-property-028-manual.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Transitions Test: transition-property - max-width</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<link rel="author" title="Shiyou Tan" href="mailto:shiyoux.tan@intel.com">
+<link rel="help" href="https://drafts.csswg.org/web-animations-1/#animation-type">
+<link rel="help" href="https://drafts.csswg.org/css-sizing-3/#max-size-properties">
+<meta name="assert" content="Test checks that the 'max-width' property is animatable.">
+<style>
+ #test {
+ background-color: blue;
+ height: 100px;
+ max-width: 200px;
+ transition-duration: 4s;
+ transition-property: max-width;
+ transition-timing-function: linear;
+ width: 200px;
+ }
+</style>
+<body>
+ <p>Click the blue rectangle below. Test passes if the width of blue rectangle narrows gradually not immediately until it stops.</p>
+ <div id="test"></div>
+ <script>
+ (function() {
+ var test = document.querySelector("#test");
+ test.addEventListener("click", function(evt) {
+ test.setAttribute("style", "max-width: 100px;");
+ }, false);
+ })();
+ </script>
+</body>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-property-029-manual.html b/testing/web-platform/tests/css/css-transitions/transition-property-029-manual.html
new file mode 100644
index 0000000000..70bc4e015f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-property-029-manual.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Transitions Test: transition-property - min-height</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<link rel="author" title="Shiyou Tan" href="mailto:shiyoux.tan@intel.com">
+<link rel="help" href="https://drafts.csswg.org/web-animations-1/#animation-type">
+<link rel="help" href="https://drafts.csswg.org/css-sizing-3/#min-size-properties">
+<meta name="assert" content="Test checks that the 'min-height' property is animatable.">
+<style>
+ #test {
+ background-color: blue;
+ height: 50px;
+ min-height: 50px;
+ transition-duration: 4s;
+ transition-property: min-height;
+ transition-timing-function: linear;
+ width: 100px;
+ }
+</style>
+<body>
+ <p>Click the blue rectangle below. Test passes if the height of blue rectangle increases gradually not immediately until it stops.</p>
+ <div id="test"></div>
+ <script>
+ (function() {
+ var test = document.querySelector("#test");
+ test.addEventListener("click", function(evt) {
+ test.setAttribute("style", "min-height: 100px;");
+ }, false);
+ })();
+ </script>
+</body>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-property-030-manual.html b/testing/web-platform/tests/css/css-transitions/transition-property-030-manual.html
new file mode 100644
index 0000000000..4f6d6c2a41
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-property-030-manual.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Transitions Test: transition-property - min-width</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<link rel="author" title="Shiyou Tan" href="mailto:shiyoux.tan@intel.com">
+<link rel="help" href="https://drafts.csswg.org/web-animations-1/#animation-type">
+<link rel="help" href="https://drafts.csswg.org/css-sizing-3/#min-size-properties">
+<meta name="assert" content="Test checks that the 'min-width' property is animatable.">
+<style>
+ #test {
+ background-color: blue;
+ height: 100px;
+ min-width: 50px;
+ transition-duration: 4s;
+ transition-property: min-width;
+ transition-timing-function: linear;
+ width: 50px;
+ }
+</style>
+<body>
+ <p>Click the blue rectangle below. Test passes if the width of blue rectangle increases gradually not immediately until it stops.</p>
+ <div id="test"></div>
+ <script>
+ (function() {
+ var test = document.querySelector("#test");
+ test.addEventListener("click", function(evt) {
+ test.setAttribute("style", "min-width: 100px;");
+ }, false);
+ })();
+ </script>
+</body>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-property-031-manual.html b/testing/web-platform/tests/css/css-transitions/transition-property-031-manual.html
new file mode 100644
index 0000000000..4f58a976c3
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-property-031-manual.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Transitions Test: transition-property - opacity</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<link rel="author" title="Shiyou Tan" href="mailto:shiyoux.tan@intel.com">
+<link rel="help" href="https://drafts.csswg.org/web-animations-1/#animation-type">
+<link rel="help" href="https://drafts.csswg.org/css-color-3/#transparency">
+<meta name="assert" content="Test checks that the 'opacity' property is animatable.">
+<style>
+ #test {
+ background-color: red;
+ height: 100px;
+ opacity: 1;
+ transition-duration: 2s;
+ transition-property: opacity;
+ transition-timing-function: linear;
+ width: 100px;
+ }
+</style>
+<body>
+ <p>Click the red square below. Test passes if the red square blurs gradually not immediately until it disappears.</p>
+ <div id="test"></div>
+ <script>
+ (function() {
+ var test = document.querySelector("#test");
+ test.addEventListener("click", function(evt) {
+ test.setAttribute("style", "opacity: 0;");
+ }, false);
+ })();
+ </script>
+</body>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-property-032-manual.html b/testing/web-platform/tests/css/css-transitions/transition-property-032-manual.html
new file mode 100644
index 0000000000..a8e143830a
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-property-032-manual.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Transitions Test: transition-property - outline-color</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<link rel="author" title="Shiyou Tan" href="mailto:shiyoux.tan@intel.com">
+<link rel="help" href="https://drafts.csswg.org/web-animations-1/#animation-type">
+<link rel="help" href="https://drafts.csswg.org/css-ui-3/#outline-color">
+<meta name="assert" content="Test checks that the 'outline-color' property is animatable.">
+<style>
+ #test {
+ height: 100px;
+ outline-style: solid;
+ outline-color: red;
+ outline-width: 4px;
+ transition-duration: 2s;
+ transition-property: outline-color;
+ transition-timing-function: linear;
+ width: 100px;
+ }
+</style>
+<body>
+ <p>Click the blank square with red border below. Test passes if the color of border transforms to green gradually not immediately.</p>
+ <div id="test"></div>
+ <script>
+ (function() {
+ var test = document.querySelector("#test");
+ test.addEventListener("click", function(evt) {
+ test.setAttribute("style", "outline-color: green;");
+ }, false);
+ })();
+ </script>
+</body>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-property-033-manual.html b/testing/web-platform/tests/css/css-transitions/transition-property-033-manual.html
new file mode 100644
index 0000000000..b6df1f3e97
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-property-033-manual.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Transitions Test: transition-property - outline-width</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<link rel="author" title="Shiyou Tan" href="mailto:shiyoux.tan@intel.com">
+<link rel="help" href="https://drafts.csswg.org/web-animations-1/#animation-type">
+<link rel="help" href="https://drafts.csswg.org/css-ui-3/#outline-width">
+<meta name="assert" content="Test checks that the 'outline-width' property is animatable.">
+<style>
+ #test {
+ height: 100px;
+ margin-left: 20px;
+ outline-style: solid;
+ outline-width: 2px;
+ transition-duration: 2s;
+ transition-property: outline-width;
+ transition-timing-function: linear;
+ width: 100px;
+ }
+</style>
+<body>
+ <p>Click the blank square with black border below. Test passes if the width of border increases gradually not immediately until it stops.</p>
+ <div id="test"></div>
+ <script>
+ (function() {
+ var test = document.querySelector("#test");
+ test.addEventListener("click", function(evt) {
+ test.setAttribute("style", "outline-width: 10px;");
+ }, false);
+ })();
+ </script>
+</body>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-property-034-manual.html b/testing/web-platform/tests/css/css-transitions/transition-property-034-manual.html
new file mode 100644
index 0000000000..0839abd100
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-property-034-manual.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Transitions Test: transition-property - padding-bottom</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<link rel="author" title="Shiyou Tan" href="mailto:shiyoux.tan@intel.com">
+<link rel="help" href="https://drafts.csswg.org/web-animations-1/#animation-type">
+<link rel="help" href="https://drafts.csswg.org/css-box-3/#padding-physical">
+<meta name="assert" content="Test checks that the 'padding-bottom' property is animatable.">
+<style>
+ #test {
+ background-color: blue;
+ height: 100px;
+ padding-bottom: 0px;
+ transition-duration: 2s;
+ transition-property: padding-bottom;
+ transition-timing-function: linear;
+ width: 100px;
+ }
+</style>
+<body>
+ <p>Click the blue square below. Test passes if the height of blue square increases gradually not immediately until it stops.</p>
+ <div id="test"></div>
+ <script>
+ (function() {
+ var ref = document.querySelector("#test");
+ test.addEventListener("click", function(evt) {
+ test.setAttribute("style", "padding-bottom: 100px;");
+ }, false);
+ })();
+ </script>
+</body>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-property-035-manual.html b/testing/web-platform/tests/css/css-transitions/transition-property-035-manual.html
new file mode 100644
index 0000000000..c53b5a7c07
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-property-035-manual.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Transitions Test: transition-property - padding-left</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<link rel="author" title="Shiyou Tan" href="mailto:shiyoux.tan@intel.com">
+<link rel="help" href="https://drafts.csswg.org/web-animations-1/#animation-type">
+<link rel="help" href="https://drafts.csswg.org/css-box-3/#padding-physical">
+<meta name="assert" content="Test checks that the 'padding-left' property is animatable.">
+<style>
+ #test {
+ padding-left: 1px;
+ transition-duration: 2s;
+ transition-property: padding-left;
+ transition-timing-function: linear;
+ }
+ #ref {
+ background-color: blue;
+ height: 100px;
+ width: 100px;
+ }
+</style>
+<body>
+ <p>Click the blue square below. Test passes if the blue square moves gradually not immediately form left to right until it stops.</p>
+ <div id="test">
+ <div id="ref"></div>
+ </div>
+ <script>
+ (function() {
+ var test = document.querySelector("#test");
+ test.addEventListener("click", function(evt) {
+ test.setAttribute("style", "padding-left: 200px;");
+ }, false);
+ })();
+ </script>
+</body>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-property-036-manual.html b/testing/web-platform/tests/css/css-transitions/transition-property-036-manual.html
new file mode 100644
index 0000000000..de79094e87
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-property-036-manual.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Transitions Test: transition-property - padding-right</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<link rel="author" title="Shiyou Tan" href="mailto:shiyoux.tan@intel.com">
+<link rel="help" href="https://drafts.csswg.org/web-animations-1/#animation-type">
+<link rel="help" href="https://drafts.csswg.org/css-box-3/#padding-physical">
+<meta name="assert" content="Test checks that the 'padding-right' property is animatable.">
+<style>
+ #test {
+ padding-right: 0px;
+ transition-duration: 2s;
+ transition-property: padding-right;
+ transition-timing-function: linear;
+ }
+ #ref {
+ background-color: blue;
+ float: right;
+ height: 100px;
+ width: 100px;
+ }
+</style>
+<body>
+ <p>Click the blue square below. Test passes if the blue square moves gradually not immediately from right to left until it stops.</p>
+ <div id="test">
+ <div id="ref"></div>
+ </div>
+ <script>
+ (function() {
+ var ref = document.querySelector("#ref");
+ ref.addEventListener("click", function(evt) {
+ document.querySelector("#test").setAttribute("style", "padding-right: 200px;");
+ }, false);
+ })();
+ </script>
+</body>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-property-037-manual.html b/testing/web-platform/tests/css/css-transitions/transition-property-037-manual.html
new file mode 100644
index 0000000000..29e165a95b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-property-037-manual.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Transitions Test: transition-property - padding-top</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<link rel="author" title="Shiyou Tan" href="mailto:shiyoux.tan@intel.com">
+<link rel="help" href="https://drafts.csswg.org/web-animations-1/#animation-type">
+<link rel="help" href="https://drafts.csswg.org/css-box-3/#padding-physical">
+<meta name="assert" content="Test checks that the 'padding-top' property is animatable.">
+<style>
+ #test {
+ padding-top: 1px;
+ transition-duration: 2s;
+ transition-property: padding-top;
+ transition-timing-function: linear;
+ }
+ #ref {
+ background-color: blue;
+ height: 100px;
+ width: 100px;
+ }
+</style>
+<body>
+ <p>Click the blue square below. Test passes if the blue square moves down gradually not immediately until it stops.</p>
+ <div id="test">
+ <div id="ref"></div>
+ </div>
+ <script>
+ (function() {
+ var test = document.querySelector("#test");
+ test.addEventListener("click", function(evt) {
+ test.setAttribute("style", "padding-top: 200px;");
+ }, false);
+ })();
+ </script>
+</body>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-property-038-manual.html b/testing/web-platform/tests/css/css-transitions/transition-property-038-manual.html
new file mode 100644
index 0000000000..5656d57ff9
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-property-038-manual.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Transitions Test: transition-property - right</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<link rel="author" title="Shiyou Tan" href="mailto:shiyoux.tan@intel.com">
+<link rel="help" href="https://drafts.csswg.org/web-animations-1/#animation-type">
+<link rel="help" href="https://www.w3.org/TR/CSS22/visuren.html#position-props">
+<meta name="assert" content="Test checks that the 'right' property is animatable.">
+<style>
+ #test {
+ background-color: blue;
+ height: 100px;
+ position: relative;
+ transition-duration: 2s;
+ transition-property: right;
+ transition-timing-function: linear;
+ width: 100px;
+ }
+</style>
+<body>
+ <p>Click the blue square below. Test passes if the blue square moves gradually not immediately from left to right until it stops.</p>
+ <div id="test"></div>
+ <script>
+ (function() {
+ var test = document.querySelector("#test");
+ test.addEventListener("click", function(evt) {
+ test.setAttribute("style", "right: -200px;");
+ }, false);
+ })();
+ </script>
+</body>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-property-039-manual.html b/testing/web-platform/tests/css/css-transitions/transition-property-039-manual.html
new file mode 100644
index 0000000000..892dbefe79
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-property-039-manual.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Transitions Test: transition-property - text-indent</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<link rel="author" title="Shiyou Tan" href="mailto:shiyoux.tan@intel.com">
+<link rel="help" href="https://drafts.csswg.org/web-animations-1/#animation-type">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#text-indent-property">
+<meta name="assert" content="Test checks that the 'text-indent' property is animatable.">
+<style>
+ #test {
+ transition-duration: 2s;
+ transition-property: text-indent;
+ transition-timing-function: linear;
+ }
+</style>
+<body>
+ <p>Click the 'FillerText' below. Test passes if the 'FillerText' moves gradually not immediately from left to right until it stops.</p>
+ <div id="test">FillerText</div>
+ <script>
+ (function() {
+ var test = document.querySelector("#test");
+ test.addEventListener("click", function(evt) {
+ test.setAttribute("style", "text-indent: 200px;");
+ }, false);
+ })();
+ </script>
+</body>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-property-040-manual.html b/testing/web-platform/tests/css/css-transitions/transition-property-040-manual.html
new file mode 100644
index 0000000000..3131ccac30
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-property-040-manual.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Transitions Test: transition-property - text-shadow</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<link rel="author" title="Shiyou Tan" href="mailto:shiyoux.tan@intel.com">
+<link rel="help" href="https://drafts.csswg.org/web-animations-1/#animation-type">
+<link rel="help" href="https://drafts.csswg.org/css-text-decor-3/#text-shadow-property">
+<meta name="assert" content="Test checks that the 'text-shadow' property is animatable.">
+<style>
+ #test {
+ transition-duration: 2s;
+ transition-property: text-shadow;
+ transition-timing-function: linear;
+ }
+</style>
+<body>
+ <p>Click the 'FillerText' that has no text shadow below. Test passes if the shadow of 'FillerText' appears gradually not immediately.</p>
+ <div id="test">FillerTextFillerText</div>
+ <script>
+ (function() {
+ var test = document.querySelector("#test");
+ test.addEventListener("click", function(evt) {
+ test.setAttribute("style", "text-shadow: 4px 5px;");
+ }, false);
+ })();
+ </script>
+</body>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-property-041-manual.html b/testing/web-platform/tests/css/css-transitions/transition-property-041-manual.html
new file mode 100644
index 0000000000..066afa7731
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-property-041-manual.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Transitions Test: transition-property - top</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<link rel="author" title="Shiyou Tan" href="mailto:shiyoux.tan@intel.com">
+<link rel="help" href="https://drafts.csswg.org/web-animations-1/#animation-type">
+<link rel="help" href="https://www.w3.org/TR/CSS22/visuren.html#position-props">
+<meta name="assert" content="Test checks that the 'top' property is animatable.">
+<style>
+ #test {
+ background-color: blue;
+ height: 100px;
+ position: relative;
+ transition-duration: 2s;
+ transition-property: top;
+ transition-timing-function: linear;
+ width: 100px;
+ }
+</style>
+<body>
+ <p>Click blue square below. Test passes if the blue square moves down gradually not immediately until it stops.</p>
+ <div id="test"></div>
+ <script>
+ (function() {
+ var test = document.querySelector("#test");
+ test.addEventListener("click", function(evt) {
+ test.setAttribute("style", "top: 200px;");
+ }, false);
+ })();
+ </script>
+</body>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-property-042-manual.html b/testing/web-platform/tests/css/css-transitions/transition-property-042-manual.html
new file mode 100644
index 0000000000..24e3d5bfc3
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-property-042-manual.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Transitions Test: transition-property - vertical-align</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<link rel="author" title="Shiyou Tan" href="mailto:shiyoux.tan@intel.com">
+<link rel="help" href="https://drafts.csswg.org/web-animations-1/#animation-type">
+<link rel="help" href="https://www.w3.org/TR/CSS22/visudet.html#propdef-vertical-align">
+<meta name="assert" content="Test checks that the 'vertical-align' property is animatable.">
+<style>
+ #test {
+ transition-duration: 2s;
+ transition-property: vertical-align;
+ transition-timing-function: linear;
+ vertical-align: top;
+ }
+</style>
+<body>
+ <p>Click the cat image below. Test passes if the 'FillerText' moves down to the bottom of the cat image gradually not immediately.</p>
+ <div id="test">
+ FillerText<image id="ref" src="support/cat.png"></image>
+ </div>
+ <script>
+ (function() {
+ var ref = document.querySelector("#ref");
+ ref.addEventListener("click", function(evt) {
+ document.querySelector("#test").setAttribute("style", "vertical-align: bottom;");
+ }, false);
+ })();
+ </script>
+</body>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-property-043-manual.html b/testing/web-platform/tests/css/css-transitions/transition-property-043-manual.html
new file mode 100644
index 0000000000..30231c6829
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-property-043-manual.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Transitions Test: transition-property - visibility</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<link rel="author" title="Shiyou Tan" href="mailto:shiyoux.tan@intel.com">
+<link rel="help" href="https://drafts.csswg.org/web-animations-1/#animation-type">
+<link rel="help" href="https://drafts.csswg.org/web-animations-1/#animation-types">
+<meta name="assert" content="Test checks that the 'visibility' property is animatable.">
+<style>
+ #test {
+ background-color: blue;
+ height: 100px;
+ transition-duration: 2s;
+ transition-property: visibility;
+ transition-timing-function: linear;
+ visibility: display;
+ width: 100px;
+ }
+</style>
+<body>
+ <p>Click blue square below. Test passes if the blue square disappears gradually not immediately.</p>
+ <div id="test"></div>
+ <script>
+ (function() {
+ var test = document.querySelector("#test");
+ test.addEventListener("click", function(evt) {
+ test.setAttribute("style", "visibility: hidden;");
+ }, false);
+ })();
+ </script>
+</body>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-property-044-manual.html b/testing/web-platform/tests/css/css-transitions/transition-property-044-manual.html
new file mode 100644
index 0000000000..bd06404cdb
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-property-044-manual.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Transitions Test: transition-property - word-spacing</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<link rel="author" title="Shiyou Tan" href="mailto:shiyoux.tan@intel.com">
+<link rel="help" href="https://drafts.csswg.org/web-animations-1/#animation-type">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#word-spacing-property">
+<meta name="flags" content="ahem">
+<meta name="assert" content="Test checks that the 'word-spacing' property is animatable.">
+<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" />
+<style>
+ #test {
+ font-family: ahem;
+ transition-duration: 2s;
+ transition-property: word-spacing;
+ transition-timing-function: linear;
+ }
+</style>
+<body>
+ <p>Click any black rectangle below. Test passes if the second rectangle moves gradually not immediately from left to right until it stops and the first one does not move.</p>
+ <div id="test">text text</div>
+ <script>
+ (function() {
+ var test = document.querySelector("#test");
+ test.addEventListener("click", function(evt) {
+ test.setAttribute("style", "word-spacing: 40px;");
+ }, false);
+ })();
+ </script>
+</body>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-property-045-manual.html b/testing/web-platform/tests/css/css-transitions/transition-property-045-manual.html
new file mode 100644
index 0000000000..25160bfe11
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-property-045-manual.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Transitions Test: transition-property - z-index</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<link rel="author" title="Shiyou Tan" href="mailto:shiyoux.tan@intel.com">
+<link rel="help" href="https://drafts.csswg.org/web-animations-1/#animation-type">
+<link rel="help" href="https://www.w3.org/TR/CSS22/visuren.html#z-index">
+<meta name="flags" content="ahem">
+<meta name="assert" content="Test checks that the 'z-index' property is animatable.">
+<style>
+ div {
+ height: 100px;
+ width: 100px;
+ }
+ #ref {
+ background-color: red;
+ z-index: 1;
+ }
+ #test {
+ background-color: green;
+ position: relative;
+ top: -100px;
+ transition-duration: 2s;
+ transition-property: z-index;
+ transition-timing-function: linear;
+ z-index: -100;
+ }
+</style>
+<body>
+ <p>Click red square below. Test passes if the color of square changes to green after waiting a moment.</p>
+ <div id="ref"></div>
+ <div id="test"></div>
+ <script>
+ (function() {
+ var test = document.querySelector("#test");
+ document.addEventListener("click", function(evt) {
+ test.setAttribute("style", "z-index: 100;");
+ }, false);
+ })();
+ </script>
+</body>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-reparented.html b/testing/web-platform/tests/css/css-transitions/transition-reparented.html
new file mode 100644
index 0000000000..3dfd19425f
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-reparented.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Transition should cancel when an element is reparented</title>
+<link rel="help" href="https://www.w3.org/TR/css-transitions-1/#starting">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<style>
+.animated-div {
+ margin-left: 100px;
+ transition: margin-left 10s -5s linear;
+}
+</style>
+
+<div id="parent1">
+ <div id="target" class='animated-div'></div>
+</div>
+
+<div id="parent2"></div>
+
+<script>
+'use strict';
+
+test(t => {
+ assert_equals(getComputedStyle(target).marginLeft, '100px');
+ target.style.marginLeft = '200px';
+
+ // Because the start delay is -50% of the transition duration, we should
+ // immediately be (approximately) at the halfway point. What we really care
+ // about checking is that the transition has started but has not ended.
+ assert_not_equals(getComputedStyle(target).marginLeft, '100px');
+ assert_not_equals(getComputedStyle(target).marginLeft, '200px');
+
+ // Now change the target's parent. This should cancel the transition and
+ // skip straight to the end state.
+ parent2.appendChild(target);
+ assert_equals(getComputedStyle(target).marginLeft, '200px');
+}, 'When an element is reparented, any CSS Transition on it should be cancelled');
+</script>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-test.html b/testing/web-platform/tests/css/css-transitions/transition-test.html
new file mode 100644
index 0000000000..10700abf9b
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-test.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>CSS Transition Test: invalid values cause all properites to animate.</title>
+ <link rel="author" title="Oleg Janeiko" href="mailto:oleg@the-incredible.me">
+ <link rel="help" href="http://www.w3.org/TR/css3-transitions/#transition-property-property">
+ <link rel="match" href="reference/transition-test-ref.html">
+ <meta name="assert" content="When an invalid value is specified as one of the transition properties, it causes the the transition-property to change to 'all'. Instead of leaving the invalid property in and animating the valid properites with matching durations.">
+ <style type="text/css">
+ .container {
+ background-color: red;
+ height: 200px;
+ width: 200px;
+ }
+ .box {
+ width: 100px;
+ height: 100px;
+ background-color: green;
+
+ transition-property: width, foo; /* invalid foo */
+ transition-duration: 0, 5s;
+ }
+ .box.transition {
+ width: 200px;
+ height: 200px;
+ }
+ </style>
+ <script type="text/javascript" charset="utf-8">
+ function ready(){
+ var box = document.querySelector('.box');
+ box.className = 'box transition';
+ }
+ </script>
+</head>
+<body onload="ready();">
+ <div>
+ <p>You should not see a red background during the transition. Note: if the test passes transition is instant.</p>
+ </div>
+ <div class="container">
+ <div class="box"></div>
+ </div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-timing-function-002-manual.html b/testing/web-platform/tests/css/css-transitions/transition-timing-function-002-manual.html
new file mode 100644
index 0000000000..f4b95cd18d
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-timing-function-002-manual.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Transitions Test: transition-timing-function - 'ease' equivalent to 'cubic-bezier(0.25, 0.1, 0.25, 1.0)'</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<link rel="author" title="Shiyou Tan" href="mailto:shiyoux.tan@intel.com">
+<link rel="help" title="2.3. The 'transition-timing-function' Property" href="https://www.w3.org/TR/css-transitions-1/#transition-timing-function-property">
+<meta name="assert" content="The 'transition-timing-function' property set 'ease' is equivalent to cubic-bezier(0.25, 0.1, 0.25, 1.0)">
+<style>
+ div {
+ height: 100px;
+ transition: width 2s;
+ width: 100px;
+ }
+ #test1 {
+ background-color: blue;
+ transition-timing-function: ease;
+ }
+ #test2 {
+ background-color: yellow;
+ transition-timing-function: cubic-bezier(0.25, 0.1, 0.25, 1.0);
+ }
+</style>
+<body>
+ <p>Click the 'Start' button. Test passes if the width growth of blue square is <strong>equivalent</strong> to the yellow square.</p>
+ <div id="test1"></div>
+ <div id="test2"></div>
+ <button>Start</button>
+ <script>
+ (function() {
+ var button = document.querySelector("button");
+ button.addEventListener("click", function(evt) {
+ var test1 = document.querySelector("#test1"),
+ test2 = document.querySelector("#test2");
+ test1.setAttribute("style", "width: 300px");
+ test2.setAttribute("style", "width: 300px");
+ }, false);
+ })();
+ </script>
+</body>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-timing-function-003-manual.html b/testing/web-platform/tests/css/css-transitions/transition-timing-function-003-manual.html
new file mode 100644
index 0000000000..e1c4fdfb24
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-timing-function-003-manual.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Transitions Test: transition-timing-function - 'ease-in' equivalent to 'cubic-bezier(0.42, 0, 1.0, 1.0)'</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<link rel="author" title="Shiyou Tan" href="mailto:shiyoux.tan@intel.com">
+<link rel="help" href="https://www.w3.org/TR/css-transitions-1/#transition-timing-function-property">
+<meta name="assert" content="The 'transition-timing-function' property set 'ease-in' is equivalent to cubic-bezier(0.42, 0, 1.0, 1.0)">
+<style>
+ div {
+ height: 100px;
+ transition: width 2s;
+ width: 100px;
+ }
+ #test1 {
+ background-color: blue;
+ transition-timing-function: ease-in;
+ }
+ #test2 {
+ background-color: yellow;
+ transition-timing-function: cubic-bezier(0.42, 0, 1.0, 1.0);
+ }
+</style>
+<body>
+ <p>Click the 'Start' button. Test passes if the width growth of blue square is <strong>equivalent</strong> to the yellow square.</p>
+ <div id="test1"></div>
+ <div id="test2"></div>
+ <button>Start</button>
+ <script>
+ (function() {
+ var button = document.querySelector("button");
+ button.addEventListener("click", function(evt) {
+ var test1 = document.querySelector("#test1"),
+ test2 = document.querySelector("#test2");
+ test1.setAttribute("style", "width: 300px");
+ test2.setAttribute("style", "width: 300px");
+ }, false);
+ })();
+ </script>
+</body>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-timing-function-004-manual.html b/testing/web-platform/tests/css/css-transitions/transition-timing-function-004-manual.html
new file mode 100644
index 0000000000..21f801f8af
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-timing-function-004-manual.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Transitions Test: transition-timing-function - 'ease-in-out' equivalent to 'cubic-bezier(0.42, 0, 0.58, 1.0)'</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<link rel="author" title="Shiyou Tan" href="mailto:shiyoux.tan@intel.com">
+<link rel="help" href="https://www.w3.org/TR/css-transitions-1/#transition-timing-function-property">
+<meta name="assert" content="The 'transition-timing-function' property set 'ease-in-out' is equivalent to cubic-bezier(0.42, 0, 0.58, 1.0)">
+<style>
+ div {
+ height: 100px;
+ transition: width 2s;
+ width: 100px;
+ }
+ #test1 {
+ background-color: blue;
+ transition-timing-function: ease-in-out;
+ }
+ #test2 {
+ background-color: yellow;
+ transition-timing-function: cubic-bezier(0.42, 0, 0.58, 1.0);
+ }
+</style>
+<body>
+ <p>Click the 'Start' button. Test passes if the width growth of blue square is <strong>equivalent</strong> to the yellow square.</p>
+ <div id="test1"></div>
+ <div id="test2"></div>
+ <button>Start</button>
+ <script>
+ (function() {
+ var button = document.querySelector("button");
+ button.addEventListener("click", function(evt) {
+ var test1 = document.querySelector("#test1"),
+ test2 = document.querySelector("#test2");
+ test1.setAttribute("style", "width: 300px");
+ test2.setAttribute("style", "width: 300px");
+ }, false);
+ })();
+ </script>
+</body>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-timing-function-005-manual.html b/testing/web-platform/tests/css/css-transitions/transition-timing-function-005-manual.html
new file mode 100644
index 0000000000..c3f188b129
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-timing-function-005-manual.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Transitions Test: transition-timing-function - 'ease-out' equivalent to 'cubic-bezier(0, 0, 0.58, 1.0)'</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<link rel="author" title="Shiyou Tan" href="mailto:shiyoux.tan@intel.com">
+<link rel="help" href="https://www.w3.org/TR/css-transitions-1/#transition-timing-function-property">
+<meta name="assert" content="The 'transition-timing-function' property set 'ease-out' is equivalent to cubic-bezier(0, 0, 0.58, 1.0)">
+<style>
+ div {
+ height: 100px;
+ transition: width 2s;
+ width: 100px;
+ }
+ #test1 {
+ background-color: blue;
+ transition-timing-function: ease-out;
+ }
+ #test2 {
+ background-color: yellow;
+ transition-timing-function: cubic-bezier(0, 0, 0.58, 1.0);
+ }
+</style>
+<body>
+ <p>Click the 'Start' button. Test passes if the width growth of blue square is <strong>equivalent</strong> to the yellow square.</p>
+ <div id="test1"></div>
+ <div id="test2"></div>
+ <button>Start</button>
+ <script>
+ (function() {
+ var button = document.querySelector("button");
+ button.addEventListener("click", function(evt) {
+ var test1 = document.querySelector("#test1"),
+ test2 = document.querySelector("#test2");
+ test1.setAttribute("style", "width: 300px");
+ test2.setAttribute("style", "width: 300px");
+ }, false);
+ })();
+ </script>
+</body>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-timing-function-006-manual.html b/testing/web-platform/tests/css/css-transitions/transition-timing-function-006-manual.html
new file mode 100644
index 0000000000..a9bfdd3fd0
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-timing-function-006-manual.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Transitions Test: transition-timing-function - 'linear' equivalent to 'cubic-bezier(0.0, 0.0, 1.0, 1.0)'</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<link rel="author" title="Shiyou Tan" href="mailto:shiyoux.tan@intel.com">
+<link rel="help" href="https://www.w3.org/TR/css-transitions-1/#transition-timing-function-property">
+<meta name="assert" content="The 'transition-timing-function' property set 'linear' is equivalent to cubic-bezier(0.0, 0.0, 1.0, 1.0)">
+<style>
+ div {
+ height: 100px;
+ transition: width 2s;
+ width: 100px;
+ }
+ #test1 {
+ background-color: blue;
+ transition-timing-function: linear;
+ }
+ #test2 {
+ background-color: yellow;
+ transition-timing-function: cubic-bezier(0, 0, 1.0, 1.0);
+ }
+</style>
+<body>
+ <p>Click the 'Start' button. Test passes if the width growth of blue square is <strong>equivalent</strong> to the yellow square.</p>
+ <div id="test1"></div>
+ <div id="test2"></div>
+ <button>Start</button>
+ <script>
+ (function() {
+ var button = document.querySelector("button");
+ button.addEventListener("click", function(evt) {
+ var test1 = document.querySelector("#test1"),
+ test2 = document.querySelector("#test2");
+ test1.setAttribute("style", "width: 300px");
+ test2.setAttribute("style", "width: 300px");
+ }, false);
+ })();
+ </script>
+</body>
diff --git a/testing/web-platform/tests/css/css-transitions/transition-timing-function-010-manual.html b/testing/web-platform/tests/css/css-transitions/transition-timing-function-010-manual.html
new file mode 100644
index 0000000000..0a38a7196e
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transition-timing-function-010-manual.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Transitions Test: transition-timing-function - steps(2)</title>
+<link rel="author" title="Intel" href="http://www.intel.com">
+<link rel="author" title="Shiyou Tan" href="mailto:shiyoux.tan@intel.com">
+<link rel="help" href="https://www.w3.org/TR/css-transitions-1/#transition-timing-function-property">
+<meta name="assert" content="Test checks that the first parameter of 'steps()' function specifies the number of intervals.">
+<style>
+ div {
+ background-color: blue;
+ height: 100px;
+ transition-duration: 1s;
+ transition-property: width;
+ transition-timing-function: steps(2);
+ width: 100px;
+ }
+</style>
+<body>
+ <p>Click the blue square. Test passes if the width of blue square grows <strong>twice</strong>.</p>
+ <div></div>
+ <script>
+ (function() {
+ var div = document.querySelector("div");
+ div.addEventListener("click", function(evt) {
+ div.setAttribute("style", "width: 300px");
+ }, false);
+ })();
+ </script>
+</body>
diff --git a/testing/web-platform/tests/css/css-transitions/transitioncancel-001.html b/testing/web-platform/tests/css/css-transitions/transitioncancel-001.html
new file mode 100644
index 0000000000..6546195259
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transitioncancel-001.html
@@ -0,0 +1,65 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>CSS Transitions Test: display:none causes transitioncancel</title>
+ <meta name="timeout" content="long">
+ <link rel="author" title="Chris Rebert" href="http://chrisrebert.com">
+ <link rel="help" href="https://drafts.csswg.org/css-transitions-2/#event-dispatch">
+ <link rel="help" href="https://lists.w3.org/Archives/Public/www-style/2015Apr/0405.html" data-section-title="AnimationEnd events and display: none">
+ <meta name="flags" content="dom">
+ <meta name="assert" content="Making an element display:none; while it has a transition in progress should fire a transitioncancel event.">
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ <style>
+#a {
+ height: 100px;
+ width: 100px;
+ transition: background-color 2s;
+}
+.red {
+ background-color: red;
+}
+.blue {
+ background-color: blue;
+}
+.hidden {
+ display: none !important;
+}
+ </style>
+ <script>
+async_test(function (t) {
+ window.addEventListener('load', function () {
+ var div = document.getElementById('a');
+ var canceled = false;
+ var after = false;
+ div.addEventListener('transitioncancel', function () {
+ canceled = true;
+ t.step(function () {
+ assert_true(true, "transitioncancel event did fire");
+ });
+ }, false);
+
+ div.className = 'blue';// initiate transition
+ window.setTimeout(function () {
+ t.step(function () {
+ assert_false(canceled, "transitioncancel did not fire before hiding callback ran");
+ assert_false(after, "hiding callback ran before the end of the test");
+ });
+ div.className += ' hidden';// force display:none during the transition
+ }, 1000);// halfway into the transition
+ window.setTimeout(function () {
+ after = true;
+ t.step(function () {
+ assert_true(canceled, "transitioncancel event did fire");
+ t.done();
+ });
+ }, 2100);// after the transition would have ended
+ }, false);
+}, "transitioncancel should be fired if the element is made display:none during the transition");
+ </script>
+</head>
+<body>
+ <div id="a" class="red"></div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-transitions/transitioncancel-002.html b/testing/web-platform/tests/css/css-transitions/transitioncancel-002.html
new file mode 100644
index 0000000000..e62b17b5dc
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transitioncancel-002.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Transitions Test: Removing transitioning property from transition-property triggers transitioncancel</title>
+<link rel="author" title="Martin Robinson" href="mailto:mrobinson@igalia.com">
+<meta name="assert" content="Removing transitioning property from transition-property
+causes transitioncancel.">
+<link rel="help" href="https://drafts.csswg.org/css-transitions-2/#event-dispatch">
+
+<script src="/resources/testharness.js" type="text/javascript"></script>
+<script src="/resources/testharnessreport.js" type="text/javascript"></script>
+<script src="./support/helper.js" type="text/javascript"></script>
+
+</head>
+<body>
+<div id="log"></div>
+
+<script>
+promise_test(async t => {
+ // Create element and prepare to trigger a transition on it.
+ const div = addDiv(t, {
+ style: 'transition: background-color 0.25s; background-color: red;',
+ });
+
+ // Attach event listeners
+ const eventWatcher = new EventWatcher(t, div, ['transitioncancel']);
+ div.addEventListener('transitionend', t.step_func((event) => {
+ assert_unreached('transitionend event should not be fired');
+ }));
+
+ // Trigger transition
+ getComputedStyle(div).backgroundColor;
+ div.style.backgroundColor = 'green';
+ getComputedStyle(div).backgroundColor;
+
+ // Remove the transitioning property from transition-property asynchronously.
+ await waitForFrame();
+ div.style.transitionProperty = 'none';
+
+ await eventWatcher.wait_for('transitioncancel');
+}, 'Removing a transitioning property from transition-property should trigger transitioncancel');
+</script>
+
+</body>
+</html>
diff --git a/testing/web-platform/tests/css/css-transitions/transitionevent-interface.html b/testing/web-platform/tests/css/css-transitions/transitionevent-interface.html
new file mode 100644
index 0000000000..a40ba45375
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/transitionevent-interface.html
@@ -0,0 +1,229 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Transitions Test: TransitionEvent interface</title>
+<link rel="help" href="https://drafts.csswg.org/css-transitions-1/#interface-transitionevent">
+
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="transitionevent-interface.js"></script>
+
+<script>
+test(function() {
+ var event = new TransitionEvent("");
+ assert_true(event instanceof window.TransitionEvent);
+}, "the event is an instance of TransitionEvent");
+
+test(function() {
+ var event = new TransitionEvent("");
+ assert_true(event instanceof window.Event);
+}, "the event inherts from Event");
+
+test(function() {
+ assert_throws_js(TypeError, function() {
+ new TransitionEvent();
+ }, 'First argument is required, so was expecting a TypeError.');
+}, 'Missing type argument');
+
+test(function() {
+ var event = new TransitionEvent("test");
+ assert_equals(event.type, "test");
+}, "type argument is string");
+
+test(function() {
+ var event = new TransitionEvent(null);
+ assert_equals(event.type, "null");
+}, "type argument is null");
+
+test(function() {
+ var event = new TransitionEvent(undefined);
+ assert_equals(event.type, "undefined");
+}, "event type set to undefined");
+
+test(function() {
+ var event = new TransitionEvent("test");
+ assert_equals(event.propertyName, "");
+}, "propertyName has default value of empty string");
+
+test(function() {
+ var event = new TransitionEvent("test");
+ assert_equals(event.elapsedTime, 0.0);
+}, "elapsedTime has default value of 0.0");
+
+test(function() {
+ var event = new TransitionEvent("test");
+ assert_readonly(event, "propertyName", "readonly attribute value");
+}, "propertyName is readonly");
+
+test(function() {
+ var event = new TransitionEvent("test");
+ assert_readonly(event, "elapsedTime", "readonly attribute value");
+}, "elapsedTime is readonly");
+
+test(function() {
+ var event = new TransitionEvent("test", null);
+ assert_equals(event.propertyName, "");
+ assert_equals(event.elapsedTime, 0.0);
+}, "animationEventInit argument is null");
+
+test(function() {
+ var event = new TransitionEvent("test", undefined);
+ assert_equals(event.propertyName, "");
+ assert_equals(event.elapsedTime, 0.0);
+}, "animationEventInit argument is undefined");
+
+test(function() {
+ var event = new TransitionEvent("test", {});
+ assert_equals(event.propertyName, "");
+ assert_equals(event.elapsedTime, 0.0);
+}, "animationEventInit argument is empty dictionary");
+
+test(function() {
+ var event = new TransitionEvent("test", {pseudoElement: "::testPseudo"});
+ assert_equals(event.pseudoElement, "::testPseudo");
+}, "TransitionEvent.pseudoElement initialized from the dictionary");
+
+test(function() {
+ var event = new TransitionEvent("test", {propertyName: "sample"});
+ assert_equals(event.propertyName, "sample");
+}, "propertyName set to 'sample'");
+
+test(function() {
+ var event = new TransitionEvent("test", {propertyName: undefined});
+ assert_equals(event.propertyName, "");
+}, "propertyName set to undefined");
+
+test(function() {
+ var event = new TransitionEvent("test", {propertyName: null});
+ assert_equals(event.propertyName, "null");
+}, "propertyName set to null");
+
+test(function() {
+ var event = new TransitionEvent("test", {propertyName: false});
+ assert_equals(event.propertyName, "false");
+}, "propertyName set to false");
+
+test(function() {
+ var event = new TransitionEvent("test", {propertyName: true});
+ assert_equals(event.propertyName, "true");
+}, "propertyName set to true");
+
+test(function() {
+ var event = new TransitionEvent("test", {propertyName: 0.5});
+ assert_equals(event.propertyName, "0.5");
+}, "propertyName set to a number");
+
+test(function() {
+ var event = new TransitionEvent("test", {propertyName: []});
+ assert_equals(event.propertyName, "");
+}, "propertyName set to []");
+
+test(function() {
+ var event = new TransitionEvent("test", {propertyName: [1, 2, 3]});
+ assert_equals(event.propertyName, "1,2,3");
+}, "propertyName set to [1, 2, 3]");
+
+test(function() {
+ var event = new TransitionEvent("test", {propertyName: {sample: 0.5}});
+ assert_equals(event.propertyName, "[object Object]");
+}, "propertyName set to an object");
+
+test(function() {
+ var event = new TransitionEvent("test",
+ {propertyName: {valueOf: function () { return 'sample'; }}});
+ assert_equals(event.propertyName, "[object Object]");
+}, "propertyName set to an object with a valueOf function");
+
+test(function() {
+ var event = new TransitionEvent("test", {elapsedTime: 0.5});
+ assert_equals(event.elapsedTime, 0.5);
+}, "elapsedTime set to 0.5");
+
+test(function() {
+ var event = new TransitionEvent("test", {elapsedTime: -0.5});
+ assert_equals(event.elapsedTime, -0.5);
+}, "elapsedTime set to -0.5");
+
+test(function() {
+ var event = new TransitionEvent("test", {elapsedTime: undefined});
+ assert_equals(event.elapsedTime, 0);
+}, "elapsedTime set to undefined");
+
+test(function() {
+ var event = new TransitionEvent("test", {elapsedTime: null});
+ assert_equals(event.elapsedTime, 0);
+}, "elapsedTime set to null");
+
+test(function() {
+ var event = new TransitionEvent("test", {elapsedTime: false});
+ assert_equals(event.elapsedTime, 0);
+}, "elapsedTime set to false");
+
+test(function() {
+ var event = new TransitionEvent("test", {elapsedTime: true});
+ assert_equals(event.elapsedTime, 1);
+}, "elapsedTime set to true");
+
+test(function() {
+ var event = new TransitionEvent("test", {elapsedTime: ""});
+ assert_equals(event.elapsedTime, 0);
+}, "elapsedTime set to ''");
+
+test(function() {
+ var event = new TransitionEvent("test", {elapsedTime: []});
+ assert_equals(event.elapsedTime, 0);
+}, "elapsedTime set to []");
+
+test(function() {
+ var event = new TransitionEvent("test", {elapsedTime: [0.5]});
+ assert_equals(event.elapsedTime, 0.5);
+}, "elapsedTime set to [0.5]");
+
+test(function() {
+ var event = new TransitionEvent(
+ "test", {elapsedTime: { valueOf: function() { return 0.5; }}});
+ assert_equals(event.elapsedTime, 0.5);
+}, "elapsedTime set to an object with a valueOf function");
+
+test(function() {
+ assert_throws_js(TypeError, function() {
+ new TransitionEvent("test", {elapsedTime: NaN});
+ }, 'elapsedTime cannot be NaN so was expecting a TypeError');
+}, "elapsedTime cannot be set to NaN");
+
+test(function() {
+ assert_throws_js(TypeError, function() {
+ new TransitionEvent("test", {elapsedTime: Infinity});
+ }, 'elapsedTime cannot be Infinity so was expecting a TypeError');
+}, "elapsedTime cannot be set to Infinity");
+
+test(function() {
+ assert_throws_js(TypeError, function() {
+ new TransitionEvent("test", {elapsedTime: -Infinity});
+ }, 'elapsedTime cannot be -Infinity so was expecting a TypeError');
+}, "elapsedTime cannot be set to -Infinity");
+
+test(function() {
+ assert_throws_js(TypeError, function() {
+ new TransitionEvent("test", {elapsedTime: "sample"});
+ }, 'elapsedTime cannot be a string so was expecting a TypeError');
+}, "elapsedTime cannot be set to 'sample'");
+
+test(function() {
+ assert_throws_js(TypeError, function() {
+ new TransitionEvent("test", {elapsedTime: [0.5, 1.0]});
+ }, 'elapsedTime cannot be a multi-element array so was expecting a TypeError');
+}, "elapsedTime cannot be set to [0.5, 1.0]");
+
+test(function() {
+ assert_throws_js(TypeError, function() {
+ new TransitionEvent("test", {elapsedTime: { sample: 0.5}});
+ }, 'elapsedTime cannot be an object so was expecting a TypeError');
+}, "elapsedTime cannot be set to an object");
+
+test(function() {
+ var eventInit = {propertyName: "sample", elapsedTime: 0.5};
+ var event = new TransitionEvent("test", eventInit);
+ assert_equals(event.propertyName, "sample");
+ assert_equals(event.elapsedTime, 0.5);
+}, "TransitionEventInit properties set value");
+</script>
diff --git a/testing/web-platform/tests/css/css-transitions/zero-duration-multiple-transition.html b/testing/web-platform/tests/css/css-transitions/zero-duration-multiple-transition.html
new file mode 100644
index 0000000000..7b85702092
--- /dev/null
+++ b/testing/web-platform/tests/css/css-transitions/zero-duration-multiple-transition.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<meta charset="utf-8">
+<link rel="help" href="https://drafts.csswg.org/css-transitions/#starting">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1461070">
+<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+ #t {
+ color: red;
+ transition-property: color, color;
+ transition-duration: 1s, 0s;
+ }
+</style>
+<div id="t"></div>
+<script>
+test(function() {
+ let div = document.getElementById("t");
+ assert_equals(getComputedStyle(div).color, "rgb(255, 0, 0)");
+
+ div.style.color = "green";
+ assert_equals(
+ div.getAnimations().length,
+ 0,
+ "No transition should've started"
+ );
+
+ assert_equals(getComputedStyle(div).color, "rgb(0, 128, 0)");
+}, "transition-duration of 0 prevents earlier transitions with the same property from starting.");
+</script>