toolkit/javascript/d3/test/core/transition-test-each.js
changeset 47 c0b4a8b5a012
equal deleted inserted replaced
46:efd9c589177a 47:c0b4a8b5a012
       
     1 require("../env");
       
     2 require("../../d3");
       
     3 
       
     4 var assert = require("assert");
       
     5 
       
     6 module.exports = {
       
     7   "start": {
       
     8     topic: function() {
       
     9       var cb = this.callback,
       
    10           div = d3.select("body").html("").selectAll().data(["foo", "bar"]).enter().append("div").attr("class", String),
       
    11           transition = div.transition().delay(150),
       
    12           then = Date.now(),
       
    13           n = 0,
       
    14           calls = [],
       
    15           context = [],
       
    16           data = [],
       
    17           index = [],
       
    18           count = [],
       
    19           delay = [];
       
    20 
       
    21       // A callback to verify that multiple callbacks are allowed.
       
    22       transition.each("start.other", function() {
       
    23         ++n;
       
    24       });
       
    25 
       
    26       // A callback which captures arguments and context.
       
    27       transition.each("start", function(d, i) {
       
    28         context.push(this);
       
    29         data.push(d);
       
    30         index.push(i);
       
    31         count.push(++n);
       
    32         delay.push(Date.now() - then);
       
    33         if (n >= 4) cb(null, {
       
    34           selection: div,
       
    35           delay: delay,
       
    36           context: context,
       
    37           data: data,
       
    38           index: index,
       
    39           count: count,
       
    40           id: transition.id
       
    41         });
       
    42       });
       
    43     },
       
    44 
       
    45     "invokes the listener after the specified delay": function(result) {
       
    46       assert.inDelta(result.delay, [150, 150], 20);
       
    47     },
       
    48     "invokes each listener exactly once, in order": function(result) {
       
    49       assert.deepEqual(result.count, [2, 4]);
       
    50     },
       
    51 
       
    52     // For the same node, listeners will be called back in order, according to
       
    53     // the implementation of d3.dispatch. However, the order of callbacks across
       
    54     // nodes is not guaranteed; currently, callbacks are in reverse order if
       
    55     // they share the same delay, because of the timer queue. I suppose it'd be
       
    56     // slightly better if the callbacks were invoked in node order (consistent
       
    57     // with selections), but since these callbacks happen asynchronously I don't
       
    58     // think the API needs to guarantee the order of callbacks.
       
    59 
       
    60     "uses the node as the context": function(result) {
       
    61       assert.domEqual(result.context[1], result.selection[0][0]);
       
    62       assert.domEqual(result.context[0], result.selection[0][1]);
       
    63     },
       
    64     "passes the data and index to the function": function(result) {
       
    65       assert.deepEqual(result.data, ["bar", "foo"], "expected data, got {actual}");
       
    66       assert.deepEqual(result.index, [1, 0], "expected index, got {actual}");
       
    67     },
       
    68 
       
    69     "sets an exclusive lock on transitioning nodes": function(result) {
       
    70       var id = result.id;
       
    71       assert.isTrue(id > 0);
       
    72       assert.equal(result.selection[0][0].__transition__.count, 1);
       
    73       assert.equal(result.selection[0][1].__transition__.count, 1);
       
    74       assert.equal(result.selection[0][0].__transition__.active, id);
       
    75       assert.equal(result.selection[0][1].__transition__.active, id);
       
    76     }
       
    77   },
       
    78 
       
    79   "end": {
       
    80     topic: function() {
       
    81       var cb = this.callback,
       
    82           div = d3.select("body").html("").selectAll().data(["foo", "bar"]).enter().append("div").attr("class", String),
       
    83           transition = div.transition().duration(150),
       
    84           then = Date.now(),
       
    85           n = 0,
       
    86           calls = [],
       
    87           context = [],
       
    88           data = [],
       
    89           index = [],
       
    90           count = [],
       
    91           delay = [];
       
    92 
       
    93       // A callback to verify that multiple callbacks are allowed.
       
    94       transition.each("end.other", function() {
       
    95         ++n;
       
    96       });
       
    97 
       
    98       // A callback which captures arguments and context.
       
    99       transition.each("end", function(d, i) {
       
   100         context.push(this);
       
   101         data.push(d);
       
   102         index.push(i);
       
   103         count.push(++n);
       
   104         delay.push(Date.now() - then);
       
   105         if (n >= 4) cb(null, {
       
   106           selection: div,
       
   107           delay: delay,
       
   108           context: context,
       
   109           data: data,
       
   110           index: index,
       
   111           count: count,
       
   112           id: transition.id
       
   113         });
       
   114       });
       
   115     },
       
   116 
       
   117     "invokes the listener after the specified delay": function(result) {
       
   118       assert.inDelta(result.delay, [150, 150], 20);
       
   119     },
       
   120     "invokes each listener exactly once, in order": function(result) {
       
   121       assert.deepEqual(result.count, [2, 4]);
       
   122     },
       
   123 
       
   124     // For the same node, listeners will be called back in order, according to
       
   125     // the implementation of d3.dispatch. However, the order of callbacks across
       
   126     // nodes is not guaranteed; currently, callbacks are in reverse order if
       
   127     // they share the same delay, because of the timer queue. I suppose it'd be
       
   128     // slightly better if the callbacks were invoked in node order (consistent
       
   129     // with selections), but since these callbacks happen asynchronously I don't
       
   130     // think the API needs to guarantee the order of callbacks.
       
   131 
       
   132     "uses the node as the context": function(result) {
       
   133       assert.domEqual(result.context[1], result.selection[0][0]);
       
   134       assert.domEqual(result.context[0], result.selection[0][1]);
       
   135     },
       
   136     "passes the data and index to the function": function(result) {
       
   137       assert.deepEqual(result.data, ["bar", "foo"], "expected data, got {actual}");
       
   138       assert.deepEqual(result.index, [1, 0], "expected index, got {actual}");
       
   139     },
       
   140 
       
   141     "deletes the transition lock after end": function(result) {
       
   142       assert.isFalse("__transition__" in result.selection[0][0]);
       
   143       assert.isFalse("__transition__" in result.selection[0][1]);
       
   144     },
       
   145 
       
   146     // I'd like to test d3.timer.flush here, but unfortunately there's a bug in
       
   147     // Vows where it really doesn't like to receive multiple callbacks from
       
   148     // different tests at the same time!
       
   149 
       
   150     "sequenced": {
       
   151       topic: function(result) {
       
   152         var cb = this.callback,
       
   153             node = result.selection[0][0],
       
   154             id = result.id;
       
   155         d3.select(node).transition().delay(150).each("start", function() {
       
   156           cb(null, {id: id, node: this});
       
   157         });
       
   158       },
       
   159       "inherits the same transition id": function(result) {
       
   160         assert.isTrue(result.id > 0);
       
   161         assert.equal(result.node.__transition__.count, 1);
       
   162         assert.equal(result.node.__transition__.active, result.id);
       
   163       }
       
   164     }
       
   165   }
       
   166 };