From 49e012c0305f1e66c06e18b1ec5d581b3191ce24 Mon Sep 17 00:00:00 2001 From: Hiroyuki Ikezoe Date: Thu, 7 Dec 2017 10:06:02 +0900 Subject: [PATCH] Bug 1416693 - Make animation test cases that don't require asynchronous. r=boris Below list is animation test cases remain in test_animation_observers_async.html * single_animation : waiting for animationend event * single_animation_cancelled_fill : waiting for animaitonend event * tree_ordering : waiting for animationend event * coalesce_change_cancel : testing a non-cancelling change to an animation followed immediately by a cancelling change sends only one removal notification, I am concerned that adding explicit style flush (e.g. getComputedstyle) might change the test purpose. * play : redundant play() seems to be affected by asynchronous. I haven't dug into detail. * finish_from_pause : waiting for Animation.ready to make sure pause pending state to finish. MozReview-Commit-ID: HAelOTwSqgv --HG-- extra : rebase_source : 819e8975028f62580dccd07fedc53d250b71f97a --- .../test_animation_observers_async.html | 451 ------------------ .../chrome/test_animation_observers_sync.html | 426 +++++++++++++++++ 2 files changed, 426 insertions(+), 451 deletions(-) diff --git a/dom/animation/test/chrome/test_animation_observers_async.html b/dom/animation/test/chrome/test_animation_observers_async.html index 06309526d9bf..7de3f3acc494 100644 --- a/dom/animation/test/chrome/test_animation_observers_async.html +++ b/dom/animation/test/chrome/test_animation_observers_async.html @@ -272,99 +272,6 @@ function assert_records_any_order(expected, desc) { e.style = ""; }); - // Test that starting a single animation that is cancelled by resetting - // the animation-name property dispatches an added notification and - // then a removed notification. - addAsyncAnimTest("single_animation_cancelled_name", aOptions, function*() { - // Start a long animation. - e.style = "animation: anim 100s;"; - - // The animation should cause the creation of a single Animation. - var animations = e.getAnimations(); - is(animations.length, 1, "getAnimations().length after animation start"); - - // Wait for the single MutationRecord for the Animation addition to - // be delivered. - yield waitForFrame(); - assert_records([{ added: animations, changed: [], removed: [] }], - "records after animation start"); - - // Cancel the animation by setting animation-name. - e.style.animationName = "none"; - - // Wait for the single MutationRecord for the Animation removal to - // be delivered. - yield waitForFrame(); - assert_records([{ added: [], changed: [], removed: animations }], - "records after animation end"); - - e.style = ""; - }); - - // Test that starting a single animation that is cancelled by updating - // the animation-duration property dispatches an added notification and - // then a removed notification. - addAsyncAnimTest("single_animation_cancelled_duration", aOptions, function*() { - // Start a long animation. - e.style = "animation: anim 100s;"; - - // The animation should cause the creation of a single Animation. - var animations = e.getAnimations(); - is(animations.length, 1, "getAnimations().length after animation start"); - - // Wait for the single MutationRecord for the Animation addition to - // be delivered. - yield waitForFrame(); - assert_records([{ added: animations, changed: [], removed: [] }], - "records after animation start"); - - // Advance the animation by a second. - animations[0].currentTime += 1 * MS_PER_SEC; - - // Cancel the animation by setting animation-duration to a value less - // than a second. - e.style.animationDuration = "0.1s"; - - // Wait for the change MutationRecord from seeking the Animation to - // be delivered, followed by a further MutationRecord for the Animation - // removal. - yield waitForFrame(); - assert_records([{ added: [], changed: animations, removed: [] }, - { added: [], changed: [], removed: animations }], - "records after animation end"); - - e.style = ""; - }); - - // Test that starting a single animation that is cancelled by updating - // the animation-delay property dispatches an added notification and - // then a removed notification. - addAsyncAnimTest("single_animation_cancelled_delay", aOptions, function*() { - // Start a long animation. - e.style = "animation: anim 100s;"; - - // The animation should cause the creation of a single Animation. - var animations = e.getAnimations(); - is(animations.length, 1, "getAnimations().length after animation start"); - - // Wait for the single MutationRecord for the Animation addition to - // be delivered. - yield waitForFrame(); - assert_records([{ added: animations, changed: [], removed: [] }], - "records after animation start"); - - // Cancel the animation by setting animation-delay. - e.style.animationDelay = "-200s"; - - // Wait for the single MutationRecord for the Animation removal to - // be delivered. - yield waitForFrame(); - assert_records([{ added: [], changed: [], removed: animations }], - "records after animation end"); - - e.style = ""; - }); - // Test that starting a single animation that is cancelled by updating // the animation-fill-mode property dispatches an added notification and // then a removed notification. @@ -412,90 +319,6 @@ function assert_records_any_order(expected, desc) { e.style = ""; }); - // Test that starting a single animation that is cancelled by updating - // the animation-iteration-count property dispatches an added notification - // and then a removed notification. - addAsyncAnimTest("single_animation_cancelled_iteration_count", - aOptions, function*() { - // Start a short, repeated animation. - e.style = "animation: anim 0.5s infinite;"; - - // The animation should cause the creation of a single Animation. - var animations = e.getAnimations(); - is(animations.length, 1, "getAnimations().length after animation start"); - - // Wait for the single MutationRecord for the Animation addition to - // be delivered. - yield waitForFrame(); - assert_records([{ added: animations, changed: [], removed: [] }], - "records after animation start"); - - // Advance the animation until we are past the first iteration. - animations[0].currentTime += 1 * MS_PER_SEC; - - // The only MutationRecord at this point should be the change from - // seeking the Animation. - yield waitForFrame(); - assert_records([{ added: [], changed: animations, removed: [] }], - "records after seeking animations"); - - // Cancel the animation by setting animation-iteration-count. - e.style.animationIterationCount = "1"; - - // Wait for the single MutationRecord for the Animation removal to - // be delivered. - yield waitForFrame(); - assert_records([{ added: [], changed: [], removed: animations }], - "records after animation end"); - - e.style = ""; - }); - - // Test that updating an animation property dispatches a changed notification. - [ - { name: "duration", prop: "animationDuration", val: "200s" }, - { name: "timing", prop: "animationTimingFunction", val: "linear" }, - { name: "iteration", prop: "animationIterationCount", val: "2" }, - { name: "direction", prop: "animationDirection", val: "reverse" }, - { name: "state", prop: "animationPlayState", val: "paused" }, - { name: "delay", prop: "animationDelay", val: "-1s" }, - { name: "fill", prop: "animationFillMode", val: "both" }, - ].forEach(aChangeTest => { - addAsyncAnimTest(`single_animation_change_${aChangeTest.name}`, aOptions, function*() { - // Start a long animation. - e.style = "animation: anim 100s;"; - - // The animation should cause the creation of a single Animation. - var animations = e.getAnimations(); - is(animations.length, 1, "getAnimations().length after animation start"); - - // Wait for the single MutationRecord for the Animation addition to - // be delivered. - yield waitForFrame(); - assert_records([{ added: animations, changed: [], removed: [] }], - "records after animation start"); - - // Change a property of the animation such that it keeps running. - e.style[aChangeTest.prop] = aChangeTest.val; - - // Wait for the single MutationRecord for the Animation change to - // be delivered. - yield waitForFrame(); - assert_records([{ added: [], changed: animations, removed: [] }], - "records after animation change"); - - // Cancel the animation. - e.style.animationName = "none"; - - // Wait for the addition, change and removal MutationRecords to be delivered. - yield waitForFrame(); - assert_records([{ added: [], changed: [], removed: animations }], - "records after animation end"); - - e.style = ""; - }); - }); - // Test that calling finish() on a paused (but otherwise finished) animation // dispatches a changed notification. addAsyncAnimTest("finish_from_pause", aOptions, function*() { @@ -551,53 +374,6 @@ function assert_records_any_order(expected, desc) { "records after animation end"); }); - // Test that calling finish() on a pause-pending (but otherwise finished) - // animation dispatches a changed notification. - addAsyncAnimTest("finish_from_pause_pending", aOptions, function*() { - // Start a long animation - e.style = "animation: anim 100s forwards"; - - // The animation should cause the creation of a single Animation. - var animations = e.getAnimations(); - is(animations.length, 1, "getAnimations().length after animation start"); - - // Wait for the single MutationRecord for the Animation addition to - // be delivered. - yield waitForFrame(); - assert_records([{ added: animations, changed: [], removed: [] }], - "records after animation start"); - - // Wait until the animation is playing. - yield animations[0].ready; - - // Finish and pause. - animations[0].finish(); - animations[0].pause(); - is(animations[0].playState, "paused", - "playState after finishing and calling pause()"); - - // Call finish() again to abort the pause - animations[0].finish(); - is(animations[0].playState, "finished", - "playState after finishing again"); - - // Wait for three MutationRecords for the Animation changes to - // be delivered: one for each finish(), pause(), finish() operation. - yield waitForFrame(); - assert_records([{ added: [], changed: animations, removed: [] }, - { added: [], changed: animations, removed: [] }, - { added: [], changed: animations, removed: [] }], - "records after finish(), pause(), finish()"); - - // Cancel the animation. - e.style = ""; - - // Wait for the single removal notification. - yield waitForFrame(); - assert_records([{ added: [], changed: [], removed: animations }], - "records after animation end"); - }); - // Test that calling play() on a paused Animation dispatches a changed // notification. addAsyncAnimTest("play", aOptions, function*() { @@ -642,233 +418,6 @@ function assert_records_any_order(expected, desc) { "records after animation end"); }); - // Test that calling play() on a finished Animation that fills forwards - // dispatches a changed notification. - addAsyncAnimTest("play_filling_forwards", aOptions, function*() { - // Start a long animation with a forwards fill - e.style = "animation: anim 100s forwards"; - - // The animation should cause the creation of a single Animation. - var animations = e.getAnimations(); - is(animations.length, 1, "getAnimations().length after animation start"); - - // Wait for the single MutationRecord for the Animation addition to - // be delivered. - yield waitForFrame(); - assert_records([{ added: animations, changed: [], removed: [] }], - "records after animation start"); - - // Wait until the animation is ready - yield animations[0].ready; - - // Seek to the end - animations[0].finish(); - - // Wait for the single MutationRecord for the Animation change to - // be delivered. - yield waitForFrame(); - assert_records([{ added: [], changed: animations, removed: [] }], - "records after finish()"); - - // Since we are filling forwards, calling play() should produce a - // change record since the animation remains relevant. - animations[0].play(); - - // Wait for the single MutationRecord for the Animation change to - // be delivered. - yield waitForFrame(); - assert_records([{ added: [], changed: animations, removed: [] }], - "records after play()"); - - // Cancel the animation. - e.style = ""; - - // Wait for the single removal notification. - yield waitForFrame(); - assert_records([{ added: [], changed: [], removed: animations }], - "records after animation end"); - }); - - // Test that calling play() on a finished Animation that does *not* fill - // forwards dispatches an addition notification. - addAsyncAnimTest("play_after_finish", aOptions, function*() { - // Start a long animation - e.style = "animation: anim 100s"; - - // The animation should cause the creation of a single Animation. - var animations = e.getAnimations(); - is(animations.length, 1, "getAnimations().length after animation start"); - - // Wait for the single MutationRecord for the Animation addition to - // be delivered. - yield waitForFrame(); - assert_records([{ added: animations, changed: [], removed: [] }], - "records after animation start"); - - // Wait until the animation is ready - yield animations[0].ready; - - // Seek to the end - animations[0].finish(); - - // Wait for the single MutationRecord for the Animation removal to - // be delivered. - yield waitForFrame(); - assert_records([{ added: [], changed: [], removed: animations }], - "records after finish()"); - - // Since we are *not* filling forwards, calling play() is equivalent - // to creating a new animation since it becomes relevant again. - animations[0].play(); - - // Wait for the single MutationRecord for the Animation addition to - // be delivered. - yield waitForFrame(); - assert_records([{ added: animations, changed: [], removed: [] }], - "records after play()"); - - // Cancel the animation. - e.style = ""; - - // Wait for the single removal notification. - yield waitForFrame(); - assert_records([{ added: [], changed: [], removed: animations }], - "records after animation end"); - }); - - // Test that calling pause() on an Animation dispatches a changed - // notification. - addAsyncAnimTest("pause", aOptions, function*() { - // Start a long animation - e.style = "animation: anim 100s"; - - // The animation should cause the creation of a single Animation. - var animations = e.getAnimations(); - is(animations.length, 1, "getAnimations().length after animation start"); - - // Wait for the single MutationRecord for the Animation addition to - // be delivered. - yield waitForFrame(); - assert_records([{ added: animations, changed: [], removed: [] }], - "records after animation start"); - - // Wait until the animation is ready - yield animations[0].ready; - - // Pause - animations[0].pause(); - - // Wait for the single MutationRecord for the Animation change to - // be delivered. - yield animations[0].ready; - assert_records([{ added: [], changed: animations, removed: [] }], - "records after pause()"); - - // Redundant pause - animations[0].pause(); - - // Wait to ensure no change is dispatched - yield animations[0].ready; - assert_records([], "records after redundant pause()"); - - // Cancel the animation. - e.style = ""; - // Explicitly flush style to make sure the above style change happens. - // That's because after the above `animations[0].ready` we are the state - // just before the next tick happens. So if we waited for a - // requestAnimationFrame as usual here, we have no chance to process the - // style change since requestAnimationFrame is processed prior to styling. - flushComputedStyle(e); - - // Wait for the single removal notification. - yield waitForFrame(); - assert_records([{ added: [], changed: [], removed: animations }], - "records after animation end"); - }); - - // Test that calling pause() on an Animation that is pause-pending - // does not dispatch an additional changed notification. - addAsyncAnimTest("pause_while_pause_pending", aOptions, function*() { - // Start a long animation - e.style = "animation: anim 100s"; - - // The animation should cause the creation of a single Animation. - var animations = e.getAnimations(); - is(animations.length, 1, "getAnimations().length after animation start"); - - // Wait for the single MutationRecord for the Animation addition to - // be delivered. - yield waitForFrame(); - assert_records([{ added: animations, changed: [], removed: [] }], - "records after animation start"); - - // Wait until the animation is ready - yield animations[0].ready; - - // Pause - animations[0].pause(); - - // We are now pause-pending, but pause again - animations[0].pause(); - - // We should only get a single change record - yield animations[0].ready; - assert_records([{ added: [], changed: animations, removed: [] }], - "records after pause()"); - - // Cancel the animation. - e.style = ""; - // Explicitly flush style as with the above test. - flushComputedStyle(e); - - // Wait for the single removal notification. - yield waitForFrame(); - assert_records([{ added: [], changed: [], removed: animations }], - "records after animation end"); - }); - - // Test that calling play() on an Animation that is pause-pending - // dispatches a changed notification. - addAsyncAnimTest("aborted_pause", aOptions, function*() { - // Start a long animation - e.style = "animation: anim 100s"; - - // The animation should cause the creation of a single Animation. - var animations = e.getAnimations(); - is(animations.length, 1, "getAnimations().length after animation start"); - - // Wait for the single MutationRecord for the Animation addition to - // be delivered. - yield waitForFrame(); - assert_records([{ added: animations, changed: [], removed: [] }], - "records after animation start"); - - // Wait until the animation is ready - yield animations[0].ready; - - // Pause - animations[0].pause(); - - // We are now pause-pending. If we play() now, we will abort the pause - animations[0].play(); - - // We should get two change records - yield animations[0].ready; - assert_records([{ added: [], changed: animations, removed: [] }, - { added: [], changed: animations, removed: [] }], - "records after aborting a pause()"); - - // Cancel the animation. - e.style = ""; - // Explicitly flush style as with the above test. - flushComputedStyle(e); - - // Wait for the single removal notification. - yield waitForFrame(); - assert_records([{ added: [], changed: [], removed: animations }], - "records after animation end"); - }); - // Test that a non-cancelling change to an animation followed immediately by a // cancelling change will only send an animation removal notification. addAsyncAnimTest("coalesce_change_cancel", aOptions, function*() { diff --git a/dom/animation/test/chrome/test_animation_observers_sync.html b/dom/animation/test/chrome/test_animation_observers_sync.html index df7d1a4eccf7..af4ce2cc434f 100644 --- a/dom/animation/test/chrome/test_animation_observers_sync.html +++ b/dom/animation/test/chrome/test_animation_observers_sync.html @@ -1028,6 +1028,432 @@ function runTest() { "records after other transition ends"); }, "multiple_transitions"); + // Test that starting a single animation that is cancelled by resetting + // the animation-name property dispatches an added notification and + // then a removed notification. + test(t => { + var div = + addDiv(t, { style: "animation: anim 100s" }); + var observer = + setupSynchronousObserver(t, + aOptions.subtree ? div.parentNode : div, + aOptions.subtree); + + // The animation should cause the creation of a single Animation. + var animations = div.getAnimations(); + assert_equals(animations.length, 1, + "getAnimations().length after animation start"); + + assert_equals_records(observer.takeRecords(), + [{ added: animations, changed: [], removed: [] }], + "records after animation start"); + + // Cancel the animation by setting animation-name. + div.style.animationName = "none"; + getComputedStyle(div).animationName; + + assert_equals_records(observer.takeRecords(), + [{ added: [], changed: [], removed: animations }], + "records after animation end"); + }, "single_animation_cancelled_name"); + + // Test that starting a single animation that is cancelled by updating + // the animation-duration property dispatches an added notification and + // then a removed notification. + test(t => { + var div = + addDiv(t, { style: "animation: anim 100s" }); + var observer = + setupSynchronousObserver(t, + aOptions.subtree ? div.parentNode : div, + aOptions.subtree); + + // The animation should cause the creation of a single Animation. + var animations = div.getAnimations(); + assert_equals(animations.length, 1, + "getAnimations().length after animation start"); + + assert_equals_records(observer.takeRecords(), + [{ added: animations, changed: [], removed: [] }], + "records after animation start"); + + // Advance the animation by a second. + animations[0].currentTime += 1 * MS_PER_SEC; + + // Cancel the animation by setting animation-duration to a value less + // than a second. + div.style.animationDuration = "0.1s"; + getComputedStyle(div).animationName; + + assert_equals_records(observer.takeRecords(), + [{ added: [], changed: animations, removed: [] }, + { added: [], changed: [], removed: animations }], + "records after animation end"); + }, "single_animation_cancelled_duration"); + + // Test that starting a single animation that is cancelled by updating + // the animation-delay property dispatches an added notification and + // then a removed notification. + test(t => { + var div = + addDiv(t, { style: "animation: anim 100s" }); + var observer = + setupSynchronousObserver(t, + aOptions.subtree ? div.parentNode : div, + aOptions.subtree); + + // The animation should cause the creation of a single Animation. + var animations = div.getAnimations(); + assert_equals(animations.length, 1, + "getAnimations().length after animation start"); + + assert_equals_records(observer.takeRecords(), + [{ added: animations, changed: [], removed: [] }], + "records after animation start"); + + // Cancel the animation by setting animation-delay. + div.style.animationDelay = "-200s"; + getComputedStyle(div).animationName; + + assert_equals_records(observer.takeRecords(), + [{ added: [], changed: [], removed: animations }], + "records after animation end"); + }, "single_animation_cancelled_delay"); + + // Test that starting a single animation that is cancelled by updating + // the animation-iteration-count property dispatches an added notification + // and then a removed notification. + test(t => { + // A short, repeated animation. + var div = + addDiv(t, { style: "animation: anim 0.5s infinite;" }); + var observer = + setupSynchronousObserver(t, + aOptions.subtree ? div.parentNode : div, + aOptions.subtree); + + // The animation should cause the creation of a single Animation. + var animations = div.getAnimations(); + assert_equals(animations.length, 1, + "getAnimations().length after animation start"); + + assert_equals_records(observer.takeRecords(), + [{ added: animations, changed: [], removed: [] }], + "records after animation start"); + + // Advance the animation until we are past the first iteration. + animations[0].currentTime += 1 * MS_PER_SEC; + + assert_equals_records(observer.takeRecords(), + [{ added: [], changed: animations, removed: [] }], + "records after seeking animations"); + + // Cancel the animation by setting animation-iteration-count. + div.style.animationIterationCount = "1"; + getComputedStyle(div).animationName; + + assert_equals_records(observer.takeRecords(), + [{ added: [], changed: [], removed: animations }], + "records after animation end"); + }, "single_animation_cancelled_iteration_count"); + + // Test that updating an animation property dispatches a changed notification. + [ + { name: "duration", prop: "animationDuration", val: "200s" }, + { name: "timing", prop: "animationTimingFunction", val: "linear" }, + { name: "iteration", prop: "animationIterationCount", val: "2" }, + { name: "direction", prop: "animationDirection", val: "reverse" }, + { name: "state", prop: "animationPlayState", val: "paused" }, + { name: "delay", prop: "animationDelay", val: "-1s" }, + { name: "fill", prop: "animationFillMode", val: "both" }, + ].forEach(aChangeTest => { + test(t => { + // Start a long animation. + var div = addDiv(t, { style: "animation: anim 100s;" }); + var observer = + setupSynchronousObserver(t, + aOptions.subtree ? div.parentNode : div, + aOptions.subtree); + + // The animation should cause the creation of a single Animation. + var animations = div.getAnimations(); + assert_equals(animations.length, 1, + "getAnimations().length after animation start"); + + assert_equals_records(observer.takeRecords(), + [{ added: animations, changed: [], removed: [] }], + "records after animation start"); + + // Change a property of the animation such that it keeps running. + div.style[aChangeTest.prop] = aChangeTest.val; + getComputedStyle(div).animationName; + + assert_equals_records(observer.takeRecords(), + [{ added: [], changed: animations, removed: [] }], + "records after animation change"); + + // Cancel the animation. + div.style.animationName = "none"; + getComputedStyle(div).animationName; + + assert_equals_records(observer.takeRecords(), + [{ added: [], changed: [], removed: animations }], + "records after animation end"); + }, `single_animation_change_${aChangeTest.name}`); + }); + + // Test that calling finish() on a pause-pending (but otherwise finished) + // animation dispatches a changed notification. + test(t => { + var div = + addDiv(t, { style: "animation: anim 100s forwards" }); + var observer = + setupSynchronousObserver(t, + aOptions.subtree ? div.parentNode : div, + aOptions.subtree); + + // The animation should cause the creation of a single Animation. + var animations = div.getAnimations(); + assert_equals(animations.length, 1, + "getAnimations().length after animation start"); + + assert_equals_records(observer.takeRecords(), + [{ added: animations, changed: [], removed: [] }], + "records after animation start"); + + // Finish and pause. + animations[0].finish(); + animations[0].pause(); + assert_equals(animations[0].playState, "paused", + "playState after finishing and calling pause()"); + + // Call finish() again to abort the pause + animations[0].finish(); + assert_equals(animations[0].playState, "finished", + "playState after finishing again"); + + // Wait for three MutationRecords for the Animation changes to + // be delivered: one for each finish(), pause(), finish() operation. + assert_equals_records(observer.takeRecords(), + [{ added: [], changed: animations, removed: [] }, + { added: [], changed: animations, removed: [] }, + { added: [], changed: animations, removed: [] }], + "records after finish(), pause(), finish()"); + + // Cancel the animation. + div.style = ""; + getComputedStyle(div).animationName; + + assert_equals_records(observer.takeRecords(), + [{ added: [], changed: [], removed: animations }], + "records after animation end"); + }, "finish_from_pause_pending"); + + // Test that calling play() on a finished Animation that fills forwards + // dispatches a changed notification. + test(t => { + // Animation with a forwards fill + var div = + addDiv(t, { style: "animation: anim 100s forwards" }); + var observer = + setupSynchronousObserver(t, + aOptions.subtree ? div.parentNode : div, + aOptions.subtree); + + // The animation should cause the creation of a single Animation. + var animations = div.getAnimations(); + assert_equals(animations.length, 1, + "getAnimations().length after animation start"); + + assert_equals_records(observer.takeRecords(), + [{ added: animations, changed: [], removed: [] }], + "records after animation start"); + + // Seek to the end + animations[0].finish(); + + assert_equals_records(observer.takeRecords(), + [{ added: [], changed: animations, removed: [] }], + "records after finish()"); + + // Since we are filling forwards, calling play() should produce a + // change record since the animation remains relevant. + animations[0].play(); + + assert_equals_records(observer.takeRecords(), + [{ added: [], changed: animations, removed: [] }], + "records after play()"); + + // Cancel the animation. + div.style = ""; + getComputedStyle(div).animationName; + + assert_equals_records(observer.takeRecords(), + [{ added: [], changed: [], removed: animations }], + "records after animation end"); + }, "play_filling_forwards"); + + // Test that calling pause() on an Animation dispatches a changed + // notification. + test(t => { + var div = + addDiv(t, { style: "animation: anim 100s" }); + var observer = + setupSynchronousObserver(t, + aOptions.subtree ? div.parentNode : div, + aOptions.subtree); + + // The animation should cause the creation of a single Animation. + var animations = div.getAnimations(); + assert_equals(animations.length, 1, + "getAnimations().length after animation start"); + + assert_equals_records(observer.takeRecords(), + [{ added: animations, changed: [], removed: [] }], + "records after animation start"); + + // Pause + animations[0].pause(); + + assert_equals_records(observer.takeRecords(), + [{ added: [], changed: animations, removed: [] }], + "records after pause()"); + + // Redundant pause + animations[0].pause(); + + assert_equals_records(observer.takeRecords(), + [], "records after redundant pause()"); + + // Cancel the animation. + div.style = ""; + getComputedStyle(div).animationName; + + assert_equals_records(observer.takeRecords(), + [{ added: [], changed: [], removed: animations }], + "records after animation end"); + }, "pause"); + + // Test that calling pause() on an Animation that is pause-pending + // does not dispatch an additional changed notification. + test(t => { + var div = + addDiv(t, { style: "animation: anim 100s" }); + var observer = + setupSynchronousObserver(t, + aOptions.subtree ? div.parentNode : div, + aOptions.subtree); + + // The animation should cause the creation of a single Animation. + var animations = div.getAnimations(); + assert_equals(animations.length, 1, + "getAnimations().length after animation start"); + + assert_equals_records(observer.takeRecords(), + [{ added: animations, changed: [], removed: [] }], + "records after animation start"); + + // Pause + animations[0].pause(); + + // We are now pause-pending, but pause again + animations[0].pause(); + + assert_equals_records(observer.takeRecords(), + [{ added: [], changed: animations, removed: [] }], + "records after pause()"); + + // Cancel the animation. + div.style = ""; + getComputedStyle(div).animationName; + + assert_equals_records(observer.takeRecords(), + [{ added: [], changed: [], removed: animations }], + "records after animation end"); + }, "pause_while_pause_pending"); + + // Test that calling play() on an Animation that is pause-pending + // dispatches a changed notification. + test(t => { + var div = + addDiv(t, { style: "animation: anim 100s" }); + var observer = + setupSynchronousObserver(t, + aOptions.subtree ? div.parentNode : div, + aOptions.subtree); + + // The animation should cause the creation of a single Animation. + var animations = div.getAnimations(); + assert_equals(animations.length, 1, + "getAnimations().length after animation start"); + + assert_equals_records(observer.takeRecords(), + [{ added: animations, changed: [], removed: [] }], + "records after animation start"); + + // Pause + animations[0].pause(); + + // We are now pause-pending. If we play() now, we will abort the pause + animations[0].play(); + + assert_equals_records(observer.takeRecords(), + [{ added: [], changed: animations, removed: [] }, + { added: [], changed: animations, removed: [] }], + "records after aborting a pause()"); + + // Cancel the animation. + div.style = ""; + getComputedStyle(div).animationName; + + assert_equals_records(observer.takeRecords(), + [{ added: [], changed: [], removed: animations }], + "records after animation end"); + }, "aborted_pause"); + + // Test that calling play() on a finished Animation that does *not* fill + // forwards dispatches an addition notification. + test(t => { + var div = + addDiv(t, { style: "animation: anim 100s" }); + var observer = + setupSynchronousObserver(t, + aOptions.subtree ? div.parentNode : div, + aOptions.subtree); + + // The animation should cause the creation of a single Animation. + var animations = div.getAnimations(); + assert_equals(animations.length, 1, + "getAnimations().length after animation start"); + + assert_equals_records(observer.takeRecords(), + [{ added: animations, changed: [], removed: [] }], + "records after animation start"); + + // Seek to the end + animations[0].finish(); + + assert_equals_records(observer.takeRecords(), + [{ added: [], changed: [], removed: animations }], + "records after finish()"); + + // Since we are *not* filling forwards, calling play() is equivalent + // to creating a new animation since it becomes relevant again. + animations[0].play(); + + assert_equals_records(observer.takeRecords(), + [{ added: animations, changed: [], removed: [] }], + "records after play()"); + + // Cancel the animation. + div.style = ""; + getComputedStyle(div).animationName; + + assert_equals_records(observer.takeRecords(), + [{ added: [], changed: [], removed: animations }], + "records after animation end"); + }, "play_after_finish"); + }); test(t => {