diff options
Diffstat (limited to 'testing/web-platform/tests/web-animations/interfaces/KeyframeEffect/style-change-events.html')
-rw-r--r-- | testing/web-platform/tests/web-animations/interfaces/KeyframeEffect/style-change-events.html | 242 |
1 files changed, 242 insertions, 0 deletions
diff --git a/testing/web-platform/tests/web-animations/interfaces/KeyframeEffect/style-change-events.html b/testing/web-platform/tests/web-animations/interfaces/KeyframeEffect/style-change-events.html new file mode 100644 index 0000000000..eecf170cd9 --- /dev/null +++ b/testing/web-platform/tests/web-animations/interfaces/KeyframeEffect/style-change-events.html @@ -0,0 +1,242 @@ +<!doctype html> +<meta charset=utf-8> +<title>KeyframeEffect interface: style change events</title> +<link rel="help" + href="https://drafts.csswg.org/web-animations-1/#model-liveness"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../../testcommon.js"></script> +<body> +<div id="log"></div> +<script> +'use strict'; + +// Test that each property defined in the KeyframeEffect interface does not +// produce style change events. +// +// There are two types of tests: +// +// MakeInEffectTest +// +// For properties that are able to cause the KeyframeEffect to start +// affecting the CSS 'opacity' property. +// +// This function takes either: +// +// (a) A function that makes the passed-in KeyframeEffect affect the +// 'opacity' property. +// +// (b) An object with the following format: +// +// { +// setup: elem => { /* return Animation */ } +// test: effect => { /* make |effect| affect 'opacity' */ } +// } +// +// If the latter form is used, the setup function should return an Animation +// whose KeyframeEffect does NOT (yet) affect the 'opacity' property (or is +// NOT yet in-effect). Otherwise, the transition we use to detect if a style +// change event has occurred will never have a chance to be triggered (since +// the animated style will clobber both before-change and after-change +// style). +// +// UsePropertyTest +// +// For properties that cannot cause the KeyframeEffect to start affecting the +// CSS 'opacity' property. +// +// The shape of the parameter to the UsePropertyTest is identical to the +// MakeInEffectTest. The only difference is that the function (or 'test' +// function of the object format is used) does not need to make the +// KeyframeEffect affect the CSS 'opacity' property, but simply needs to +// get/set the property under test. + +const MakeInEffectTest = testFuncOrObj => { + let test, setup; + + if (typeof testFuncOrObj === 'function') { + test = testFuncOrObj; + } else { + test = testFuncOrObj.test; + if (typeof testFuncOrObj.setup === 'function') { + setup = testFuncOrObj.setup; + } + } + + if (!setup) { + setup = elem => + elem.animate({ color: ['blue', 'green'] }, 100 * MS_PER_SEC); + } + + return { test, setup }; +}; + +const UsePropertyTest = testFuncOrObj => { + const { test, setup } = MakeInEffectTest(testFuncOrObj); + + let coveringAnimation; + return { + setup: elem => { + coveringAnimation = new Animation( + new KeyframeEffect(elem, { opacity: [0, 1] }, 100 * MS_PER_SEC) + ); + + return setup(elem); + }, + test: effect => { + test(effect); + coveringAnimation.play(); + }, + }; +}; + +const tests = { + getTiming: UsePropertyTest(effect => effect.getTiming()), + getComputedTiming: UsePropertyTest(effect => effect.getComputedTiming()), + updateTiming: MakeInEffectTest({ + // Initially put the effect in its before phase (with no fill mode)... + setup: elem => + elem.animate( + { opacity: [0.5, 1] }, + { + duration: 100 * MS_PER_SEC, + delay: 100 * MS_PER_SEC, + } + ), + // ... so that when the delay is removed, it begins to affect the opacity. + test: effect => { + effect.updateTiming({ delay: 0 }); + }, + }), + get target() { + let targetElem; + return MakeInEffectTest({ + setup: (elem, t) => { + targetElem = elem; + const targetB = createDiv(t); + return targetB.animate({ opacity: [0.5, 1] }, 100 * MS_PER_SEC); + }, + test: effect => { + effect.target = targetElem; + }, + }); + }, + pseudoElement: MakeInEffectTest({ + setup: elem => elem.animate( + {opacity: [0.5, 1]}, + {duration: 100 * MS_PER_SEC, pseudoElement: '::before'} + ), + test: effect => { + effect.pseudoElement = null; + }, + }), + iterationComposite: UsePropertyTest(effect => { + // Get iterationComposite + effect.iterationComposite; + + // Set iterationComposite + effect.iterationComposite = 'accumulate'; + }), + composite: UsePropertyTest(effect => { + // Get composite + effect.composite; + + // Set composite + effect.composite = 'add'; + }), + getKeyframes: UsePropertyTest(effect => effect.getKeyframes()), + setKeyframes: MakeInEffectTest(effect => + effect.setKeyframes({ opacity: [0.5, 1] }) + ), + get ['KeyframeEffect constructor']() { + let originalElem; + let animation; + return UsePropertyTest({ + setup: elem => { + originalElem = elem; + // Return a dummy animation so the caller has something to wait on + return elem.animate(null); + }, + test: () => + new KeyframeEffect( + originalElem, + { opacity: [0.5, 1] }, + 100 * MS_PER_SEC + ), + }); + }, + get ['KeyframeEffect copy constructor']() { + let effectToClone; + return UsePropertyTest({ + setup: elem => { + effectToClone = new KeyframeEffect( + elem, + { opacity: [0.5, 1] }, + 100 * MS_PER_SEC + ); + // Return a dummy animation so the caller has something to wait on + return elem.animate(null); + }, + test: () => new KeyframeEffect(effectToClone), + }); + }, +}; + +// Check that each enumerable property and the constructors follow the +// expected behavior with regards to triggering style change events. +const properties = [ + ...Object.keys(AnimationEffect.prototype), + ...Object.keys(KeyframeEffect.prototype), + 'KeyframeEffect constructor', + 'KeyframeEffect copy constructor', +]; + +test(() => { + for (const property of Object.keys(tests)) { + assert_in_array( + property, + properties, + `Test property '${property}' should be one of the properties on ` + + ' KeyframeEffect' + ); + } +}, 'All property keys are recognized'); + +for (const key of properties) { + promise_test(async t => { + assert_own_property(tests, key, `Should have a test for '${key}' property`); + const { setup, test } = tests[key]; + + // Setup target element + const div = createDiv(t); + let gotTransition = false; + div.addEventListener('transitionrun', () => { + gotTransition = true; + }); + + // Setup animation + const animation = setup(div, t); + + // Setup transition start point + div.style.transition = 'opacity 100s'; + getComputedStyle(div).opacity; + + // Update specified style but don't flush + div.style.opacity = '0.5'; + + // Trigger the property + test(animation.effect); + + // If the test function produced a style change event it will have triggered + // a transition. + + // Wait for the animation to start and then for at least one animation + // frame to give the transitionrun event a chance to be dispatched. + await animation.ready; + await waitForAnimationFrames(1); + + assert_false(gotTransition, 'A transition should NOT have been triggered'); + }, `KeyframeEffect.${key} does NOT trigger a style change event`); +} +</script> +</body> |