<!DOCTYPE html>
<link rel="help" src="https://github.com/w3c/csswg-drafts/pull/5666">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/web-animations/testcommon.js"></script>
<style>
  main {
    overflow: hidden;
    height: 0px;
    timeline-scope: --timeline1, --timeline2, --timeline3;
  }
  .scroller {
    overflow: hidden;
    width: 100px;
    height: 100px;
  }
  .scroller > div {
    height: 200px;
  }
  @keyframes expand {
    from { width: 100px; }
    to { width: 200px; }
  }
  #scroller1 {
    scroll-timeline-name: --timeline1;
  }
  #scroller2 {
    scroll-timeline-name: --timeline2;
  }
  #scroller3 {
    scroll-timeline-name: --timeline3;
  }
  #element {
    width: 0px;
    height: 20px;
    animation-name: expand;
    animation-duration: 1000s;
    animation-timing-function: linear;
    animation-timeline: --timeline1;
  }
  /* Ensure stable expectations if feature is not supported */
  @supports not (animation-timeline:--foo) {
    #element { animation-play-state: paused; }
  }
</style>
<main>
  <div class=scroller id=scroller1><div></div></div>
  <div class=scroller id=scroller2><div></div></div>
  <div class=scroller id=scroller3><div></div></div>
  <div class=scroller id=scroller4><div></div></div>
  <div id=container></div>
</main>
<script>
  scroller1.scrollTop = 20;
  scroller2.scrollTop = 40;
  scroller3.scrollTop = 60;
  scroller4.scrollTop = 80;

  // Create #element in #container, run |func|, then clean up afterwards.
  function test_animation_timeline(func, description) {
    promise_test(async () => {
      try {
        await runAndWaitForFrameUpdate(() => {
          let element = document.createElement('element');
          element.setAttribute('id', 'element');
          container.append(element);
        });
        await func();
      } finally {
        while (container.firstChild)
          container.firstChild.remove();
      }
    }, description);
  }

  test_animation_timeline(async () => {
    let animation = element.getAnimations()[0];
    assert_equals(getComputedStyle(element).width, '120px');
    element.style = 'animation-timeline:--timeline2';
    await animation.ready;

    assert_equals(getComputedStyle(element).width, '140px');
  }, 'Changing animation-timeline changes the timeline (sanity check)');

  test_animation_timeline(async () => {
    let animation = element.getAnimations()[0];
    assert_equals(getComputedStyle(element).width, '120px');

    // Set a (non-CSS) ScrollTimeline on the CSSAnimation.
    let timeline4 = new ScrollTimeline({ source: scroller4 });

    animation.timeline = timeline4;
    await animation.ready;
    assert_equals(getComputedStyle(element).width, '180px');

    // Changing the animation-timeline property should have no effect.
    element.style = 'animation-timeline:--timeline2';
    await animation.ready;

    assert_equals(getComputedStyle(element).width, '180px');
  }, 'animation-timeline ignored after setting timeline with JS ' +
     '(ScrollTimeline from JS)');

  test_animation_timeline(async () => {
    let animation = element.getAnimations()[0];
    assert_equals(getComputedStyle(element).width, '120px');

    let timeline1 = animation.timeline;
    element.style = 'animation-timeline:--timeline2';
    await animation.ready;
    assert_equals(getComputedStyle(element).width, '140px');

    animation.timeline = timeline1;
    await animation.ready;

    assert_equals(getComputedStyle(element).width, '120px');

    // Should have no effect.
    element.style = 'animation-timeline:--timeline3';
    await animation.ready;

    assert_equals(getComputedStyle(element).width, '120px');
  }, 'animation-timeline ignored after setting timeline with JS ' +
     '(ScrollTimeline from CSS)');

  test_animation_timeline(async () => {
    let animation = element.getAnimations()[0];
    assert_equals(getComputedStyle(element).width, '120px');
    animation.timeline = document.timeline;
    await animation.ready;

    // (The animation continues from where the previous timeline left it).
    assert_equals(getComputedStyle(element).width, '120px');

    // Changing the animation-timeline property should have no effect.
    element.style = 'animation-timeline:--timeline2';
    await animation.ready;
    assert_equals(getComputedStyle(element).width, '120px');
  }, 'animation-timeline ignored after setting timeline with JS (document timeline)');

  test_animation_timeline(async () => {
    let animation = element.getAnimations()[0];
    assert_equals(getComputedStyle(element).width, '120px');
    animation.timeline = null;
    assert_false(animation.pending);
    assert_equals(getComputedStyle(element).width, '120px');

    // Changing the animation-timeline property should have no effect.
    element.style = 'animation-timeline:--timeline2';
    assert_false(animation.pending);
    assert_equals(getComputedStyle(element).width, '120px');
  }, 'animation-timeline ignored after setting timeline with JS (null)');
</script>
