animation-trigger-addAnimation.tentative.html (6253B)
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <link rel="help" src="https://drafts.csswg.org/css-animations-2/#animation-trigger"> 5 <script src="/resources/testharness.js"></script> 6 <script src="/resources/testharnessreport.js"></script> 7 <script src="/web-animations/testcommon.js"></script> 8 <script src="/dom/events/scrolling/scroll_support.js"></script> 9 <script src="support/support.js"></script> 10 </head> 11 <body> 12 <style> 13 .subject, .target { 14 height: 50px; 15 width: 50px; 16 background-color: red; 17 } 18 .scroller { 19 overflow-y: scroll; 20 height: 500px; 21 width: 500px; 22 border: solid 1px; 23 position: relative; 24 } 25 #space { 26 width: 50px; 27 height: 600px; 28 } 29 </style> 30 <div id="wrapper"> 31 <div id="scroller" class="scroller"> 32 <div id="space"></div> 33 <div id="subject" class="subject"></div> 34 <div id="space"></div> 35 </div> 36 <div id="target" class="target"></div> 37 </div> 38 <script> 39 // The trigger and exit ranges are the same for this test. 40 const TRIGGER_START_PX = 150; 41 const TRIGGER_END_PX = 200; 42 const scroller = document.getElementById("scroller"); 43 const target = document.getElementById("target"); 44 const COVER_START_OFFSET = 100; 45 const rangeBoundaries = getRangeBoundariesForTest( 46 COVER_START_OFFSET + TRIGGER_START_PX, 47 COVER_START_OFFSET + TRIGGER_END_PX, 48 COVER_START_OFFSET + TRIGGER_START_PX, 49 COVER_START_OFFSET + TRIGGER_END_PX, 50 scroller); 51 const ANIMATION_DURATION_MS = 1; 52 const view_timeline = new ViewTimeline({ subject: subject }); 53 function setupAnimation() { 54 const animation = new Animation( 55 new KeyframeEffect( 56 target, 57 [ 58 { transform: "scaleX(1)", backgroundColor: "pink", left: "0px" }, 59 { transform: "scaleX(5)", backgroundColor: "pink", left: "10px" } 60 ], 61 { duration: ANIMATION_DURATION_MS, fill: "both" } 62 )); 63 return animation; 64 } 65 function setupAnimationTrigger(use_default_trigger=false) { 66 const trigger = use_default_trigger ? new TimelineTrigger() 67 : new TimelineTrigger({ 68 timeline: view_timeline, 69 rangeStart: `${TRIGGER_START_PX}px`, 70 rangeEnd: `${TRIGGER_END_PX}px` 71 }); 72 return trigger; 73 } 74 75 promise_test(async (test) => { 76 const animation = setupAnimation(); 77 const trigger = setupAnimationTrigger(/*use_default_trigger=*/true); 78 assert_array_equals(trigger.getAnimations(), [], 79 "trigger has no animations"); 80 81 // As the default trigger is always in the tripped state, the animation 82 // should be played right away. 83 trigger.addAnimation(animation, "play-forwards", "play-backwards"); 84 await animation.finished; 85 86 assert_times_equal(animation.currentTime, ANIMATION_DURATION_MS, 87 "animation finish reflected in currentTime"); 88 assert_equals(animation.playState, "finished", 89 "animation finish reflected in playeState"); 90 assert_array_equals(trigger.getAnimations(), [animation], 91 "trigger has animation attached"); 92 }, "Animation attached to tripped (default) trigger plays."); 93 94 promise_test(async (test) => { 95 const animation = setupAnimation(); 96 const trigger = setupAnimationTrigger(); 97 98 assert_equals(animation.playState, "idle", "animation is idle"); 99 assert_equals(animation.currentTime, null, "currentTime is null"); 100 assert_array_equals(trigger.getAnimations(), [], 101 "trigger has no animations"); 102 103 assert_equals(scroller.scrollTop, 0, "scroller is not scrolled, i.e. " + 104 "not within the trigger range"); 105 106 trigger.addAnimation(animation, "play-forwards", "play-backwards"); 107 108 await waitForAnimationFrames(2); 109 110 assert_equals(animation.playState, "paused", 111 "animation is paused, awaiting trigger event"); 112 assert_times_equal(animation.currentTime, 0, "currentTime is 0"); 113 114 // Entering the trigger range should play the animation. 115 rangeBoundaries.enterTriggerRange(); 116 await animation.finished; 117 118 assert_equals(animation.playState, "finished", 119 "animation is paused, awaiting trigger event"); 120 assert_times_equal(animation.currentTime, ANIMATION_DURATION_MS, 121 "currentTime is 0"); 122 assert_array_equals(trigger.getAnimations(), [animation], 123 "trigger has animation attached"); 124 }, "Animation attached to untripped trigger is paused at the beginning."); 125 126 promise_test(async (test) => { 127 await waitForScrollReset(test, scroller); 128 129 assert_equals(scroller.scrollTop, 0, "scroller is not scrolled, i.e. " + 130 "not within the trigger range"); 131 132 const animation = setupAnimation(); 133 const trigger = setupAnimationTrigger(); 134 135 assert_equals(animation.playState, "idle", "animation is idle"); 136 assert_equals(animation.currentTime, null, "currentTime is null"); 137 assert_array_equals(trigger.getAnimations(), [], 138 "trigger has no animations"); 139 140 rangeBoundaries.enterTriggerRange(); 141 await waitForAnimationFrames(2); 142 143 assert_equals(animation.playState, "idle", "animation is still idle"); 144 assert_equals(animation.currentTime, null, "currentTime is still null"); 145 146 trigger.addAnimation(animation, "play-forwards", "play-backwards"); 147 await animation.finished; 148 149 assert_equals(animation.playState, "finished", 150 "animation is paused, awaiting trigger event"); 151 assert_times_equal(animation.currentTime, ANIMATION_DURATION_MS, 152 `currentTime is ${ANIMATION_DURATION_MS}`); 153 assert_array_equals(trigger.getAnimations(), [animation], 154 "trigger has animation attached"); 155 }, "Animation attached to tripped trigger is played immediately."); 156 </script> 157 </body> 158 </html>