summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/web-animations/interfaces/KeyframeEffect/style-change-events.html
diff options
context:
space:
mode:
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.html242
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>