1(function(QUnit) {
2
3  QUnit.module('Backbone.Events');
4
5  QUnit.test('on and trigger', function(assert) {
6    assert.expect(2);
7    var obj = {counter: 0};
8    _.extend(obj, Backbone.Events);
9    obj.on('event', function() { obj.counter += 1; });
10    obj.trigger('event');
11    assert.equal(obj.counter, 1, 'counter should be incremented.');
12    obj.trigger('event');
13    obj.trigger('event');
14    obj.trigger('event');
15    obj.trigger('event');
16    assert.equal(obj.counter, 5, 'counter should be incremented five times.');
17  });
18
19  QUnit.test('binding and triggering multiple events', function(assert) {
20    assert.expect(4);
21    var obj = {counter: 0};
22    _.extend(obj, Backbone.Events);
23
24    obj.on('a b c', function() { obj.counter += 1; });
25
26    obj.trigger('a');
27    assert.equal(obj.counter, 1);
28
29    obj.trigger('a b');
30    assert.equal(obj.counter, 3);
31
32    obj.trigger('c');
33    assert.equal(obj.counter, 4);
34
35    obj.off('a c');
36    obj.trigger('a b c');
37    assert.equal(obj.counter, 5);
38  });
39
40  QUnit.test('binding and triggering with event maps', function(assert) {
41    var obj = {counter: 0};
42    _.extend(obj, Backbone.Events);
43
44    var increment = function() {
45      this.counter += 1;
46    };
47
48    obj.on({
49      a: increment,
50      b: increment,
51      c: increment
52    }, obj);
53
54    obj.trigger('a');
55    assert.equal(obj.counter, 1);
56
57    obj.trigger('a b');
58    assert.equal(obj.counter, 3);
59
60    obj.trigger('c');
61    assert.equal(obj.counter, 4);
62
63    obj.off({
64      a: increment,
65      c: increment
66    }, obj);
67    obj.trigger('a b c');
68    assert.equal(obj.counter, 5);
69  });
70
71  QUnit.test('binding and triggering multiple event names with event maps', function(assert) {
72    var obj = {counter: 0};
73    _.extend(obj, Backbone.Events);
74
75    var increment = function() {
76      this.counter += 1;
77    };
78
79    obj.on({
80      'a b c': increment
81    });
82
83    obj.trigger('a');
84    assert.equal(obj.counter, 1);
85
86    obj.trigger('a b');
87    assert.equal(obj.counter, 3);
88
89    obj.trigger('c');
90    assert.equal(obj.counter, 4);
91
92    obj.off({
93      'a c': increment
94    });
95    obj.trigger('a b c');
96    assert.equal(obj.counter, 5);
97  });
98
99  QUnit.test('binding and trigger with event maps context', function(assert) {
100    assert.expect(2);
101    var obj = {counter: 0};
102    var context = {};
103    _.extend(obj, Backbone.Events);
104
105    obj.on({
106      a: function() {
107        assert.strictEqual(this, context, 'defaults `context` to `callback` param');
108      }
109    }, context).trigger('a');
110
111    obj.off().on({
112      a: function() {
113        assert.strictEqual(this, context, 'will not override explicit `context` param');
114      }
115    }, this, context).trigger('a');
116  });
117
118  QUnit.test('listenTo and stopListening', function(assert) {
119    assert.expect(1);
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); });
125    a.stopListening();
126    b.trigger('anything');
127  });
128
129  QUnit.test('listenTo and stopListening with event maps', function(assert) {
130    assert.expect(4);
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});
135    b.trigger('event');
136    a.listenTo(b, {event2: cb});
137    b.on('event2', cb);
138    a.stopListening(b, {event2: cb});
139    b.trigger('event event2');
140    a.stopListening();
141    b.trigger('event event2');
142  });
143
144  QUnit.test('stopListening with omitted args', function(assert) {
145    assert.expect(2);
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);
150    b.on('event', cb);
151    a.listenTo(b, 'event2', cb);
152    a.stopListening(null, {event: cb});
153    b.trigger('event event2');
154    b.off();
155    a.listenTo(b, 'event event2', cb);
156    a.stopListening(null, 'event');
157    a.stopListening();
158    b.trigger('event2');
159  });
160
161  QUnit.test('listenToOnce', function(assert) {
162    assert.expect(2);
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.');
173  });
174
175  QUnit.test('listenToOnce and stopListening', function(assert) {
176    assert.expect(1);
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); });
183    a.stopListening();
184    b.trigger('anything');
185  });
186
187  QUnit.test('listenTo, listenToOnce and stopListening', function(assert) {
188    assert.expect(1);
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); });
195    a.stopListening();
196    b.trigger('anything');
197  });
198
199  QUnit.test('listenTo and stopListening with event maps', function(assert) {
200    assert.expect(1);
201    var a = _.extend({}, Backbone.Events);
202    var b = _.extend({}, Backbone.Events);
203    a.listenTo(b, {change: function(){ assert.ok(true); }});
204    b.trigger('change');
205    a.listenTo(b, {change: function(){ assert.ok(false); }});
206    a.stopListening();
207    b.trigger('change');
208  });
209
210  QUnit.test('listenTo yourself', function(assert) {
211    assert.expect(1);
212    var e = _.extend({}, Backbone.Events);
213    e.listenTo(e, 'foo', function(){ assert.ok(true); });
214    e.trigger('foo');
215  });
216
217  QUnit.test('listenTo yourself cleans yourself up with stopListening', function(assert) {
218    assert.expect(1);
219    var e = _.extend({}, Backbone.Events);
220    e.listenTo(e, 'foo', function(){ assert.ok(true); });
221    e.trigger('foo');
222    e.stopListening();
223    e.trigger('foo');
224  });
225
226  QUnit.test('stopListening cleans up references', function(assert) {
227    assert.expect(12);
228    var a = _.extend({}, Backbone.Events);
229    var b = _.extend({}, Backbone.Events);
230    var fn = function() {};
231    b.on('event', fn);
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);
248  });
249
250  QUnit.test('stopListening cleans up references from listenToOnce', function(assert) {
251    assert.expect(12);
252    var a = _.extend({}, Backbone.Events);
253    var b = _.extend({}, Backbone.Events);
254    var fn = function() {};
255    b.on('event', fn);
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);
272  });
273
274  QUnit.test('listenTo and off cleaning up references', function(assert) {
275    assert.expect(8);
276    var a = _.extend({}, Backbone.Events);
277    var b = _.extend({}, Backbone.Events);
278    var fn = function() {};
279    a.listenTo(b, 'event', fn);
280    b.off();
281    assert.equal(_.size(a._listeningTo), 0);
282    assert.equal(_.size(b._listeners), 0);
283    a.listenTo(b, 'event', fn);
284    b.off('event');
285    assert.equal(_.size(a._listeningTo), 0);
286    assert.equal(_.size(b._listeners), 0);
287    a.listenTo(b, 'event', fn);
288    b.off(null, 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);
295  });
296
297  QUnit.test('listenTo and stopListening cleaning up references', function(assert) {
298    assert.expect(2);
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);
307  });
308
309  QUnit.test('listenToOnce without context cleans up references after the event has fired', function(assert) {
310    assert.expect(2);
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);
316  });
317
318  QUnit.test('listenToOnce with event maps cleans up references', function(assert) {
319    assert.expect(2);
320    var a = _.extend({}, Backbone.Events);
321    var b = _.extend({}, Backbone.Events);
322    a.listenToOnce(b, {
323      one: function() { assert.ok(true); },
324      two: function() { assert.ok(false); }
325    });
326    b.trigger('one');
327    assert.equal(_.size(a._listeningTo), 1);
328  });
329
330  QUnit.test('listenToOnce with event maps binds the correct `this`', function(assert) {
331    assert.expect(1);
332    var a = _.extend({}, Backbone.Events);
333    var b = _.extend({}, Backbone.Events);
334    a.listenToOnce(b, {
335      one: function() { assert.ok(this === a); },
336      two: function() { assert.ok(false); }
337    });
338    b.trigger('one');
339  });
340
341  QUnit.test("listenTo with empty callback doesn't throw an error", function(assert) {
342    assert.expect(1);
343    var e = _.extend({}, Backbone.Events);
344    e.listenTo(e, 'foo', null);
345    e.trigger('foo');
346    assert.ok(true);
347  });
348
349  QUnit.test('trigger all for each event', function(assert) {
350    assert.expect(3);
351    var a, b, obj = {counter: 0};
352    _.extend(obj, Backbone.Events);
353    obj.on('all', function(event) {
354      obj.counter++;
355      if (event === 'a') a = true;
356      if (event === 'b') b = true;
357    })
358    .trigger('a b');
359    assert.ok(a);
360    assert.ok(b);
361    assert.equal(obj.counter, 2);
362  });
363
364  QUnit.test('on, then unbind all functions', function(assert) {
365    assert.expect(1);
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');
371    obj.off('event');
372    obj.trigger('event');
373    assert.equal(obj.counter, 1, 'counter should have only been incremented once.');
374  });
375
376  QUnit.test('bind two callbacks, unbind only one', function(assert) {
377    assert.expect(2);
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.');
388  });
389
390  QUnit.test('unbind a callback in the midst of it firing', function(assert) {
391    assert.expect(1);
392    var obj = {counter: 0};
393    _.extend(obj, Backbone.Events);
394    var callback = function() {
395      obj.counter += 1;
396      obj.off('event', callback);
397    };
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.');
403  });
404
405  QUnit.test('two binds that unbind themeselves', function(assert) {
406    assert.expect(2);
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.');
418  });
419
420  QUnit.test('bind a callback with a default context when none supplied', function(assert) {
421    assert.expect(1);
422    var obj = _.extend({
423      assertTrue: function() {
424        assert.equal(this, obj, '`this` was bound to the callback');
425      }
426    }, Backbone.Events);
427
428    obj.once('event', obj.assertTrue);
429    obj.trigger('event');
430  });
431
432  QUnit.test('bind a callback with a supplied context', function(assert) {
433    assert.expect(1);
434    var TestClass = function() {
435      return this;
436    };
437    TestClass.prototype.assertTrue = function() {
438      assert.ok(true, '`this` was bound to the callback');
439    };
440
441    var obj = _.extend({}, Backbone.Events);
442    obj.on('event', function() { this.assertTrue(); }, new TestClass);
443    obj.trigger('event');
444  });
445
446  QUnit.test('nested trigger with unbind', function(assert) {
447    assert.expect(1);
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');
456  });
457
458  QUnit.test('callback list is not altered during trigger', function(assert) {
459    assert.expect(2);
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); };
464
465    obj.on('event all', incrOn).trigger('event');
466    assert.equal(counter, 0, 'on does not alter callback list');
467
468    obj.off().on('event', incrOff).on('event all', incr).trigger('event');
469    assert.equal(counter, 2, 'off does not alter callback list');
470  });
471
472  QUnit.test("#1282 - 'all' callback list is retrieved after each event.", function(assert) {
473    assert.expect(1);
474    var counter = 0;
475    var obj = _.extend({}, Backbone.Events);
476    var incr = function(){ counter++; };
477    obj.on('x', function() {
478      obj.on('y', incr).on('all', incr);
479    })
480    .trigger('x y');
481    assert.strictEqual(counter, 2);
482  });
483
484  QUnit.test('if no callback is provided, `on` is a noop', function(assert) {
485    assert.expect(0);
486    _.extend({}, Backbone.Events).on('test').trigger('test');
487  });
488
489  QUnit.test('if callback is truthy but not a function, `on` should throw an error just like jQuery', function(assert) {
490    assert.expect(1);
491    var view = _.extend({}, Backbone.Events).on('test', 'noop');
492    assert.raises(function() {
493      view.trigger('test');
494    });
495  });
496
497  QUnit.test('remove all events for a specific context', function(assert) {
498    assert.expect(4);
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);
503    obj.trigger('x y');
504  });
505
506  QUnit.test('remove all events for a specific callback', function(assert) {
507    assert.expect(4);
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);
513    obj.off(null, fail);
514    obj.trigger('x y');
515  });
516
517  QUnit.test('#1310 - off does not skip consecutive events', function(assert) {
518    assert.expect(0);
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');
524  });
525
526  QUnit.test('once', function(assert) {
527    assert.expect(2);
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.');
538  });
539
540  QUnit.test('once variant one', function(assert) {
541    assert.expect(3);
542    var f = function(){ assert.ok(true); };
543
544    var a = _.extend({}, Backbone.Events).once('event', f);
545    var b = _.extend({}, Backbone.Events).on('event', f);
546
547    a.trigger('event');
548
549    b.trigger('event');
550    b.trigger('event');
551  });
552
553  QUnit.test('once variant two', function(assert) {
554    assert.expect(3);
555    var f = function(){ assert.ok(true); };
556    var obj = _.extend({}, Backbone.Events);
557
558    obj
559      .once('event', f)
560      .on('event', f)
561      .trigger('event')
562      .trigger('event');
563  });
564
565  QUnit.test('once with off', function(assert) {
566    assert.expect(0);
567    var f = function(){ assert.ok(true); };
568    var obj = _.extend({}, Backbone.Events);
569
570    obj.once('event', f);
571    obj.off('event', f);
572    obj.trigger('event');
573  });
574
575  QUnit.test('once with event maps', function(assert) {
576    var obj = {counter: 0};
577    _.extend(obj, Backbone.Events);
578
579    var increment = function() {
580      this.counter += 1;
581    };
582
583    obj.once({
584      a: increment,
585      b: increment,
586      c: increment
587    }, obj);
588
589    obj.trigger('a');
590    assert.equal(obj.counter, 1);
591
592    obj.trigger('a b');
593    assert.equal(obj.counter, 2);
594
595    obj.trigger('c');
596    assert.equal(obj.counter, 3);
597
598    obj.trigger('a b c');
599    assert.equal(obj.counter, 3);
600  });
601
602  QUnit.test('bind a callback with a supplied context using once with object notation', function(assert) {
603    assert.expect(1);
604    var obj = {counter: 0};
605    var context = {};
606    _.extend(obj, Backbone.Events);
607
608    obj.once({
609      a: function() {
610        assert.strictEqual(this, context, 'defaults `context` to `callback` param');
611      }
612    }, context).trigger('a');
613  });
614
615  QUnit.test('once with off only by context', function(assert) {
616    assert.expect(0);
617    var context = {};
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');
622  });
623
624  QUnit.test('Backbone object inherits Events', function(assert) {
625    assert.ok(Backbone.on === Backbone.Events.on);
626  });
627
628  QUnit.test('once with asynchronous events', function(assert) {
629    var done = assert.async();
630    assert.expect(1);
631    var func = _.debounce(function() { assert.ok(true); done(); }, 50);
632    var obj = _.extend({}, Backbone.Events).once('async', func);
633
634    obj.trigger('async');
635    obj.trigger('async');
636  });
637
638  QUnit.test('once with multiple events.', function(assert) {
639    assert.expect(2);
640    var obj = _.extend({}, Backbone.Events);
641    obj.once('x y', function() { assert.ok(true); });
642    obj.trigger('x y');
643  });
644
645  QUnit.test('Off during iteration with once.', function(assert) {
646    assert.expect(2);
647    var obj = _.extend({}, Backbone.Events);
648    var f = function(){ this.off('event', f); };
649    obj.on('event', f);
650    obj.once('event', function(){});
651    obj.on('event', function(){ assert.ok(true); });
652
653    obj.trigger('event');
654    obj.trigger('event');
655  });
656
657  QUnit.test('`once` on `all` should work as expected', function(assert) {
658    assert.expect(1);
659    Backbone.once('all', function() {
660      assert.ok(true);
661      Backbone.trigger('all');
662    });
663    Backbone.trigger('all');
664  });
665
666  QUnit.test('once without a callback is a noop', function(assert) {
667    assert.expect(0);
668    _.extend({}, Backbone.Events).once('event').trigger('event');
669  });
670
671  QUnit.test('listenToOnce without a callback is a noop', function(assert) {
672    assert.expect(0);
673    var obj = _.extend({}, Backbone.Events);
674    obj.listenToOnce(obj, 'event').trigger('event');
675  });
676
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());
692  });
693
694  QUnit.test('#3448 - listenToOnce with space-separated events', function(assert) {
695    assert.expect(2);
696    var one = _.extend({}, Backbone.Events);
697    var two = _.extend({}, Backbone.Events);
698    var count = 1;
699    one.listenToOnce(two, 'x y', function(n) { assert.ok(n === count++); });
700    two.trigger('x', 1);
701    two.trigger('x', 1);
702    two.trigger('y', 2);
703    two.trigger('y', 2);
704  });
705
706})(QUnit);
707