96d2fb8f31605d24b76f0a6a4f4efa774db631fd
[aai/esr-gui.git] /
1 var assert = require('assert');
2 var Kareem = require('../');
3
4 /* Much like [hooks](https://npmjs.org/package/hooks), kareem lets you define
5  * pre and post hooks: pre hooks are called before a given function executes.
6  * Unlike hooks, kareem stores hooks and other internal state in a separate
7  * object, rather than relying on inheritance. Furthermore, kareem exposes
8  * an `execPre()` function that allows you to execute your pre hooks when
9  * appropriate, giving you more fine-grained control over your function hooks.
10  */
11 describe('pre hooks', function() {
12   var hooks;
13
14   beforeEach(function() {
15     hooks = new Kareem();
16   });
17
18   it('runs without any hooks specified', function(done) {
19     hooks.execPre('cook', null, function() {
20       done();
21     });
22   });
23
24   /* pre hook functions take one parameter, a "done" function that you execute
25    * when your pre hook is finished.
26    */
27   it('runs basic serial pre hooks', function(done) {
28     var count = 0;
29
30     hooks.pre('cook', function(done) {
31       ++count;
32       done();
33     });
34
35     hooks.execPre('cook', null, function() {
36       assert.equal(1, count);
37       done();
38     });
39   });
40
41   it('can run multipe pre hooks', function(done) {
42     var count1 = 0;
43     var count2 = 0;
44
45     hooks.pre('cook', function(done) {
46       ++count1;
47       done();
48     });
49
50     hooks.pre('cook', function(done) {
51       ++count2;
52       done();
53     });
54
55     hooks.execPre('cook', null, function() {
56       assert.equal(1, count1);
57       assert.equal(1, count2);
58       done();
59     });
60   });
61
62   /* If your pre hook function takes no parameters, its assumed to be
63    * fully synchronous.
64    */
65   it('can run fully synchronous pre hooks', function(done) {
66     var count1 = 0;
67     var count2 = 0;
68
69     hooks.pre('cook', function() {
70       ++count1;
71     });
72
73     hooks.pre('cook', function() {
74       ++count2;
75     });
76
77     hooks.execPre('cook', null, function(error) {
78       assert.equal(null, error);
79       assert.equal(1, count1);
80       assert.equal(1, count2);
81       done();
82     });
83   });
84
85   /* Pre save hook functions are bound to the second parameter to `execPre()`
86    */
87   it('properly attaches context to pre hooks', function(done) {
88     hooks.pre('cook', function(done) {
89       this.bacon = 3;
90       done();
91     });
92
93     hooks.pre('cook', function(done) {
94       this.eggs = 4;
95       done();
96     });
97
98     var obj = { bacon: 0, eggs: 0 };
99
100     // In the pre hooks, `this` will refer to `obj`
101     hooks.execPre('cook', obj, function(error) {
102       assert.equal(null, error);
103       assert.equal(3, obj.bacon);
104       assert.equal(4, obj.eggs);
105       done();
106     });
107   });
108
109   /* Like the hooks module, you can declare "async" pre hooks - these take two
110    * parameters, the functions `next()` and `done()`. `next()` passes control to
111    * the next pre hook, but the underlying function won't be called until all
112    * async pre hooks have called `done()`.
113    */
114   it('can execute parallel (async) pre hooks', function(done) {
115     hooks.pre('cook', true, function(next, done) {
116       this.bacon = 3;
117       next();
118       setTimeout(function() {
119         done();
120       }, 5);
121     });
122
123     hooks.pre('cook', true, function(next, done) {
124       next();
125       var _this = this;
126       setTimeout(function() {
127         _this.eggs = 4;
128         done();
129       }, 10);
130     });
131
132     hooks.pre('cook', function(next) {
133       this.waffles = false;
134       next();
135     });
136
137     var obj = { bacon: 0, eggs: 0 };
138
139     hooks.execPre('cook', obj, function() {
140       assert.equal(3, obj.bacon);
141       assert.equal(4, obj.eggs);
142       assert.equal(false, obj.waffles);
143       done();
144     });
145   });
146 });
147
148 describe('post hooks', function() {
149   var hooks;
150
151   beforeEach(function() {
152     hooks = new Kareem();
153   });
154
155   it('runs without any hooks specified', function(done) {
156     hooks.execPost('cook', null, [1], function(error, eggs) {
157       assert.ifError(error);
158       assert.equal(1, eggs);
159       done();
160     });
161   });
162
163   it('executes with parameters passed in', function(done) {
164     hooks.post('cook', function(eggs, bacon, callback) {
165       assert.equal(1, eggs);
166       assert.equal(2, bacon);
167       callback();
168     });
169
170     hooks.execPost('cook', null, [1, 2], function(error, eggs, bacon) {
171       assert.ifError(error);
172       assert.equal(1, eggs);
173       assert.equal(2, bacon);
174       done();
175     });
176   });
177
178   it('can use synchronous post hooks', function(done) {
179     var execed = {};
180
181     hooks.post('cook', function(eggs, bacon) {
182       execed.first = true;
183       assert.equal(1, eggs);
184       assert.equal(2, bacon);
185     });
186
187     hooks.post('cook', function(eggs, bacon, callback) {
188       execed.second = true;
189       assert.equal(1, eggs);
190       assert.equal(2, bacon);
191       callback();
192     });
193
194     hooks.execPost('cook', null, [1, 2], function(error, eggs, bacon) {
195       assert.ifError(error);
196       assert.equal(2, Object.keys(execed).length);
197       assert.ok(execed.first);
198       assert.ok(execed.second);
199       assert.equal(1, eggs);
200       assert.equal(2, bacon);
201       done();
202     });
203   });
204 });
205
206 describe('wrap()', function() {
207   var hooks;
208
209   beforeEach(function() {
210     hooks = new Kareem();
211   });
212
213   it('wraps pre and post calls into one call', function(done) {
214     hooks.pre('cook', true, function(next, done) {
215       this.bacon = 3;
216       next();
217       setTimeout(function() {
218         done();
219       }, 5);
220     });
221
222     hooks.pre('cook', true, function(next, done) {
223       next();
224       var _this = this;
225       setTimeout(function() {
226         _this.eggs = 4;
227         done();
228       }, 10);
229     });
230
231     hooks.pre('cook', function(next) {
232       this.waffles = false;
233       next();
234     });
235
236     hooks.post('cook', function(obj) {
237       obj.tofu = 'no';
238     });
239
240     var obj = { bacon: 0, eggs: 0 };
241
242     var args = [obj];
243     args.push(function(error, result) {
244       assert.ifError(error);
245       assert.equal(null, error);
246       assert.equal(3, obj.bacon);
247       assert.equal(4, obj.eggs);
248       assert.equal(false, obj.waffles);
249       assert.equal('no', obj.tofu);
250
251       assert.equal(obj, result);
252       done();
253     });
254
255     hooks.wrap(
256       'cook',
257       function(o, callback) {
258         assert.equal(3, obj.bacon);
259         assert.equal(4, obj.eggs);
260         assert.equal(false, obj.waffles);
261         assert.equal(undefined, obj.tofu);
262         callback(null, o);
263       },
264       obj,
265       args);
266   });
267 });
268
269 describe('createWrapper()', function() {
270   var hooks;
271
272   beforeEach(function() {
273     hooks = new Kareem();
274   });
275
276   it('wraps wrap() into a callable function', function(done) {
277     hooks.pre('cook', true, function(next, done) {
278       this.bacon = 3;
279       next();
280       setTimeout(function() {
281         done();
282       }, 5);
283     });
284
285     hooks.pre('cook', true, function(next, done) {
286       next();
287       var _this = this;
288       setTimeout(function() {
289         _this.eggs = 4;
290         done();
291       }, 10);
292     });
293
294     hooks.pre('cook', function(next) {
295       this.waffles = false;
296       next();
297     });
298
299     hooks.post('cook', function(obj) {
300       obj.tofu = 'no';
301     });
302
303     var obj = { bacon: 0, eggs: 0 };
304
305     var cook = hooks.createWrapper(
306       'cook',
307       function(o, callback) {
308         assert.equal(3, obj.bacon);
309         assert.equal(4, obj.eggs);
310         assert.equal(false, obj.waffles);
311         assert.equal(undefined, obj.tofu);
312         callback(null, o);
313       },
314       obj);
315
316     cook(obj, function(error, result) {
317       assert.ifError(error);
318       assert.equal(3, obj.bacon);
319       assert.equal(4, obj.eggs);
320       assert.equal(false, obj.waffles);
321       assert.equal('no', obj.tofu);
322
323       assert.equal(obj, result);
324       done();
325     });
326   });
327 });
328
329 describe('clone()', function() {
330   it('clones a Kareem object', function() {
331     var k1 = new Kareem();
332     k1.pre('cook', function() {});
333     k1.post('cook', function() {});
334
335     var k2 = k1.clone();
336     assert.deepEqual(['cook'], Object.keys(k2._pres));
337     assert.deepEqual(['cook'], Object.keys(k2._posts));
338   });
339 });