<!doctype html>
<meta charset=utf-8>
<title>KeyframeEffect.setKeyframes() for CSS animations</title>
<!-- TODO: Add a more specific link for this once it is specified. -->
<link rel="help" href="https://drafts.csswg.org/css-animations-2/">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="support/testcommon.js"></script>
<style>
@keyframes anim-simple {
  from { left: 0px }
  to   { left: 100px }
}
</style>
<body>
<div id="log"></div>
<script>
"use strict";

// Note that the sanity check that getKeyframes() normally DOES return the
// updated keyframes is contained in KeyframeEffect-getKeyframes.html.
test(t => {
  const div = addDiv(t);

  // Add custom @keyframes rule
  const stylesheet = document.styleSheets[0];
  const keyframes = '@keyframes anim-custom { to { left: 100px } }';
  const ruleIndex = stylesheet.insertRule(keyframes, 0);
  const keyframesRule = stylesheet.cssRules[ruleIndex];

  t.add_cleanup(function() {
    stylesheet.deleteRule(ruleIndex);
  });

  div.style.animation = 'anim-custom 100s';

  // Update the keyframes via the API
  const animation = div.getAnimations()[0];
  animation.effect.setKeyframes({ left: '200px' });

  // Then update them via style
  keyframesRule.deleteRule(0);
  keyframesRule.appendRule('to { left: 300px }');

  // The result should be the keyframes as set by the API, not via style.
  const frames = animation.effect.getKeyframes();
  assert_frames_equal(
    frames[frames.length - 1],
    {
      offset: null,
      computedOffset: 1,
      easing: 'linear',
      composite: 'auto',
      left: '200px',
    },
    'Keyframes reflect the value set via setKeyframes'
  );
}, 'KeyframeEffect.setKeyframes() causes subsequent changes to @keyframes'
   + ' rules to be ignored');

test(t => {
  const div = addDiv(t);
  div.style.animation = 'anim-simple 100s';

  const animation = div.getAnimations()[0];
  assert_equals(animation.effect.getKeyframes()[0].easing, 'ease');

  animation.effect.setKeyframes({ left: ['200px', '300px'] });
  assert_equals(animation.effect.getKeyframes()[0].easing, 'linear');

  div.style.animationTimingFunction = 'ease-in';
  getComputedStyle(div).animationTimingFunction;

  assert_equals(
    animation.effect.getKeyframes()[0].easing,
    'linear',
    'Easing should be the easing set by the API'
  );
}, 'KeyframeEffect.setKeyframes() causes subsequent changes to'
   + ' animation-timing-function to be ignored');

test(t => {
  const div = addDiv(t);

  const stylesheet = document.styleSheets[0];
  const keyframes = '@keyframes anim-custom { to { left: 100px } }';
  const ruleIndex = stylesheet.insertRule(keyframes, 0);
  const keyframesRule = stylesheet.cssRules[ruleIndex];

  t.add_cleanup(function() {
    stylesheet.deleteRule(ruleIndex);
  });

  div.style.animation = 'anim-custom 100s';

  // Try updating in a way that throws an error
  const animation = div.getAnimations()[0];
  assert_throws_js(TypeError, () => {
    animation.effect.setKeyframes({ left: '200px', offset: 'yer' });
  });

  keyframesRule.deleteRule(0);
  keyframesRule.appendRule('to { left: 300px }');

  // The result should be the keyframes as set via style.
  const frames = animation.effect.getKeyframes();
  assert_frames_equal(
    frames[frames.length - 1],
    {
      offset: 1,
      computedOffset: 1,
      easing: 'ease',
      composite: 'auto',
      left: '300px',
    },
    'Keyframes reflect the value set via style'
  );
}, 'KeyframeEffect.setKeyframes() should NOT cause subsequent changes to'
   + ' @keyframes rules to be ignored if it threw');

</script>
</body>
