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 default context when none supplied', function(assert) {
423 assertTrue: function() {
424 assert.equal(this, obj, '`this` was bound to the callback');
428 obj.once('event', obj.assertTrue);
429 obj.trigger('event');
432 QUnit.test('bind a callback with a supplied context', function(assert) {
434 var TestClass = function() {
437 TestClass.prototype.assertTrue = function() {
438 assert.ok(true, '`this` was bound to the callback');
441 var obj = _.extend({}, Backbone.Events);
442 obj.on('event', function() { this.assertTrue(); }, new TestClass);
443 obj.trigger('event');
446 QUnit.test('nested trigger with unbind', function(assert) {
448 var obj = {counter: 0};
449 _.extend(obj, Backbone.Events);
450 var incr1 = function(){ obj.counter += 1; obj.off('event', incr1); obj.trigger('event'); };
451 var incr2 = function(){ obj.counter += 1; };
452 obj.on('event', incr1);
453 obj.on('event', incr2);
454 obj.trigger('event');
455 assert.equal(obj.counter, 3, 'counter should have been incremented three times');
458 QUnit.test('callback list is not altered during trigger', function(assert) {
460 var counter = 0, obj = _.extend({}, Backbone.Events);
461 var incr = function(){ counter++; };
462 var incrOn = function(){ obj.on('event all', incr); };
463 var incrOff = function(){ obj.off('event all', incr); };
465 obj.on('event all', incrOn).trigger('event');
466 assert.equal(counter, 0, 'on does not alter callback list');
468 obj.off().on('event', incrOff).on('event all', incr).trigger('event');
469 assert.equal(counter, 2, 'off does not alter callback list');
472 QUnit.test("#1282 - 'all' callback list is retrieved after each event.", function(assert) {
475 var obj = _.extend({}, Backbone.Events);
476 var incr = function(){ counter++; };
477 obj.on('x', function() {
478 obj.on('y', incr).on('all', incr);
481 assert.strictEqual(counter, 2);
484 QUnit.test('if no callback is provided, `on` is a noop', function(assert) {
486 _.extend({}, Backbone.Events).on('test').trigger('test');
489 QUnit.test('if callback is truthy but not a function, `on` should throw an error just like jQuery', function(assert) {
491 var view = _.extend({}, Backbone.Events).on('test', 'noop');
492 assert.raises(function() {
493 view.trigger('test');
497 QUnit.test('remove all events for a specific context', function(assert) {
499 var obj = _.extend({}, Backbone.Events);
500 obj.on('x y all', function() { assert.ok(true); });
501 obj.on('x y all', function() { assert.ok(false); }, obj);
502 obj.off(null, null, obj);
506 QUnit.test('remove all events for a specific callback', function(assert) {
508 var obj = _.extend({}, Backbone.Events);
509 var success = function() { assert.ok(true); };
510 var fail = function() { assert.ok(false); };
511 obj.on('x y all', success);
512 obj.on('x y all', fail);
517 QUnit.test('#1310 - off does not skip consecutive events', function(assert) {
519 var obj = _.extend({}, Backbone.Events);
520 obj.on('event', function() { assert.ok(false); }, obj);
521 obj.on('event', function() { assert.ok(false); }, obj);
522 obj.off(null, null, obj);
523 obj.trigger('event');
526 QUnit.test('once', function(assert) {
528 // Same as the previous test, but we use once rather than having to explicitly unbind
529 var obj = {counterA: 0, counterB: 0};
530 _.extend(obj, Backbone.Events);
531 var incrA = function(){ obj.counterA += 1; obj.trigger('event'); };
532 var incrB = function(){ obj.counterB += 1; };
533 obj.once('event', incrA);
534 obj.once('event', incrB);
535 obj.trigger('event');
536 assert.equal(obj.counterA, 1, 'counterA should have only been incremented once.');
537 assert.equal(obj.counterB, 1, 'counterB should have only been incremented once.');
540 QUnit.test('once variant one', function(assert) {
542 var f = function(){ assert.ok(true); };
544 var a = _.extend({}, Backbone.Events).once('event', f);
545 var b = _.extend({}, Backbone.Events).on('event', f);
553 QUnit.test('once variant two', function(assert) {
555 var f = function(){ assert.ok(true); };
556 var obj = _.extend({}, Backbone.Events);
565 QUnit.test('once with off', function(assert) {
567 var f = function(){ assert.ok(true); };
568 var obj = _.extend({}, Backbone.Events);
570 obj.once('event', f);
572 obj.trigger('event');
575 QUnit.test('once with event maps', function(assert) {
576 var obj = {counter: 0};
577 _.extend(obj, Backbone.Events);
579 var increment = function() {
590 assert.equal(obj.counter, 1);
593 assert.equal(obj.counter, 2);
596 assert.equal(obj.counter, 3);
598 obj.trigger('a b c');
599 assert.equal(obj.counter, 3);
602 QUnit.test('bind a callback with a supplied context using once with object notation', function(assert) {
604 var obj = {counter: 0};
606 _.extend(obj, Backbone.Events);
610 assert.strictEqual(this, context, 'defaults `context` to `callback` param');
612 }, context).trigger('a');
615 QUnit.test('once with off only by context', function(assert) {
618 var obj = _.extend({}, Backbone.Events);
619 obj.once('event', function(){ assert.ok(false); }, context);
620 obj.off(null, null, context);
621 obj.trigger('event');
624 QUnit.test('Backbone object inherits Events', function(assert) {
625 assert.ok(Backbone.on === Backbone.Events.on);
628 QUnit.test('once with asynchronous events', function(assert) {
629 var done = assert.async();
631 var func = _.debounce(function() { assert.ok(true); done(); }, 50);
632 var obj = _.extend({}, Backbone.Events).once('async', func);
634 obj.trigger('async');
635 obj.trigger('async');
638 QUnit.test('once with multiple events.', function(assert) {
640 var obj = _.extend({}, Backbone.Events);
641 obj.once('x y', function() { assert.ok(true); });
645 QUnit.test('Off during iteration with once.', function(assert) {
647 var obj = _.extend({}, Backbone.Events);
648 var f = function(){ this.off('event', f); };
650 obj.once('event', function(){});
651 obj.on('event', function(){ assert.ok(true); });
653 obj.trigger('event');
654 obj.trigger('event');
657 QUnit.test('`once` on `all` should work as expected', function(assert) {
659 Backbone.once('all', function() {
661 Backbone.trigger('all');
663 Backbone.trigger('all');
666 QUnit.test('once without a callback is a noop', function(assert) {
668 _.extend({}, Backbone.Events).once('event').trigger('event');
671 QUnit.test('listenToOnce without a callback is a noop', function(assert) {
673 var obj = _.extend({}, Backbone.Events);
674 obj.listenToOnce(obj, 'event').trigger('event');
677 QUnit.test('event functions are chainable', function(assert) {
678 var obj = _.extend({}, Backbone.Events);
679 var obj2 = _.extend({}, Backbone.Events);
680 var fn = function() {};
681 assert.equal(obj, obj.trigger('noeventssetyet'));
682 assert.equal(obj, obj.off('noeventssetyet'));
683 assert.equal(obj, obj.stopListening('noeventssetyet'));
684 assert.equal(obj, obj.on('a', fn));
685 assert.equal(obj, obj.once('c', fn));
686 assert.equal(obj, obj.trigger('a'));
687 assert.equal(obj, obj.listenTo(obj2, 'a', fn));
688 assert.equal(obj, obj.listenToOnce(obj2, 'b', fn));
689 assert.equal(obj, obj.off('a c'));
690 assert.equal(obj, obj.stopListening(obj2, 'a'));
691 assert.equal(obj, obj.stopListening());
694 QUnit.test('#3448 - listenToOnce with space-separated events', function(assert) {
696 var one = _.extend({}, Backbone.Events);
697 var two = _.extend({}, Backbone.Events);
699 one.listenToOnce(two, 'x y', function(n) { assert.ok(n === count++); });