3 QUnit.module('Backbone.Events');
5 QUnit.test('on and trigger', function(assert) {
7 var obj = {counter: 0};
8 _.extend(obj, Backbone.Events);
9 obj.on('event', function() { obj.counter += 1; });
11 assert.equal(obj.counter, 1, 'counter should be incremented.');
16 assert.equal(obj.counter, 5, 'counter should be incremented five times.');
19 QUnit.test('binding and triggering multiple events', function(assert) {
21 var obj = {counter: 0};
22 _.extend(obj, Backbone.Events);
24 obj.on('a b c', function() { obj.counter += 1; });
27 assert.equal(obj.counter, 1);
30 assert.equal(obj.counter, 3);
33 assert.equal(obj.counter, 4);
37 assert.equal(obj.counter, 5);
40 QUnit.test('binding and triggering with event maps', function(assert) {
41 var obj = {counter: 0};
42 _.extend(obj, Backbone.Events);
44 var increment = function() {
55 assert.equal(obj.counter, 1);
58 assert.equal(obj.counter, 3);
61 assert.equal(obj.counter, 4);
68 assert.equal(obj.counter, 5);
71 QUnit.test('binding and triggering multiple event names with event maps', function(assert) {
72 var obj = {counter: 0};
73 _.extend(obj, Backbone.Events);
75 var increment = function() {
84 assert.equal(obj.counter, 1);
87 assert.equal(obj.counter, 3);
90 assert.equal(obj.counter, 4);
96 assert.equal(obj.counter, 5);
99 QUnit.test('binding and trigger with event maps context', function(assert) {
101 var obj = {counter: 0};
103 _.extend(obj, Backbone.Events);
107 assert.strictEqual(this, context, 'defaults `context` to `callback` param');
109 }, context).trigger('a');
113 assert.strictEqual(this, context, 'will not override explicit `context` param');
115 }, this, context).trigger('a');
118 QUnit.test('listenTo and stopListening', function(assert) {
120 var a = _.extend({}, Backbone.Events);
121 var b = _.extend({}, Backbone.Events);
122 a.listenTo(b, 'all', function(){ assert.ok(true); });
123 b.trigger('anything');
124 a.listenTo(b, 'all', function(){ assert.ok(false); });
126 b.trigger('anything');
129 QUnit.test('listenTo and stopListening with event maps', function(assert) {
131 var a = _.extend({}, Backbone.Events);
132 var b = _.extend({}, Backbone.Events);
133 var cb = function(){ assert.ok(true); };
134 a.listenTo(b, {event: cb});
136 a.listenTo(b, {event2: cb});
138 a.stopListening(b, {event2: cb});
139 b.trigger('event event2');
141 b.trigger('event event2');
144 QUnit.test('stopListening with omitted args', function(assert) {
146 var a = _.extend({}, Backbone.Events);
147 var b = _.extend({}, Backbone.Events);
148 var cb = function() { assert.ok(true); };
149 a.listenTo(b, 'event', cb);
151 a.listenTo(b, 'event2', cb);
152 a.stopListening(null, {event: cb});
153 b.trigger('event event2');
155 a.listenTo(b, 'event event2', cb);
156 a.stopListening(null, 'event');
161 QUnit.test('listenToOnce', function(assert) {
163 // Same as the previous test, but we use once rather than having to explicitly unbind
164 var obj = {counterA: 0, counterB: 0};
165 _.extend(obj, Backbone.Events);
166 var incrA = function(){ obj.counterA += 1; obj.trigger('event'); };
167 var incrB = function(){ obj.counterB += 1; };
168 obj.listenToOnce(obj, 'event', incrA);
169 obj.listenToOnce(obj, 'event', incrB);
170 obj.trigger('event');
171 assert.equal(obj.counterA, 1, 'counterA should have only been incremented once.');
172 assert.equal(obj.counterB, 1, 'counterB should have only been incremented once.');
175 QUnit.test('listenToOnce and stopListening', function(assert) {
177 var a = _.extend({}, Backbone.Events);
178 var b = _.extend({}, Backbone.Events);
179 a.listenToOnce(b, 'all', function() { assert.ok(true); });
180 b.trigger('anything');
181 b.trigger('anything');
182 a.listenToOnce(b, 'all', function() { assert.ok(false); });
184 b.trigger('anything');
187 QUnit.test('listenTo, listenToOnce and stopListening', function(assert) {
189 var a = _.extend({}, Backbone.Events);
190 var b = _.extend({}, Backbone.Events);
191 a.listenToOnce(b, 'all', function() { assert.ok(true); });
192 b.trigger('anything');
193 b.trigger('anything');
194 a.listenTo(b, 'all', function() { assert.ok(false); });
196 b.trigger('anything');
199 QUnit.test('listenTo and stopListening with event maps', function(assert) {
201 var a = _.extend({}, Backbone.Events);
202 var b = _.extend({}, Backbone.Events);
203 a.listenTo(b, {change: function(){ assert.ok(true); }});
205 a.listenTo(b, {change: function(){ assert.ok(false); }});
210 QUnit.test('listenTo yourself', function(assert) {
212 var e = _.extend({}, Backbone.Events);
213 e.listenTo(e, 'foo', function(){ assert.ok(true); });
217 QUnit.test('listenTo yourself cleans yourself up with stopListening', function(assert) {
219 var e = _.extend({}, Backbone.Events);
220 e.listenTo(e, 'foo', function(){ assert.ok(true); });
226 QUnit.test('stopListening cleans up references', function(assert) {
228 var a = _.extend({}, Backbone.Events);
229 var b = _.extend({}, Backbone.Events);
230 var fn = function() {};
232 a.listenTo(b, 'event', fn).stopListening();
233 assert.equal(_.size(a._listeningTo), 0);
234 assert.equal(_.size(b._events.event), 1);
235 assert.equal(_.size(b._listeners), 0);
236 a.listenTo(b, 'event', fn).stopListening(b);
237 assert.equal(_.size(a._listeningTo), 0);
238 assert.equal(_.size(b._events.event), 1);
239 assert.equal(_.size(b._listeners), 0);
240 a.listenTo(b, 'event', fn).stopListening(b, 'event');
241 assert.equal(_.size(a._listeningTo), 0);
242 assert.equal(_.size(b._events.event), 1);
243 assert.equal(_.size(b._listeners), 0);
244 a.listenTo(b, 'event', fn).stopListening(b, 'event', fn);
245 assert.equal(_.size(a._listeningTo), 0);
246 assert.equal(_.size(b._events.event), 1);
247 assert.equal(_.size(b._listeners), 0);
250 QUnit.test('stopListening cleans up references from listenToOnce', function(assert) {
252 var a = _.extend({}, Backbone.Events);
253 var b = _.extend({}, Backbone.Events);
254 var fn = function() {};
256 a.listenToOnce(b, 'event', fn).stopListening();
257 assert.equal(_.size(a._listeningTo), 0);
258 assert.equal(_.size(b._events.event), 1);
259 assert.equal(_.size(b._listeners), 0);
260 a.listenToOnce(b, 'event', fn).stopListening(b);
261 assert.equal(_.size(a._listeningTo), 0);
262 assert.equal(_.size(b._events.event), 1);
263 assert.equal(_.size(b._listeners), 0);
264 a.listenToOnce(b, 'event', fn).stopListening(b, 'event');
265 assert.equal(_.size(a._listeningTo), 0);
266 assert.equal(_.size(b._events.event), 1);
267 assert.equal(_.size(b._listeners), 0);
268 a.listenToOnce(b, 'event', fn).stopListening(b, 'event', fn);
269 assert.equal(_.size(a._listeningTo), 0);
270 assert.equal(_.size(b._events.event), 1);
271 assert.equal(_.size(b._listeners), 0);
274 QUnit.test('listenTo and off cleaning up references', function(assert) {
276 var a = _.extend({}, Backbone.Events);
277 var b = _.extend({}, Backbone.Events);
278 var fn = function() {};
279 a.listenTo(b, 'event', fn);
281 assert.equal(_.size(a._listeningTo), 0);
282 assert.equal(_.size(b._listeners), 0);
283 a.listenTo(b, 'event', fn);
285 assert.equal(_.size(a._listeningTo), 0);
286 assert.equal(_.size(b._listeners), 0);
287 a.listenTo(b, 'event', fn);
289 assert.equal(_.size(a._listeningTo), 0);
290 assert.equal(_.size(b._listeners), 0);
291 a.listenTo(b, 'event', fn);
292 b.off(null, null, a);
293 assert.equal(_.size(a._listeningTo), 0);
294 assert.equal(_.size(b._listeners), 0);
297 QUnit.test('listenTo and stopListening cleaning up references', function(assert) {
299 var a = _.extend({}, Backbone.Events);
300 var b = _.extend({}, Backbone.Events);
301 a.listenTo(b, 'all', function(){ assert.ok(true); });
302 b.trigger('anything');
303 a.listenTo(b, 'other', function(){ assert.ok(false); });
304 a.stopListening(b, 'other');
305 a.stopListening(b, 'all');
306 assert.equal(_.size(a._listeningTo), 0);
309 QUnit.test('listenToOnce without context cleans up references after the event has fired', function(assert) {
311 var a = _.extend({}, Backbone.Events);
312 var b = _.extend({}, Backbone.Events);
313 a.listenToOnce(b, 'all', function(){ assert.ok(true); });
314 b.trigger('anything');
315 assert.equal(_.size(a._listeningTo), 0);
318 QUnit.test('listenToOnce with event maps cleans up references', function(assert) {
320 var a = _.extend({}, Backbone.Events);
321 var b = _.extend({}, Backbone.Events);
323 one: function() { assert.ok(true); },
324 two: function() { assert.ok(false); }
327 assert.equal(_.size(a._listeningTo), 1);
330 QUnit.test('listenToOnce with event maps binds the correct `this`', function(assert) {
332 var a = _.extend({}, Backbone.Events);
333 var b = _.extend({}, Backbone.Events);
335 one: function() { assert.ok(this === a); },
336 two: function() { assert.ok(false); }
341 QUnit.test("listenTo with empty callback doesn't throw an error", function(assert) {
343 var e = _.extend({}, Backbone.Events);
344 e.listenTo(e, 'foo', null);
349 QUnit.test('trigger all for each event', function(assert) {
351 var a, b, obj = {counter: 0};
352 _.extend(obj, Backbone.Events);
353 obj.on('all', function(event) {
355 if (event === 'a') a = true;
356 if (event === 'b') b = true;
361 assert.equal(obj.counter, 2);
364 QUnit.test('on, then unbind all functions', function(assert) {
366 var obj = {counter: 0};
367 _.extend(obj, Backbone.Events);
368 var callback = function() { obj.counter += 1; };
369 obj.on('event', callback);
370 obj.trigger('event');
372 obj.trigger('event');
373 assert.equal(obj.counter, 1, 'counter should have only been incremented once.');
376 QUnit.test('bind two callbacks, unbind only one', function(assert) {
378 var obj = {counterA: 0, counterB: 0};
379 _.extend(obj, Backbone.Events);
380 var callback = function() { obj.counterA += 1; };
381 obj.on('event', callback);
382 obj.on('event', function() { obj.counterB += 1; });
383 obj.trigger('event');
384 obj.off('event', callback);
385 obj.trigger('event');
386 assert.equal(obj.counterA, 1, 'counterA should have only been incremented once.');
387 assert.equal(obj.counterB, 2, 'counterB should have been incremented twice.');
390 QUnit.test('unbind a callback in the midst of it firing', function(assert) {
392 var obj = {counter: 0};
393 _.extend(obj, Backbone.Events);
394 var callback = function() {
396 obj.off('event', callback);
398 obj.on('event', callback);
399 obj.trigger('event');
400 obj.trigger('event');
401 obj.trigger('event');
402 assert.equal(obj.counter, 1, 'the callback should have been unbound.');
405 QUnit.test('two binds that unbind themeselves', function(assert) {
407 var obj = {counterA: 0, counterB: 0};
408 _.extend(obj, Backbone.Events);
409 var incrA = function(){ obj.counterA += 1; obj.off('event', incrA); };
410 var incrB = function(){ obj.counterB += 1; obj.off('event', incrB); };
411 obj.on('event', incrA);
412 obj.on('event', incrB);
413 obj.trigger('event');
414 obj.trigger('event');
415 obj.trigger('event');
416 assert.equal(obj.counterA, 1, 'counterA should have only been incremented once.');
417 assert.equal(obj.counterB, 1, 'counterB should have only been incremented once.');
420 QUnit.test('bind a callback with a supplied context', function(assert) {
422 var TestClass = function() {
425 TestClass.prototype.assertTrue = function() {
426 assert.ok(true, '`this` was bound to the callback');
429 var obj = _.extend({}, Backbone.Events);
430 obj.on('event', function() { this.assertTrue(); }, new TestClass);
431 obj.trigger('event');
434 QUnit.test('nested trigger with unbind', function(assert) {
436 var obj = {counter: 0};
437 _.extend(obj, Backbone.Events);
438 var incr1 = function(){ obj.counter += 1; obj.off('event', incr1); obj.trigger('event'); };
439 var incr2 = function(){ obj.counter += 1; };
440 obj.on('event', incr1);
441 obj.on('event', incr2);
442 obj.trigger('event');
443 assert.equal(obj.counter, 3, 'counter should have been incremented three times');
446 QUnit.test('callback list is not altered during trigger', function(assert) {
448 var counter = 0, obj = _.extend({}, Backbone.Events);
449 var incr = function(){ counter++; };
450 var incrOn = function(){ obj.on('event all', incr); };
451 var incrOff = function(){ obj.off('event all', incr); };
453 obj.on('event all', incrOn).trigger('event');
454 assert.equal(counter, 0, 'on does not alter callback list');
456 obj.off().on('event', incrOff).on('event all', incr).trigger('event');
457 assert.equal(counter, 2, 'off does not alter callback list');
460 QUnit.test("#1282 - 'all' callback list is retrieved after each event.", function(assert) {
463 var obj = _.extend({}, Backbone.Events);
464 var incr = function(){ counter++; };
465 obj.on('x', function() {
466 obj.on('y', incr).on('all', incr);
469 assert.strictEqual(counter, 2);
472 QUnit.test('if no callback is provided, `on` is a noop', function(assert) {
474 _.extend({}, Backbone.Events).on('test').trigger('test');
477 QUnit.test('if callback is truthy but not a function, `on` should throw an error just like jQuery', function(assert) {
479 var view = _.extend({}, Backbone.Events).on('test', 'noop');
480 assert.raises(function() {
481 view.trigger('test');
485 QUnit.test('remove all events for a specific context', function(assert) {
487 var obj = _.extend({}, Backbone.Events);
488 obj.on('x y all', function() { assert.ok(true); });
489 obj.on('x y all', function() { assert.ok(false); }, obj);
490 obj.off(null, null, obj);
494 QUnit.test('remove all events for a specific callback', function(assert) {
496 var obj = _.extend({}, Backbone.Events);
497 var success = function() { assert.ok(true); };
498 var fail = function() { assert.ok(false); };
499 obj.on('x y all', success);
500 obj.on('x y all', fail);
505 QUnit.test('#1310 - off does not skip consecutive events', function(assert) {
507 var obj = _.extend({}, Backbone.Events);
508 obj.on('event', function() { assert.ok(false); }, obj);
509 obj.on('event', function() { assert.ok(false); }, obj);
510 obj.off(null, null, obj);
511 obj.trigger('event');
514 QUnit.test('once', function(assert) {
516 // Same as the previous test, but we use once rather than having to explicitly unbind
517 var obj = {counterA: 0, counterB: 0};
518 _.extend(obj, Backbone.Events);
519 var incrA = function(){ obj.counterA += 1; obj.trigger('event'); };
520 var incrB = function(){ obj.counterB += 1; };
521 obj.once('event', incrA);
522 obj.once('event', incrB);
523 obj.trigger('event');
524 assert.equal(obj.counterA, 1, 'counterA should have only been incremented once.');
525 assert.equal(obj.counterB, 1, 'counterB should have only been incremented once.');
528 QUnit.test('once variant one', function(assert) {
530 var f = function(){ assert.ok(true); };
532 var a = _.extend({}, Backbone.Events).once('event', f);
533 var b = _.extend({}, Backbone.Events).on('event', f);
541 QUnit.test('once variant two', function(assert) {
543 var f = function(){ assert.ok(true); };
544 var obj = _.extend({}, Backbone.Events);
553 QUnit.test('once with off', function(assert) {
555 var f = function(){ assert.ok(true); };
556 var obj = _.extend({}, Backbone.Events);
558 obj.once('event', f);
560 obj.trigger('event');
563 QUnit.test('once with event maps', function(assert) {
564 var obj = {counter: 0};
565 _.extend(obj, Backbone.Events);
567 var increment = function() {
578 assert.equal(obj.counter, 1);
581 assert.equal(obj.counter, 2);
584 assert.equal(obj.counter, 3);
586 obj.trigger('a b c');
587 assert.equal(obj.counter, 3);
590 QUnit.test('once with off only by context', function(assert) {
593 var obj = _.extend({}, Backbone.Events);
594 obj.once('event', function(){ assert.ok(false); }, context);
595 obj.off(null, null, context);
596 obj.trigger('event');
599 QUnit.test('Backbone object inherits Events', function(assert) {
600 assert.ok(Backbone.on === Backbone.Events.on);
603 QUnit.test('once with asynchronous events', function(assert) {
604 var done = assert.async();
606 var func = _.debounce(function() { assert.ok(true); done(); }, 50);
607 var obj = _.extend({}, Backbone.Events).once('async', func);
609 obj.trigger('async');
610 obj.trigger('async');
613 QUnit.test('once with multiple events.', function(assert) {
615 var obj = _.extend({}, Backbone.Events);
616 obj.once('x y', function() { assert.ok(true); });
620 QUnit.test('Off during iteration with once.', function(assert) {
622 var obj = _.extend({}, Backbone.Events);
623 var f = function(){ this.off('event', f); };
625 obj.once('event', function(){});
626 obj.on('event', function(){ assert.ok(true); });
628 obj.trigger('event');
629 obj.trigger('event');
632 QUnit.test('`once` on `all` should work as expected', function(assert) {
634 Backbone.once('all', function() {
636 Backbone.trigger('all');
638 Backbone.trigger('all');
641 QUnit.test('once without a callback is a noop', function(assert) {
643 _.extend({}, Backbone.Events).once('event').trigger('event');
646 QUnit.test('listenToOnce without a callback is a noop', function(assert) {
648 var obj = _.extend({}, Backbone.Events);
649 obj.listenToOnce(obj, 'event').trigger('event');
652 QUnit.test('event functions are chainable', function(assert) {
653 var obj = _.extend({}, Backbone.Events);
654 var obj2 = _.extend({}, Backbone.Events);
655 var fn = function() {};
656 assert.equal(obj, obj.trigger('noeventssetyet'));
657 assert.equal(obj, obj.off('noeventssetyet'));
658 assert.equal(obj, obj.stopListening('noeventssetyet'));
659 assert.equal(obj, obj.on('a', fn));
660 assert.equal(obj, obj.once('c', fn));
661 assert.equal(obj, obj.trigger('a'));
662 assert.equal(obj, obj.listenTo(obj2, 'a', fn));
663 assert.equal(obj, obj.listenToOnce(obj2, 'b', fn));
664 assert.equal(obj, obj.off('a c'));
665 assert.equal(obj, obj.stopListening(obj2, 'a'));
666 assert.equal(obj, obj.stopListening());
669 QUnit.test('#3448 - listenToOnce with space-separated events', function(assert) {
671 var one = _.extend({}, Backbone.Events);
672 var two = _.extend({}, Backbone.Events);
674 one.listenToOnce(two, 'x y', function(n) { assert.ok(n === count++); });