Home | History | Annotate | Download | only in js
      1 suite('group-player', function() {
      2   setup(function() {
      3     document.timeline._players = [];
      4     webAnimations1.timeline._players = [];
      5     this.elements = [];
      6 
      7     var animationMargin = function(target) {
      8       return new Animation(
      9           target,
     10           [
     11            {marginLeft: '0px'},
     12            {marginLeft: '100px'}
     13           ],
     14           500);
     15     };
     16     var animationColor = function(target) {
     17       return new Animation(
     18           target,
     19           [
     20            {backgroundColor: 'black'},
     21            {backgroundColor: 'white'}
     22           ],
     23           500);
     24     };
     25     var sequenceEmpty = function() {
     26       return new AnimationSequence();
     27     };
     28     var groupEmpty = function() {
     29       return new AnimationGroup();
     30     };
     31     var sequenceWithEffects = function(target) {
     32       return new AnimationSequence(
     33           [
     34            animationMargin(target),
     35            animationColor(target)
     36           ]);
     37     };
     38     var groupWithEffects = function(target) {
     39       return new AnimationGroup(
     40           [
     41            animationMargin(target),
     42            animationColor(target)
     43           ]);
     44     };
     45 
     46     var seqEmpty_source = sequenceEmpty();
     47 
     48     var seqSimple_target = document.createElement('div');
     49     this.elements.push(seqSimple_target);
     50     var seqSimple_source = sequenceWithEffects(seqSimple_target);
     51 
     52     var seqWithSeq_target = document.createElement('div');
     53     this.elements.push(seqWithSeq_target);
     54     var seqWithSeq_source = new AnimationSequence(
     55         [
     56          animationMargin(seqWithSeq_target),
     57          animationColor(seqWithSeq_target),
     58          sequenceWithEffects(seqWithSeq_target)
     59         ]);
     60 
     61     var seqWithGroup_target = document.createElement('div');
     62     this.elements.push(seqWithGroup_target);
     63     var seqWithGroup_source = new AnimationSequence(
     64         [
     65          animationMargin(seqWithGroup_target),
     66          animationColor(seqWithGroup_target),
     67          groupWithEffects(seqWithGroup_target)
     68         ]);
     69 
     70     var seqWithEmptyGroup_source = new AnimationSequence([groupEmpty()]);
     71     var seqWithEmptySeq_source = new AnimationSequence([sequenceEmpty()]);
     72 
     73     var groupEmpty_source = groupEmpty();
     74 
     75     var groupSimple_target = document.createElement('div');
     76     var groupSimple_source = groupWithEffects(groupSimple_target);
     77 
     78     var groupWithSeq_target = document.createElement('div');
     79     this.elements.push(groupWithSeq_target);
     80     var groupWithSeq_source = new AnimationGroup(
     81         [
     82          animationMargin(groupWithSeq_target),
     83          animationColor(groupWithSeq_target),
     84          sequenceWithEffects(groupWithSeq_target)
     85         ]);
     86 
     87     var groupWithGroup_target = document.createElement('div');
     88     this.elements.push(groupWithGroup_target);
     89     var groupWithGroup_source = new AnimationGroup(
     90         [
     91          animationMargin(groupWithGroup_target),
     92          animationColor(groupWithGroup_target),
     93          groupWithEffects(groupWithGroup_target)
     94         ]);
     95 
     96     var groupWithEmptyGroup_source = new AnimationGroup([groupEmpty()]);
     97     var groupWithEmptySeq_source = new AnimationGroup([sequenceEmpty()]);
     98 
     99     this.seqEmpty_source = seqEmpty_source;
    100     this.seqSimple_source = seqSimple_source;
    101     this.seqWithSeq_source = seqWithSeq_source;
    102     this.seqWithGroup_source = seqWithGroup_source;
    103     this.seqWithEmptyGroup_source = seqWithEmptyGroup_source;
    104     this.seqWithEmptySeq_source = seqWithEmptySeq_source;
    105 
    106     this.groupEmpty_source = groupEmpty_source;
    107     this.groupSimple_source = groupSimple_source;
    108     this.groupWithSeq_source = groupWithSeq_source;
    109     this.groupWithGroup_source = groupWithGroup_source;
    110     this.groupWithEmptyGroup_source = groupWithEmptyGroup_source;
    111     this.groupWithEmptySeq_source = groupWithEmptySeq_source;
    112 
    113     this.staticAnimation = function(target, value, duration) {
    114       var animation = new Animation(target, [{marginLeft: value}, {marginLeft: value}], duration);
    115       animation.testValue = value;
    116       return animation;
    117     };
    118     // The following animation structure looks like:
    119     // 44444
    120     // 11
    121     //   33
    122     //   2
    123     // 0
    124     this.complexTarget = document.createElement('div');
    125     this.elements.push(this.complexTarget);
    126     this.complexSource = new AnimationGroup([
    127       this.staticAnimation(this.complexTarget, '4px', 5),
    128       new AnimationSequence([
    129         this.staticAnimation(this.complexTarget, '1px', 2),
    130         new AnimationGroup([
    131           this.staticAnimation(this.complexTarget, '3px', 2),
    132           this.staticAnimation(this.complexTarget, '2px', 1),
    133         ]),
    134       ]),
    135       this.staticAnimation(this.complexTarget, '0px', 1),
    136     ]);
    137 
    138     this.target = document.createElement('div');
    139     this.elements.push(this.target);
    140 
    141     for (var i = 0; i < this.elements.length; i++)
    142       document.documentElement.appendChild(this.elements[i]);
    143   });
    144 
    145   teardown(function() {
    146     for (var i = 0; i < this.elements.length; i++) {
    147       if (this.elements[i].parent)
    148         this.elements[i].parent.removeChild(this.elements[i]);
    149     }
    150   });
    151 
    152   function simpleAnimationGroup() {
    153     return new AnimationGroup([new Animation(document.body, [], 2000), new Animation(document.body, [], 1000), new Animation(document.body, [], 3000)]);
    154   }
    155 
    156   function simpleAnimationSequence() {
    157     return new AnimationSequence([new Animation(document.body, [], 2000), new Animation(document.body, [], 1000), new Animation(document.body, [], 3000)]);
    158   }
    159 
    160   // FIXME: Remove _startOffset.
    161   // playerState is [startTime, currentTime, _startOffset?, offset?]
    162   // innerPlayerStates is a nested array tree of playerStates e.g. [[0, 0], [[1, -1], [2, -2]]]
    163   function checkTimes(player, playerState, innerPlayerStates, description) {
    164     description = description ? (description + ' ') : '';
    165     _checkTimes(player, playerState, 0, description + 'top player');
    166     _checkTimes(player, innerPlayerStates, 0, description + 'inner player');
    167   }
    168 
    169   function _checkTimes(player, timingList, index, trace) {
    170     assert.isDefined(player, trace + ' exists');
    171     if (timingList.length == 0) {
    172       assert.equal(player._childPlayers.length, index, trace + ' no remaining players');
    173       return;
    174     }
    175     if (timingList[0] === null || typeof timingList[0] == 'number') {
    176       assert.equal(player.startTime, timingList[0], trace + ' startTime');
    177       assert.equal(player.currentTime, timingList[1], trace + ' currentTime');
    178     } else {
    179       _checkTimes(player._childPlayers[index], timingList[0], 0, trace + ' ' + index);
    180       _checkTimes(player, timingList.slice(1), index + 1, trace);
    181     }
    182   }
    183 
    184   test('playing an animationGroup works as expected', function() {
    185     tick(90);
    186     var p = document.timeline.play(simpleAnimationGroup());
    187     checkTimes(p, [null, 0], [[null, 0], [null, 0], [null, 0]]);
    188     tick(100);
    189     checkTimes(p, [100, 0], [[100, 0], [100, 0], [100, 0]]);
    190     tick(300);
    191     checkTimes(p, [100, 200], [[100, 200], [100, 200], [100, 200]]);
    192     tick(1200);
    193     checkTimes(p, [100, 1100], [[100, 1100], [100, 1000], [100, 1100]]);
    194     tick(2200);
    195     checkTimes(p, [100, 2100], [[100, 2000], [100, 1000], [100, 2100]]);
    196     tick(3200);
    197     checkTimes(p, [100, 3000], [[100, 2000], [100, 1000], [100, 3000]]);
    198   });
    199 
    200   test('can seek an animationGroup', function() {
    201     tick(90);
    202     var p = document.timeline.play(simpleAnimationGroup());
    203     tick(100);
    204     checkTimes(p, [100, 0], [[100, 0], [100, 0], [100, 0]]);
    205     p.currentTime = 200;
    206     checkTimes(p, [-100, 200], [[-100, 200], [-100, 200], [-100, 200]]);
    207     p.currentTime = 1100;
    208     checkTimes(p, [-1000, 1100], [[-1000, 1100], [-1000, 1100], [-1000, 1100]]);
    209     p.currentTime = 2100;
    210     checkTimes(p, [-2000, 2100], [[-2000, 2100], [-2000, 2100], [-2000, 2100]]);
    211     p.currentTime = 3100;
    212     checkTimes(p, [-3000, 3100], [[-3000, 3100], [-3000, 3100], [-3000, 3100]]);
    213   });
    214 
    215   test('can startTime seek an animationGroup', function() {
    216     tick(90);
    217     var p = document.timeline.play(simpleAnimationGroup());
    218     tick(100);
    219     checkTimes(p, [100, 0], [[100, 0], [100, 0], [100, 0]]);
    220     p.startTime = -100;
    221     checkTimes(p, [-100, 200], [[-100, 200], [-100, 200], [-100, 200]]);
    222     p.startTime = -1000;
    223     checkTimes(p, [-1000, 1100], [[-1000, 1100], [-1000, 1000], [-1000, 1100]]);
    224     p.startTime = -2000;
    225     checkTimes(p, [-2000, 2100], [[-2000, 2000], [-2000, 1000], [-2000, 2100]]);
    226     p.startTime = -3000;
    227     checkTimes(p, [-3000, 3000], [[-3000, 2000], [-3000, 1000], [-3000, 3000]]);
    228   });
    229 
    230   test('playing an animationSequence works as expected', function() {
    231     tick(100);
    232     var p = document.timeline.play(simpleAnimationSequence());
    233     tick(110);
    234     checkTimes(p, [110, 0], [[110, 0], [2110, -2000], [3110, -3000]]);
    235     tick(210);
    236     checkTimes(p, [110, 100], [[110, 100], [2110, -1900], [3110, -2900]]);
    237     tick(2210);
    238     checkTimes(p, [110, 2100], [[110, 2000], [2110, 100], [3110, -900]]);
    239     tick(3210);
    240     checkTimes(p, [110, 3100], [[110, 2000], [2110, 1000], [3110, 100]]);
    241     tick(6210);
    242     checkTimes(p, [110, 6000], [[110, 2000], [2110, 1000], [3110, 3000]]);
    243   });
    244 
    245   test('can seek an animationSequence', function() {
    246     tick(100);
    247     var p = document.timeline.play(simpleAnimationSequence());
    248     tick(110);
    249     checkTimes(p, [110, 0], [[110, 0], [2110, -2000], [3110, -3000]]);
    250     p.currentTime = 100;
    251     checkTimes(p, [10, 100], [[10, 100], [2010, -1900], [3010, -2900]]);
    252     p.currentTime = 2100;
    253     checkTimes(p, [-1990, 2100], [[-1990, 2100], [10, 100], [1010, -900]]);
    254     p.currentTime = 3100;
    255     checkTimes(p, [-2990, 3100], [[-2990, 3100], [-990, 1100], [10, 100]]);
    256     p.currentTime = 6100;
    257     checkTimes(p, [-5990, 6100], [[-5990, 6100], [-3990, 4100], [-2990, 3100]]);
    258   });
    259 
    260   test('can startTime seek an animationSequence', function() {
    261     tick(100);
    262     var p = document.timeline.play(simpleAnimationSequence());
    263     tick(110);
    264     checkTimes(p, [110, 0], [[110, 0], [2110, -2000], [3110, -3000]]);
    265     p.startTime = 10;
    266     checkTimes(p, [10, 100], [[10, 100], [2010, -1900], [3010, -2900]]);
    267     p.startTime = -1990;
    268     checkTimes(p, [-1990, 2100], [[-1990, 2000], [10, 100], [1010, -900]]);
    269     p.startTime = -2990;
    270     checkTimes(p, [-2990, 3100], [[-2990, 2000], [-990, 1000], [10, 100]]);
    271     p.startTime = -5990;
    272     checkTimes(p, [-5990, 6000], [[-5990, 2000], [-3990, 1000], [-2990, 3000]]);
    273   });
    274 
    275   test('complex animation tree timing while playing', function() {
    276     tick(90);
    277     var player = document.timeline.play(this.complexSource);
    278     tick(100);
    279     checkTimes(player, [100, 0], [
    280       [100, 0], [ // 4
    281         [100, 0], [ // 1
    282           [102, -2], // 3
    283           [102, -2]]], // 2
    284       [100, 0], // 0
    285     ], 't = 100');
    286     tick(101);
    287     checkTimes(player, [100, 1], [
    288       [100, 1], [ // 4
    289         [100, 1], [ // 1
    290           [102, -1], // 3
    291           [102, -1]]], // 2
    292       [100, 1], // 0
    293     ], 't = 101');
    294     tick(102);
    295     checkTimes(player, [100, 2], [
    296       [100, 2], [ // 4
    297         [100, 2], [ // 1
    298           [102, 0], // 3
    299           [102, 0]]], // 2
    300       [100, 1], // 0
    301     ], 't = 102');
    302   });
    303 
    304   test('effects apply in the correct order', function() {
    305     tick(0);
    306     var player = document.timeline.play(this.complexSource);
    307     player.currentTime = 0;
    308     assert.equal(getComputedStyle(this.complexTarget).marginLeft, '0px');
    309     player.currentTime = 1;
    310     checkTimes(player, [-1, 1], [[-1, 1, 0], [[-1, 1, 0], [[1, -1, 0], [1, -1, 0]]], [-1, 1, 0]]);
    311     assert.equal(getComputedStyle(this.complexTarget).marginLeft, '1px');
    312     player.currentTime = 2;
    313     // TODO: When we seek we don't limit. Is this OK?
    314     checkTimes(player, [-2, 2], [[-2, 2, 0], [[-2, 2, 0], [[0, 0, 0], [0, 0, 0]]], [-2, 2, 0]]);
    315     assert.equal(getComputedStyle(this.complexTarget).marginLeft, '2px');
    316     player.currentTime = 3;
    317     assert.equal(getComputedStyle(this.complexTarget).marginLeft, '3px');
    318     player.currentTime = 4;
    319     assert.equal(getComputedStyle(this.complexTarget).marginLeft, '4px');
    320     player.currentTime = 5;
    321     assert.equal(getComputedStyle(this.complexTarget).marginLeft, '0px');
    322   });
    323 
    324   test('cancelling group players', function() {
    325     tick(0);
    326     var player = document.timeline.play(this.complexSource);
    327     tick(1);
    328     tick(4);
    329     assert.equal(getComputedStyle(this.complexTarget).marginLeft, '3px');
    330     player.cancel();
    331     assert.equal(player.currentTime, null);
    332     assert.equal(getComputedStyle(this.complexTarget).marginLeft, '0px');
    333   });
    334 
    335   test('cancelling group players before tick', function() {
    336     tick(0);
    337     var player = document.timeline.play(this.complexSource);
    338     player.cancel();
    339     assert.equal(player.currentTime, null);
    340     assert.equal(getComputedStyle(this.complexTarget).marginLeft, '0px');
    341     tick(4);
    342     assert.equal(player.currentTime, null);
    343     assert.equal(getComputedStyle(this.complexTarget).marginLeft, '0px');
    344   });
    345 
    346   test('redundant animation node wrapping', function() {
    347     tick(100);
    348     var animation = new AnimationSequence([
    349       this.staticAnimation(this.target, '0px', 1),
    350       new AnimationGroup([
    351         new AnimationSequence([
    352           this.staticAnimation(this.target, '1px', 1),
    353           this.staticAnimation(this.target, '2px', 1),
    354         ]),
    355       ]),
    356     ]);
    357     var player = document.timeline.play(animation);
    358     assert.equal(getComputedStyle(this.target).marginLeft, '0px');
    359     checkTimes(player, [100, 0], [
    360       [100, 0, 0, 0], [[ // 0
    361         [101, -1, 0, 1], // 1
    362         [102, -2, 1, 2]]] // 2
    363     ], 't = 100');
    364     tick(101);
    365     assert.equal(getComputedStyle(this.target).marginLeft, '1px');
    366     checkTimes(player, [100, 1], [
    367       [100, 1, 0, 0], [[ // 0
    368         [101, 0, 0, 1], // 1
    369         [102, -1, 1, 2]]] // 2
    370     ], 't = 101');
    371     tick(102);
    372     assert.equal(getComputedStyle(this.target).marginLeft, '2px');
    373     assert.equal(document.timeline.currentTime, 102);
    374     checkTimes(player, [100, 2], [ // FIXME: Implement limiting on group players
    375       [100, 1, 0, 0], [[ // 0
    376         [101, 1, 0, 1], // 1
    377         [102, 0, 1, 2]]] // 2
    378     ], 't = 102');
    379     tick(103);
    380     assert.equal(getComputedStyle(this.target).marginLeft, '0px');
    381     checkTimes(player, [100, 3], [ // FIXME: Implement limiting on group players
    382       [100, 1, 0, 0], [[ // 0
    383         [101, 1, 0, 1], // 1
    384         [102, 1, 1, 2]]] // 2
    385     ], 't = 103');
    386     if (this.target.parent)
    387       this.target.parent.removeChild(target);
    388   });
    389 
    390   test('setting the playbackRate on group players', function() {
    391     var group = new AnimationGroup([
    392       new Animation(null, [], 1234),
    393       new Animation(null, [], 1234),
    394     ]);
    395     var p = document.timeline.play(group);
    396     p.playbackRate = 2;
    397     assert.equal(p._player.playbackRate, 2, 'Updates the playbackRate of the inner player');
    398     p._childPlayers.forEach(function(childPlayer) {
    399       assert.equal(childPlayer.playbackRate, 2, 'It also updates the child players');
    400     });
    401   });
    402 
    403   test('delays on groups work correctly', function() {
    404     //   444
    405     //  1
    406     // 0
    407     //   33
    408     //   2
    409     var animation = new AnimationGroup([
    410       new AnimationGroup([
    411         this.staticAnimation(this.target, '4px', {duration: 3, delay: 1}),
    412         this.staticAnimation(this.target, '1px', {duration: 1, delay: 0}),
    413       ], {delay: 1}),
    414       new AnimationSequence([
    415         this.staticAnimation(this.target, '0px', {duration: 1, delay: 0}),
    416         this.staticAnimation(this.target, '3px', {duration: 2, delay: 1}),
    417         this.staticAnimation(this.target, '2px', {duration: 1, delay: -2}),
    418       ]),
    419     ]);
    420     var player = document.timeline.play(animation);
    421     tick(100);
    422     checkTimes(player, [100, 0], [
    423       [
    424         [101, -1],
    425         [101, -1],
    426       ], [
    427         [100, 0],
    428         [101, -1],
    429         [104, -4],
    430       ]
    431     ]);
    432     assert.equal(getComputedStyle(this.target).marginLeft, '0px');
    433     tick(101);
    434     assert.equal(getComputedStyle(this.target).marginLeft, '1px');
    435     tick(102);
    436     assert.equal(getComputedStyle(this.target).marginLeft, '2px');
    437     tick(103);
    438     assert.equal(getComputedStyle(this.target).marginLeft, '3px');
    439     tick(104);
    440     assert.equal(getComputedStyle(this.target).marginLeft, '4px');
    441     tick(105);
    442     assert.equal(getComputedStyle(this.target).marginLeft, '0px');
    443   });
    444 
    445   test('end delays on groups work correctly', function() {
    446     // 11
    447     //     4
    448     // 0
    449     //   33
    450     //   2
    451     var animation = new AnimationSequence([
    452       new AnimationSequence([
    453         this.staticAnimation(this.target, '1px', {duration: 2, endDelay: 2}),
    454         this.staticAnimation(this.target, '4px', {duration: 1, endDelay: 1}),
    455       ], {endDelay: -6}),
    456       new AnimationSequence([
    457         this.staticAnimation(this.target, '0px', {duration: 1, endDelay: 1}),
    458         this.staticAnimation(this.target, '3px', {duration: 2, endDelay: -2}),
    459         this.staticAnimation(this.target, '2px', {duration: 1, endDelay: 2}),
    460       ]),
    461     ]);
    462     var player = document.timeline.play(animation);
    463     tick(100);
    464     checkTimes(player, [100, 0], [
    465       [
    466         [100, 0],
    467         [104, -4],
    468       ], [
    469         [100, 0],
    470         [102, -2],
    471         [102, -2],
    472       ]
    473     ]);
    474     assert.equal(getComputedStyle(this.target).marginLeft, '0px');
    475     tick(101);
    476     assert.equal(getComputedStyle(this.target).marginLeft, '1px');
    477     tick(102);
    478     assert.equal(getComputedStyle(this.target).marginLeft, '2px');
    479     tick(103);
    480     assert.equal(getComputedStyle(this.target).marginLeft, '3px');
    481     tick(104);
    482     // FIXME: Group child player limiting bounds should match the parent player's limiting bounds.
    483     // assert.equal(getComputedStyle(this.target).marginLeft, '4px');
    484     // tick(105);
    485     // assert.equal(getComputedStyle(this.target).marginLeft, '0px');
    486   });
    487 
    488   // FIXME: This test can be removed when this suite is finished.
    489   test('sources are working for basic operations', function() {
    490     var players = [];
    491     players.push(document.timeline.play(this.seqEmpty_source));
    492     players.push(document.timeline.play(this.seqSimple_source));
    493     players.push(document.timeline.play(this.seqWithSeq_source));
    494     players.push(document.timeline.play(this.seqWithGroup_source));
    495     players.push(document.timeline.play(this.seqWithEmptyGroup_source));
    496     players.push(document.timeline.play(this.seqWithEmptySeq_source));
    497 
    498     players.push(document.timeline.play(this.groupEmpty_source));
    499     players.push(document.timeline.play(this.groupSimple_source));
    500     players.push(document.timeline.play(this.groupWithSeq_source));
    501     players.push(document.timeline.play(this.groupWithGroup_source));
    502     players.push(document.timeline.play(this.groupWithEmptyGroup_source));
    503     players.push(document.timeline.play(this.groupWithEmptySeq_source));
    504 
    505     var length = players.length;
    506 
    507     tick(50);
    508     for (var i = 0; i < length; i++)
    509       players[i].pause();
    510 
    511     tick(100);
    512     for (var i = 0; i < length; i++)
    513       players[i].play();
    514 
    515     tick(200);
    516     for (var i = 0; i < length; i++)
    517       players[i].currentTime += 1;
    518 
    519     tick(300);
    520     for (var i = 0; i < length; i++)
    521       players[i].startTime += 1;
    522 
    523     tick(350);
    524     for (var i = 0; i < length; i++)
    525       players[i].reverse();
    526 
    527     tick(400);
    528     for (var i = 0; i < length; i++)
    529       players[i].finish();
    530 
    531     tick(500);
    532     tick(600);
    533     for (var i = 0; i < length; i++)
    534       players[i].cancel();
    535 
    536     for (var i = 0; i < length; i++)
    537       players[i].play();
    538   });
    539 
    540   test('pausing works as expected with an empty AnimationSequence', function() {
    541     var player = document.timeline.play(this.seqEmpty_source);
    542     tick(0);
    543     assert.equal(player.startTime, 0);
    544     assert.equal(player.currentTime, 0);
    545 
    546     player.pause();
    547     assert.equal(player.startTime, null);
    548     assert.equal(player.currentTime, 0);
    549   });
    550 
    551   test('pausing works as expected with a simple AnimationSequence', function() {
    552     var player = document.timeline.play(this.seqSimple_source);
    553     var target = this.seqSimple_source.children[0].target;
    554     tick(0);
    555     checkTimes(player, [0, 0], [[0, 0], [500, -500]], 't = 0');
    556 
    557     tick(200);
    558     checkTimes(player, [0, 200], [[0, 200], [500, -300]], 't = 200');
    559 
    560     player.pause();
    561     checkTimes(player, [null, null], [[null, null], [null, null]], 't = 200');
    562     assert.equal(getComputedStyle(target).marginLeft, '40px');
    563 
    564     tick(300);
    565     checkTimes(player, [null, 200], [[null, 200], [null, -300]], 't = 300');
    566     assert.equal(getComputedStyle(target).marginLeft, '40px');
    567 
    568     player.play();
    569     checkTimes(player, [null, 200], [[null, 200], [null, -300]], 't = 300');
    570     assert.equal(getComputedStyle(target).marginLeft, '40px');
    571 
    572     tick(301);
    573     checkTimes(player, [101, 200], [[101, 200], [601, -300]], 't = 301');
    574     assert.equal(getComputedStyle(target).marginLeft, '40px');
    575 
    576     tick(401);
    577     checkTimes(player, [101, 300], [[101, 300], [601, -200]], 't = 401');
    578     assert.equal(getComputedStyle(target).marginLeft, '60px');
    579 
    580     tick(700);
    581     checkTimes(player, [101, 599], [[101, 500], [601, 99]], 't = 700');
    582     assert.equal(getComputedStyle(target).marginLeft, '0px');
    583   });
    584 
    585   test('pausing before tick works as expected with a simple AnimationSequence', function() {
    586     var player = document.timeline.play(this.seqSimple_source);
    587     var target = this.seqSimple_source.children[0].target;
    588     checkTimes(player, [null, 0], [[null, 0], [null, -500]], 't = 0');
    589 
    590     player.pause();
    591     checkTimes(player, [null, null], [[null, null], [null, null]], 't = 0');
    592     assert.equal(getComputedStyle(target).marginLeft, '0px');
    593 
    594     tick(10);
    595     checkTimes(player, [null, 0], [[null, 0], [null, -500]], 't = 10');
    596     assert.equal(getComputedStyle(target).marginLeft, '0px');
    597 
    598     tick(20);
    599     checkTimes(player, [null, 0], [[null, 0], [null, -500]], 't = 10');
    600     assert.equal(getComputedStyle(target).marginLeft, '0px');
    601   });
    602 
    603   test('pausing and seeking before tick works as expected with a simple AnimationSequence', function() {
    604     var player = document.timeline.play(this.seqSimple_source);
    605     player.pause();
    606 
    607     player.currentTime = 0;
    608     checkTimes(player, [null, 0], [[null, 0], [null, -500]], 't = 10');
    609 
    610     player.currentTime = 250;
    611     checkTimes(player, [null, 250], [[null, 250], [null, -250]], 't = 10');
    612 
    613     player.currentTime = 500;
    614     checkTimes(player, [null, 500], [[null, 500], [null, 0]], 't = 10');
    615 
    616     // FIXME: Expectation should be [null, 1000], [[null, 500], [null, 500]].
    617     player.currentTime = 1000;
    618     checkTimes(player, [null, 1000], [[null, 1000], [null, 500]], 't = 10');
    619   });
    620 
    621   test('pausing works as expected with an AnimationSequence inside an AnimationSequence', function() {
    622     var player = document.timeline.play(this.seqWithSeq_source);
    623     tick(0);
    624     checkTimes(
    625         player,
    626         [0, 0], [
    627           [0, 0],
    628           [500, -500], [
    629             [1000, -1000],
    630             [1500, -1500]]],
    631         't = 0');
    632 
    633     tick(200);
    634     checkTimes(
    635         player,
    636         [0, 200], [
    637           [0, 200],
    638           [500, -300], [
    639             [1000, -800],
    640             [1500, -1300]]],
    641         't = 200');
    642 
    643     player.pause();
    644     checkTimes(
    645         player,
    646         [null, null], [
    647           [null, null],
    648           [null, null], [
    649             [null, null],
    650             [null, null]]],
    651         't = 200');
    652 
    653     tick(300);
    654     checkTimes(
    655         player,
    656         [null, 200], [
    657           [null, 200],
    658           [null, -300], [
    659             [null, -800],
    660             [null, -1300]]],
    661         't = 300');
    662 
    663     player.play();
    664     tick(310);
    665     checkTimes(
    666         player,
    667         [110, 200], [
    668           [110, 200],
    669           [610, -300], [
    670             [1110, -800],
    671             [1610, -1300]]],
    672         't = 310');
    673 
    674     tick(1300);
    675     checkTimes(
    676         player,
    677         [110, 1190], [
    678           [110, 500],
    679           [610, 500], [
    680             [1110, 190],
    681             [1610, -310]]],
    682         't = 1300');
    683 
    684     player.pause();
    685     checkTimes(
    686         player,
    687         [null, null], [
    688           [null, 500],
    689           [null, 500], [
    690             [null, null],
    691             [null, null]]],
    692         't = 1300');
    693 
    694     tick(1400);
    695     checkTimes(
    696         player,
    697         [null, 1190], [
    698           [null, 500],
    699           [null, 500], [
    700             [null, 190],
    701             [null, -310]]],
    702         't = 1400');
    703 
    704     player.play();
    705     checkTimes(
    706         player,
    707         [null, 1190], [
    708           [null, 500],
    709           [null, 500], [
    710             [null, 190],
    711             [null, -310]]],
    712         't = 1400');
    713 
    714     tick(1410);
    715     checkTimes(
    716         player,
    717         [220, 1190], [
    718           [220, 500],
    719           [720, 500], [
    720             [1220, 190],
    721             [1720, -310]]],
    722         't = 1410');
    723 
    724     tick(1600);
    725     checkTimes(
    726         player,
    727         [220, 1380], [
    728           [220, 500],
    729           [720, 500], [
    730             [1220, 380],
    731             [1720, -120]]],
    732         't = 1600');
    733 
    734     player.pause();
    735     checkTimes(
    736         player,
    737         [null, null], [
    738           [null, 500],
    739           [null, 500], [
    740             [null, null],
    741             [null, null]]],
    742         't = 1600');
    743 
    744     tick(1700);
    745     checkTimes(
    746         player,
    747         [null, 1380], [
    748           [null, 500],
    749           [null, 500], [
    750             [null, 380],
    751             [null, -120]]],
    752         't = 1700');
    753 
    754     player.play();
    755     tick(1710);
    756     checkTimes(
    757         player,
    758         [330, 1380], [
    759           [330, 500],
    760           [830, 500], [
    761             [1330, 380],
    762             [1830, -120]]],
    763         't = 1710');
    764 
    765     tick(2400);
    766     checkTimes(
    767         player,
    768         [330, 2000], [
    769           [330, 500],
    770           [830, 500], [
    771             [1330, 500],
    772             [1830, 500]]],
    773         't = 2400');
    774   });
    775 
    776   test('pausing works as expected with an AnimationGroup inside an AnimationSequence', function() {
    777     var player = document.timeline.play(this.seqWithGroup_source);
    778     tick(0);
    779     checkTimes(
    780         player,
    781         [0, 0], [
    782           [0, 0],
    783           [500, -500], [
    784             [1000, -1000],
    785             [1000, -1000]]],
    786         't = 0');
    787 
    788     tick(200);
    789     checkTimes(
    790         player,
    791         [0, 200], [
    792           [0, 200],
    793           [500, -300], [
    794             [1000, -800],
    795             [1000, -800]]],
    796         't = 200');
    797 
    798     player.pause();
    799     checkTimes(
    800         player,
    801         [null, null], [
    802           [null, null],
    803           [null, null], [
    804             [null, null],
    805             [null, null]]],
    806         't = 200');
    807 
    808     tick(300);
    809     checkTimes(
    810         player,
    811         [null, 200], [
    812           [null, 200],
    813           [null, -300], [
    814             [null, -800],
    815             [null, -800]]],
    816         't = 300');
    817 
    818     player.play();
    819     tick(310);
    820     checkTimes(
    821         player,
    822         [110, 200], [
    823           [110, 200],
    824           [610, -300], [
    825             [1110, -800],
    826             [1110, -800]]],
    827         't = 310');
    828 
    829     tick(1310);
    830     checkTimes(
    831         player,
    832         [110, 1200], [
    833           [110, 500],
    834           [610, 500], [
    835             [1110, 200],
    836             [1110, 200]]],
    837         't = 1310');
    838 
    839     player.pause();
    840     checkTimes(
    841         player,
    842         [null, null], [
    843           [null, 500],
    844           [null, 500], [
    845             [null, null],
    846             [null, null]]],
    847         't = 1310');
    848 
    849     tick(1400);
    850     checkTimes(
    851         player,
    852         [null, 1200], [
    853           [null, 500],
    854           [null, 500], [
    855             [null, 200],
    856             [null, 200]]],
    857         't = 1410');
    858 
    859     player.play();
    860     tick(1410);
    861     checkTimes(
    862         player,
    863         [210, 1200], [
    864           [210, 500],
    865           [710, 500], [
    866             [1210, 200],
    867             [1210, 200]]],
    868         't = 1410');
    869 
    870     tick(1610);
    871     checkTimes(
    872         player,
    873         [210, 1400], [
    874           [210, 500],
    875           [710, 500], [
    876             [1210, 400],
    877             [1210, 400]]],
    878         't = 1610');
    879 
    880     player.pause();
    881     tick(1810);
    882     checkTimes(
    883         player,
    884         [null, 1400], [
    885           [null, 500],
    886           [null, 500], [
    887             [null, 400],
    888             [null, 400]]],
    889         't = 1810');
    890 
    891     player.play();
    892     tick(1820);
    893     checkTimes(
    894         player,
    895         [420, 1400], [
    896           [420, 500],
    897           [920, 500], [
    898             [1420, 400],
    899             [1420, 400]]],
    900         't = 1820');
    901 
    902     tick(2020);
    903     checkTimes(
    904         player,
    905         [420, 1500], [
    906           [420, 500],
    907           [920, 500], [
    908             [1420, 500],
    909             [1420, 500]]],
    910         't = 2020');
    911 
    912     player.pause();
    913     checkTimes(
    914         player,
    915         [null, 1500], [
    916           [null, 500],
    917           [null, 500], [
    918             [null, 500],
    919             [null, 500]]],
    920         't = 2020');
    921   });
    922 
    923   test('pausing works as expected with an empty AnimationSequence inside an AnimationSequence', function() {
    924     var player = document.timeline.play(this.seqWithEmptySeq_source);
    925     tick(0);
    926     checkTimes(
    927         player,
    928         [0, 0], [0, 0],
    929         't = 0');
    930 
    931     player.pause();
    932     checkTimes(
    933         player,
    934         [null, 0], [null, 0],
    935         't = 0 after pause');
    936   });
    937 
    938   test('pausing works as expected with an empty AnimationGroup inside an AnimationSequence', function() {
    939     var player = document.timeline.play(this.seqWithEmptyGroup_source);
    940     tick(0);
    941     checkTimes(
    942         player,
    943         [0, 0], [0, 0],
    944         't = 0');
    945 
    946     player.pause();
    947     checkTimes(
    948         player,
    949         [null, 0], [null, 0],
    950         't = 0 after pause');
    951   });
    952 
    953   test('playState works for groups', function() {
    954     var target = document.createElement('div');
    955     document.body.appendChild(target);
    956     var anim = new AnimationSequence([new Animation(target, [], 100), new Animation(target, [], 100)]);
    957     var p = document.timeline.play(anim);
    958     assert.equal(p.playState, 'pending');
    959     tick(1);
    960     assert.equal(p.playState, 'running');
    961     assert.equal(p._childPlayers[0]._player.playState, 'running');
    962     assert.equal(p._childPlayers[1]._player.playState, 'running');
    963     tick(101);
    964     assert.equal(p.playState, 'running');
    965     assert.equal(p._childPlayers[0]._player.playState, 'finished');
    966     assert.equal(p._childPlayers[1]._player.playState, 'running');
    967     p.pause();
    968     assert.equal(p.playState, 'pending');
    969     assert.equal(p._childPlayers[0]._player.playState, 'paused');
    970     assert.equal(p._childPlayers[1]._player.playState, 'pending');
    971     tick(102);
    972     assert.equal(p.playState, 'paused');
    973     assert.equal(p._childPlayers[0]._player.playState, 'paused');
    974     assert.equal(p._childPlayers[1]._player.playState, 'paused');
    975     p.play();
    976     assert.equal(p.playState, 'pending');
    977     assert.equal(p._childPlayers[0]._player.playState, 'pending');
    978     assert.equal(p._childPlayers[1]._player.playState, 'pending');
    979     tick(103);
    980     assert.equal(p.playState, 'running');
    981     assert.equal(p._childPlayers[0]._player.playState, 'finished');
    982     assert.equal(p._childPlayers[1]._player.playState, 'running');
    983     tick(204);
    984     assert.equal(p.playState, 'finished');
    985     assert.equal(p._childPlayers[0]._player.playState, 'finished');
    986     assert.equal(p._childPlayers[1]._player.playState, 'finished');
    987   });
    988 
    989   test('pausing then seeking out of range then seeking into range works', function() {
    990     var target = document.createElement('div');
    991     var anim = new Animation(target, [], {duration: 2000, fill: 'both'});
    992     var group = new AnimationGroup([anim], {fill: 'none'});
    993     var player = document.timeline.play(group);
    994 
    995     player.pause();
    996     player.currentTime = 3000;
    997     tick(100);
    998     player.currentTime = 1000;
    999     assert.equal(player._childPlayers.length, 1);
   1000     assert.equal(player._childPlayers[0]._player.playState, 'paused');
   1001     assert.equal(player._childPlayers[0]._player.currentTime, 1000);
   1002 
   1003   });
   1004 
   1005   test('reversing then seeking out of range then seeking into range works', function() {
   1006     var target = document.createElement('div');
   1007     var anim = new Animation(target, [], {duration: 2000, fill: 'both'});
   1008     var group = new AnimationGroup([anim], {fill: 'none'});
   1009     var player = document.timeline.play(group);
   1010 
   1011     player.currentTime = 1000;
   1012     tick(100);
   1013     player.reverse();
   1014     player.currentTime = 3000;
   1015     tick(110);
   1016     player.currentTime = 1000;
   1017     assert.equal(player.playbackRate, -1);
   1018     assert.equal(player._childPlayers.length, 1);
   1019     assert.equal(player._childPlayers[0]._player.playState, 'running');
   1020     assert.equal(player._childPlayers[0]._player.currentTime, 1000);
   1021     assert.equal(player._childPlayers[0]._player.playbackRate, -1);
   1022 
   1023   });
   1024 
   1025   test('fill none groups with fill none children do not fill', function() {
   1026     var anim = new Animation(
   1027         this.target,
   1028         [{marginLeft: '0px'}, {marginLeft: '100px'}],
   1029         {duration: 500, fill: 'none'});
   1030     var group = new AnimationGroup([anim], {fill: 'none'});
   1031     var player = document.timeline.play(group);
   1032 
   1033     tick(0);
   1034     assert.equal(getComputedStyle(this.target).marginLeft, '0px');
   1035     tick(250);
   1036     assert.equal(getComputedStyle(this.target).marginLeft, '50px');
   1037     tick(501);
   1038     assert.equal(getComputedStyle(this.target).marginLeft, '0px');
   1039     tick(502);
   1040   });
   1041 });
   1042