|
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 }; |