summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/scroll-animations/css/animation-events.html
blob: be53af487a0f9a05787f60839a05d3c6aa948bc5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
<!DOCTYPE html>
<html id="top">
<meta charset="utf-8">
<title>View timeline animation events</title>
<link rel="help" href="https://drafts.csswg.org/scroll-animations-1/#events">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/web-animations/testcommon.js"></script>
<style type="text/css">
  @keyframes anim {
    from { transform: translateX(0); }
    to   { transform: translateX(100px); }
  }
  #target {
    background: green;
    height: 100px;
    width: 100px;
    margin-bottom: 150vh;
    animation-timeline: view();
  }
  .animate {
    animation:  anim auto;
  }
</style>
<body>
  <div id="target"></div>
</body>
<script type="text/javascript">
  promise_test(async t => {
    const target = document.getElementById('target');

    // Create a timeline and advance to the next frame to ensure that the
    // timeline has a value for currentTime.
    await waitForNextFrame();
    const timeline = new ViewTimeline({ subject: target });
    await waitForNextFrame();

    let animationstart_events = 0;
    let animationend_events = 0;
    document.addEventListener('animationstart', () => {
      animationstart_events++;
    });
    document.addEventListener('animationend', () => {
      animationend_events++;
    });

    // Start the animation and swap out its timeline while still play-pending
    // so that it already has a value for current time.
    target.classList.add('animate');
    const anim = target.getAnimations();
    anim.timeline = timeline;
    // Introduce a style change that will make the timeline state stale when
    // "ticked" at the start of the next animation frame.
    target.style = 'margin-top: 150vh';

    assert_false(!!anim.startTime,
                 'Start time deferred until timeline is updated');

    // Verify that we are not evaluating a start time based on a stale timeline.
    await waitForNextFrame();
    await waitForNextFrame();
    assert_equals(animationstart_events, 0,
                  'Target initially off-screen and no animationstart event');
    assert_equals(animationend_events, 0,
                  'Target initially off-screen and no animationend event');

    const scroller = document.scrollingElement;
    scroller.scrollTop = target.getBoundingClientRect().top;
    await waitForNextFrame();
    await waitForNextFrame();

    assert_equals(animationstart_events, 1,
                  'scrollstart event received after scrolling into view.');
    assert_equals(animationend_events, 0,
                  "No scrollend event until after scrolling out of view");

    scroller.scrollTop = target.getBoundingClientRect().bottom;

    await waitForNextFrame();
    await waitForNextFrame();

    assert_equals(animationstart_events, 1,
                  'No additional scrollstart event');
    assert_equals(animationend_events, 1,
                  'scrollend event received after scrolling out of view');
  }, 'View timelime generates animationstart and animationend events');
</script>