nexus site path corrected
[portal.git] / ecomp-portal-FE / client / bower_components / lodash / vendor / backbone / test / collection.js
1 (function() {
2
3   var a, b, c, d, e, col, otherCol;
4
5   QUnit.module('Backbone.Collection', {
6
7     beforeEach: function(assert) {
8       a         = new Backbone.Model({id: 3, label: 'a'});
9       b         = new Backbone.Model({id: 2, label: 'b'});
10       c         = new Backbone.Model({id: 1, label: 'c'});
11       d         = new Backbone.Model({id: 0, label: 'd'});
12       e         = null;
13       col       = new Backbone.Collection([a, b, c, d]);
14       otherCol  = new Backbone.Collection();
15     }
16
17   });
18
19   QUnit.test('new and sort', function(assert) {
20     assert.expect(6);
21     var counter = 0;
22     col.on('sort', function(){ counter++; });
23     assert.deepEqual(col.pluck('label'), ['a', 'b', 'c', 'd']);
24     col.comparator = function(m1, m2) {
25       return m1.id > m2.id ? -1 : 1;
26     };
27     col.sort();
28     assert.equal(counter, 1);
29     assert.deepEqual(col.pluck('label'), ['a', 'b', 'c', 'd']);
30     col.comparator = function(model) { return model.id; };
31     col.sort();
32     assert.equal(counter, 2);
33     assert.deepEqual(col.pluck('label'), ['d', 'c', 'b', 'a']);
34     assert.equal(col.length, 4);
35   });
36
37   QUnit.test('String comparator.', function(assert) {
38     assert.expect(1);
39     var collection = new Backbone.Collection([
40       {id: 3},
41       {id: 1},
42       {id: 2}
43     ], {comparator: 'id'});
44     assert.deepEqual(collection.pluck('id'), [1, 2, 3]);
45   });
46
47   QUnit.test('new and parse', function(assert) {
48     assert.expect(3);
49     var Collection = Backbone.Collection.extend({
50       parse: function(data) {
51         return _.filter(data, function(datum) {
52           return datum.a % 2 === 0;
53         });
54       }
55     });
56     var models = [{a: 1}, {a: 2}, {a: 3}, {a: 4}];
57     var collection = new Collection(models, {parse: true});
58     assert.strictEqual(collection.length, 2);
59     assert.strictEqual(collection.first().get('a'), 2);
60     assert.strictEqual(collection.last().get('a'), 4);
61   });
62
63   QUnit.test('clone preserves model and comparator', function(assert) {
64     assert.expect(3);
65     var Model = Backbone.Model.extend();
66     var comparator = function(model){ return model.id; };
67
68     var collection = new Backbone.Collection([{id: 1}], {
69       model: Model,
70       comparator: comparator
71     }).clone();
72     collection.add({id: 2});
73     assert.ok(collection.at(0) instanceof Model);
74     assert.ok(collection.at(1) instanceof Model);
75     assert.strictEqual(collection.comparator, comparator);
76   });
77
78   QUnit.test('get', function(assert) {
79     assert.expect(6);
80     assert.equal(col.get(0), d);
81     assert.equal(col.get(d.clone()), d);
82     assert.equal(col.get(2), b);
83     assert.equal(col.get({id: 1}), c);
84     assert.equal(col.get(c.clone()), c);
85     assert.equal(col.get(col.first().cid), col.first());
86   });
87
88   QUnit.test('get with non-default ids', function(assert) {
89     assert.expect(5);
90     var MongoModel = Backbone.Model.extend({idAttribute: '_id'});
91     var model = new MongoModel({_id: 100});
92     var collection = new Backbone.Collection([model], {model: MongoModel});
93     assert.equal(collection.get(100), model);
94     assert.equal(collection.get(model.cid), model);
95     assert.equal(collection.get(model), model);
96     assert.equal(collection.get(101), void 0);
97
98     var collection2 = new Backbone.Collection();
99     collection2.model = MongoModel;
100     collection2.add(model.attributes);
101     assert.equal(collection2.get(model.clone()), collection2.first());
102   });
103
104   QUnit.test('has', function(assert) {
105     assert.expect(15);
106     assert.ok(col.has(a));
107     assert.ok(col.has(b));
108     assert.ok(col.has(c));
109     assert.ok(col.has(d));
110     assert.ok(col.has(a.id));
111     assert.ok(col.has(b.id));
112     assert.ok(col.has(c.id));
113     assert.ok(col.has(d.id));
114     assert.ok(col.has(a.cid));
115     assert.ok(col.has(b.cid));
116     assert.ok(col.has(c.cid));
117     assert.ok(col.has(d.cid));
118     var outsider = new Backbone.Model({id: 4});
119     assert.notOk(col.has(outsider));
120     assert.notOk(col.has(outsider.id));
121     assert.notOk(col.has(outsider.cid));
122   });
123
124   QUnit.test('update index when id changes', function(assert) {
125     assert.expect(4);
126     var collection = new Backbone.Collection();
127     collection.add([
128       {id: 0, name: 'one'},
129       {id: 1, name: 'two'}
130     ]);
131     var one = collection.get(0);
132     assert.equal(one.get('name'), 'one');
133     collection.on('change:name', function(model) { assert.ok(this.get(model)); });
134     one.set({name: 'dalmatians', id: 101});
135     assert.equal(collection.get(0), null);
136     assert.equal(collection.get(101).get('name'), 'dalmatians');
137   });
138
139   QUnit.test('at', function(assert) {
140     assert.expect(2);
141     assert.equal(col.at(2), c);
142     assert.equal(col.at(-2), c);
143   });
144
145   QUnit.test('pluck', function(assert) {
146     assert.expect(1);
147     assert.equal(col.pluck('label').join(' '), 'a b c d');
148   });
149
150   QUnit.test('add', function(assert) {
151     assert.expect(14);
152     var added, opts, secondAdded;
153     added = opts = secondAdded = null;
154     e = new Backbone.Model({id: 10, label: 'e'});
155     otherCol.add(e);
156     otherCol.on('add', function() {
157       secondAdded = true;
158     });
159     col.on('add', function(model, collection, options){
160       added = model.get('label');
161       opts = options;
162     });
163     col.add(e, {amazing: true});
164     assert.equal(added, 'e');
165     assert.equal(col.length, 5);
166     assert.equal(col.last(), e);
167     assert.equal(otherCol.length, 1);
168     assert.equal(secondAdded, null);
169     assert.ok(opts.amazing);
170
171     var f = new Backbone.Model({id: 20, label: 'f'});
172     var g = new Backbone.Model({id: 21, label: 'g'});
173     var h = new Backbone.Model({id: 22, label: 'h'});
174     var atCol = new Backbone.Collection([f, g, h]);
175     assert.equal(atCol.length, 3);
176     atCol.add(e, {at: 1});
177     assert.equal(atCol.length, 4);
178     assert.equal(atCol.at(1), e);
179     assert.equal(atCol.last(), h);
180
181     var coll = new Backbone.Collection(new Array(2));
182     var addCount = 0;
183     coll.on('add', function(){
184       addCount += 1;
185     });
186     coll.add([undefined, f, g]);
187     assert.equal(coll.length, 5);
188     assert.equal(addCount, 3);
189     coll.add(new Array(4));
190     assert.equal(coll.length, 9);
191     assert.equal(addCount, 7);
192   });
193
194   QUnit.test('add multiple models', function(assert) {
195     assert.expect(6);
196     var collection = new Backbone.Collection([{at: 0}, {at: 1}, {at: 9}]);
197     collection.add([{at: 2}, {at: 3}, {at: 4}, {at: 5}, {at: 6}, {at: 7}, {at: 8}], {at: 2});
198     for (var i = 0; i <= 5; i++) {
199       assert.equal(collection.at(i).get('at'), i);
200     }
201   });
202
203   QUnit.test('add; at should have preference over comparator', function(assert) {
204     assert.expect(1);
205     var Col = Backbone.Collection.extend({
206       comparator: function(m1, m2) {
207         return m1.id > m2.id ? -1 : 1;
208       }
209     });
210
211     var collection = new Col([{id: 2}, {id: 3}]);
212     collection.add(new Backbone.Model({id: 1}), {at: 1});
213
214     assert.equal(collection.pluck('id').join(' '), '3 1 2');
215   });
216
217   QUnit.test('add; at should add to the end if the index is out of bounds', function(assert) {
218     assert.expect(1);
219     var collection = new Backbone.Collection([{id: 2}, {id: 3}]);
220     collection.add(new Backbone.Model({id: 1}), {at: 5});
221
222     assert.equal(collection.pluck('id').join(' '), '2 3 1');
223   });
224
225   QUnit.test("can't add model to collection twice", function(assert) {
226     var collection = new Backbone.Collection([{id: 1}, {id: 2}, {id: 1}, {id: 2}, {id: 3}]);
227     assert.equal(collection.pluck('id').join(' '), '1 2 3');
228   });
229
230   QUnit.test("can't add different model with same id to collection twice", function(assert) {
231     assert.expect(1);
232     var collection = new Backbone.Collection;
233     collection.unshift({id: 101});
234     collection.add({id: 101});
235     assert.equal(collection.length, 1);
236   });
237
238   QUnit.test('merge in duplicate models with {merge: true}', function(assert) {
239     assert.expect(3);
240     var collection = new Backbone.Collection;
241     collection.add([{id: 1, name: 'Moe'}, {id: 2, name: 'Curly'}, {id: 3, name: 'Larry'}]);
242     collection.add({id: 1, name: 'Moses'});
243     assert.equal(collection.first().get('name'), 'Moe');
244     collection.add({id: 1, name: 'Moses'}, {merge: true});
245     assert.equal(collection.first().get('name'), 'Moses');
246     collection.add({id: 1, name: 'Tim'}, {merge: true, silent: true});
247     assert.equal(collection.first().get('name'), 'Tim');
248   });
249
250   QUnit.test('add model to multiple collections', function(assert) {
251     assert.expect(10);
252     var counter = 0;
253     var m = new Backbone.Model({id: 10, label: 'm'});
254     m.on('add', function(model, collection) {
255       counter++;
256       assert.equal(m, model);
257       if (counter > 1) {
258         assert.equal(collection, col2);
259       } else {
260         assert.equal(collection, col1);
261       }
262     });
263     var col1 = new Backbone.Collection([]);
264     col1.on('add', function(model, collection) {
265       assert.equal(m, model);
266       assert.equal(col1, collection);
267     });
268     var col2 = new Backbone.Collection([]);
269     col2.on('add', function(model, collection) {
270       assert.equal(m, model);
271       assert.equal(col2, collection);
272     });
273     col1.add(m);
274     assert.equal(m.collection, col1);
275     col2.add(m);
276     assert.equal(m.collection, col1);
277   });
278
279   QUnit.test('add model with parse', function(assert) {
280     assert.expect(1);
281     var Model = Backbone.Model.extend({
282       parse: function(obj) {
283         obj.value += 1;
284         return obj;
285       }
286     });
287
288     var Col = Backbone.Collection.extend({model: Model});
289     var collection = new Col;
290     collection.add({value: 1}, {parse: true});
291     assert.equal(collection.at(0).get('value'), 2);
292   });
293
294   QUnit.test('add with parse and merge', function(assert) {
295     var collection = new Backbone.Collection();
296     collection.parse = function(attrs) {
297       return _.map(attrs, function(model) {
298         if (model.model) return model.model;
299         return model;
300       });
301     };
302     collection.add({id: 1});
303     collection.add({model: {id: 1, name: 'Alf'}}, {parse: true, merge: true});
304     assert.equal(collection.first().get('name'), 'Alf');
305   });
306
307   QUnit.test('add model to collection with sort()-style comparator', function(assert) {
308     assert.expect(3);
309     var collection = new Backbone.Collection;
310     collection.comparator = function(m1, m2) {
311       return m1.get('name') < m2.get('name') ? -1 : 1;
312     };
313     var tom = new Backbone.Model({name: 'Tom'});
314     var rob = new Backbone.Model({name: 'Rob'});
315     var tim = new Backbone.Model({name: 'Tim'});
316     collection.add(tom);
317     collection.add(rob);
318     collection.add(tim);
319     assert.equal(collection.indexOf(rob), 0);
320     assert.equal(collection.indexOf(tim), 1);
321     assert.equal(collection.indexOf(tom), 2);
322   });
323
324   QUnit.test('comparator that depends on `this`', function(assert) {
325     assert.expect(2);
326     var collection = new Backbone.Collection;
327     collection.negative = function(num) {
328       return -num;
329     };
330     collection.comparator = function(model) {
331       return this.negative(model.id);
332     };
333     collection.add([{id: 1}, {id: 2}, {id: 3}]);
334     assert.deepEqual(collection.pluck('id'), [3, 2, 1]);
335     collection.comparator = function(m1, m2) {
336       return this.negative(m2.id) - this.negative(m1.id);
337     };
338     collection.sort();
339     assert.deepEqual(collection.pluck('id'), [1, 2, 3]);
340   });
341
342   QUnit.test('remove', function(assert) {
343     assert.expect(12);
344     var removed = null;
345     var result = null;
346     col.on('remove', function(model, collection, options) {
347       removed = model.get('label');
348       assert.equal(options.index, 3);
349       assert.equal(collection.get(model), undefined, '#3693: model cannot be fetched from collection');
350     });
351     result = col.remove(d);
352     assert.equal(removed, 'd');
353     assert.strictEqual(result, d);
354     //if we try to remove d again, it's not going to actually get removed
355     result = col.remove(d);
356     assert.strictEqual(result, undefined);
357     assert.equal(col.length, 3);
358     assert.equal(col.first(), a);
359     col.off();
360     result = col.remove([c, d]);
361     assert.equal(result.length, 1, 'only returns removed models');
362     assert.equal(result[0], c, 'only returns removed models');
363     result = col.remove([c, b]);
364     assert.equal(result.length, 1, 'only returns removed models');
365     assert.equal(result[0], b, 'only returns removed models');
366     result = col.remove([]);
367     assert.deepEqual(result, [], 'returns empty array when nothing removed');
368   });
369
370   QUnit.test('add and remove return values', function(assert) {
371     assert.expect(13);
372     var Even = Backbone.Model.extend({
373       validate: function(attrs) {
374         if (attrs.id % 2 !== 0) return 'odd';
375       }
376     });
377     var collection = new Backbone.Collection;
378     collection.model = Even;
379
380     var list = collection.add([{id: 2}, {id: 4}], {validate: true});
381     assert.equal(list.length, 2);
382     assert.ok(list[0] instanceof Backbone.Model);
383     assert.equal(list[1], collection.last());
384     assert.equal(list[1].get('id'), 4);
385
386     list = collection.add([{id: 3}, {id: 6}], {validate: true});
387     assert.equal(collection.length, 3);
388     assert.equal(list[0], false);
389     assert.equal(list[1].get('id'), 6);
390
391     var result = collection.add({id: 6});
392     assert.equal(result.cid, list[1].cid);
393
394     result = collection.remove({id: 6});
395     assert.equal(collection.length, 2);
396     assert.equal(result.id, 6);
397
398     list = collection.remove([{id: 2}, {id: 8}]);
399     assert.equal(collection.length, 1);
400     assert.equal(list[0].get('id'), 2);
401     assert.equal(list[1], null);
402   });
403
404   QUnit.test('shift and pop', function(assert) {
405     assert.expect(2);
406     var collection = new Backbone.Collection([{a: 'a'}, {b: 'b'}, {c: 'c'}]);
407     assert.equal(collection.shift().get('a'), 'a');
408     assert.equal(collection.pop().get('c'), 'c');
409   });
410
411   QUnit.test('slice', function(assert) {
412     assert.expect(2);
413     var collection = new Backbone.Collection([{a: 'a'}, {b: 'b'}, {c: 'c'}]);
414     var array = collection.slice(1, 3);
415     assert.equal(array.length, 2);
416     assert.equal(array[0].get('b'), 'b');
417   });
418
419   QUnit.test('events are unbound on remove', function(assert) {
420     assert.expect(3);
421     var counter = 0;
422     var dj = new Backbone.Model();
423     var emcees = new Backbone.Collection([dj]);
424     emcees.on('change', function(){ counter++; });
425     dj.set({name: 'Kool'});
426     assert.equal(counter, 1);
427     emcees.reset([]);
428     assert.equal(dj.collection, undefined);
429     dj.set({name: 'Shadow'});
430     assert.equal(counter, 1);
431   });
432
433   QUnit.test('remove in multiple collections', function(assert) {
434     assert.expect(7);
435     var modelData = {
436       id: 5,
437       title: 'Othello'
438     };
439     var passed = false;
440     var m1 = new Backbone.Model(modelData);
441     var m2 = new Backbone.Model(modelData);
442     m2.on('remove', function() {
443       passed = true;
444     });
445     var col1 = new Backbone.Collection([m1]);
446     var col2 = new Backbone.Collection([m2]);
447     assert.notEqual(m1, m2);
448     assert.ok(col1.length === 1);
449     assert.ok(col2.length === 1);
450     col1.remove(m1);
451     assert.equal(passed, false);
452     assert.ok(col1.length === 0);
453     col2.remove(m1);
454     assert.ok(col2.length === 0);
455     assert.equal(passed, true);
456   });
457
458   QUnit.test('remove same model in multiple collection', function(assert) {
459     assert.expect(16);
460     var counter = 0;
461     var m = new Backbone.Model({id: 5, title: 'Othello'});
462     m.on('remove', function(model, collection) {
463       counter++;
464       assert.equal(m, model);
465       if (counter > 1) {
466         assert.equal(collection, col1);
467       } else {
468         assert.equal(collection, col2);
469       }
470     });
471     var col1 = new Backbone.Collection([m]);
472     col1.on('remove', function(model, collection) {
473       assert.equal(m, model);
474       assert.equal(col1, collection);
475     });
476     var col2 = new Backbone.Collection([m]);
477     col2.on('remove', function(model, collection) {
478       assert.equal(m, model);
479       assert.equal(col2, collection);
480     });
481     assert.equal(col1, m.collection);
482     col2.remove(m);
483     assert.ok(col2.length === 0);
484     assert.ok(col1.length === 1);
485     assert.equal(counter, 1);
486     assert.equal(col1, m.collection);
487     col1.remove(m);
488     assert.equal(null, m.collection);
489     assert.ok(col1.length === 0);
490     assert.equal(counter, 2);
491   });
492
493   QUnit.test('model destroy removes from all collections', function(assert) {
494     assert.expect(3);
495     var m = new Backbone.Model({id: 5, title: 'Othello'});
496     m.sync = function(method, model, options) { options.success(); };
497     var col1 = new Backbone.Collection([m]);
498     var col2 = new Backbone.Collection([m]);
499     m.destroy();
500     assert.ok(col1.length === 0);
501     assert.ok(col2.length === 0);
502     assert.equal(undefined, m.collection);
503   });
504
505   QUnit.test('Collection: non-persisted model destroy removes from all collections', function(assert) {
506     assert.expect(3);
507     var m = new Backbone.Model({title: 'Othello'});
508     m.sync = function(method, model, options) { throw 'should not be called'; };
509     var col1 = new Backbone.Collection([m]);
510     var col2 = new Backbone.Collection([m]);
511     m.destroy();
512     assert.ok(col1.length === 0);
513     assert.ok(col2.length === 0);
514     assert.equal(undefined, m.collection);
515   });
516
517   QUnit.test('fetch', function(assert) {
518     assert.expect(4);
519     var collection = new Backbone.Collection;
520     collection.url = '/test';
521     collection.fetch();
522     assert.equal(this.syncArgs.method, 'read');
523     assert.equal(this.syncArgs.model, collection);
524     assert.equal(this.syncArgs.options.parse, true);
525
526     collection.fetch({parse: false});
527     assert.equal(this.syncArgs.options.parse, false);
528   });
529
530   QUnit.test('fetch with an error response triggers an error event', function(assert) {
531     assert.expect(1);
532     var collection = new Backbone.Collection();
533     collection.on('error', function() {
534       assert.ok(true);
535     });
536     collection.sync = function(method, model, options) { options.error(); };
537     collection.fetch();
538   });
539
540   QUnit.test('#3283 - fetch with an error response calls error with context', function(assert) {
541     assert.expect(1);
542     var collection = new Backbone.Collection();
543     var obj = {};
544     var options = {
545       context: obj,
546       error: function() {
547         assert.equal(this, obj);
548       }
549     };
550     collection.sync = function(method, model, opts) {
551       opts.error.call(opts.context);
552     };
553     collection.fetch(options);
554   });
555
556   QUnit.test('ensure fetch only parses once', function(assert) {
557     assert.expect(1);
558     var collection = new Backbone.Collection;
559     var counter = 0;
560     collection.parse = function(models) {
561       counter++;
562       return models;
563     };
564     collection.url = '/test';
565     collection.fetch();
566     this.syncArgs.options.success([]);
567     assert.equal(counter, 1);
568   });
569
570   QUnit.test('create', function(assert) {
571     assert.expect(4);
572     var collection = new Backbone.Collection;
573     collection.url = '/test';
574     var model = collection.create({label: 'f'}, {wait: true});
575     assert.equal(this.syncArgs.method, 'create');
576     assert.equal(this.syncArgs.model, model);
577     assert.equal(model.get('label'), 'f');
578     assert.equal(model.collection, collection);
579   });
580
581   QUnit.test('create with validate:true enforces validation', function(assert) {
582     assert.expect(3);
583     var ValidatingModel = Backbone.Model.extend({
584       validate: function(attrs) {
585         return 'fail';
586       }
587     });
588     var ValidatingCollection = Backbone.Collection.extend({
589       model: ValidatingModel
590     });
591     var collection = new ValidatingCollection();
592     collection.on('invalid', function(coll, error, options) {
593       assert.equal(error, 'fail');
594       assert.equal(options.validationError, 'fail');
595     });
596     assert.equal(collection.create({'foo': 'bar'}, {validate: true}), false);
597   });
598
599   QUnit.test('create will pass extra options to success callback', function(assert) {
600     assert.expect(1);
601     var Model = Backbone.Model.extend({
602       sync: function(method, model, options) {
603         _.extend(options, {specialSync: true});
604         return Backbone.Model.prototype.sync.call(this, method, model, options);
605       }
606     });
607
608     var Collection = Backbone.Collection.extend({
609       model: Model,
610       url: '/test'
611     });
612
613     var collection = new Collection;
614
615     var success = function(model, response, options) {
616       assert.ok(options.specialSync, 'Options were passed correctly to callback');
617     };
618
619     collection.create({}, {success: success});
620     this.ajaxSettings.success();
621   });
622
623   QUnit.test('create with wait:true should not call collection.parse', function(assert) {
624     assert.expect(0);
625     var Collection = Backbone.Collection.extend({
626       url: '/test',
627       parse: function() {
628         assert.ok(false);
629       }
630     });
631
632     var collection = new Collection;
633
634     collection.create({}, {wait: true});
635     this.ajaxSettings.success();
636   });
637
638   QUnit.test('a failing create returns model with errors', function(assert) {
639     var ValidatingModel = Backbone.Model.extend({
640       validate: function(attrs) {
641         return 'fail';
642       }
643     });
644     var ValidatingCollection = Backbone.Collection.extend({
645       model: ValidatingModel
646     });
647     var collection = new ValidatingCollection();
648     var m = collection.create({foo: 'bar'});
649     assert.equal(m.validationError, 'fail');
650     assert.equal(collection.length, 1);
651   });
652
653   QUnit.test('initialize', function(assert) {
654     assert.expect(1);
655     var Collection = Backbone.Collection.extend({
656       initialize: function() {
657         this.one = 1;
658       }
659     });
660     var coll = new Collection;
661     assert.equal(coll.one, 1);
662   });
663
664   QUnit.test('toJSON', function(assert) {
665     assert.expect(1);
666     assert.equal(JSON.stringify(col), '[{"id":3,"label":"a"},{"id":2,"label":"b"},{"id":1,"label":"c"},{"id":0,"label":"d"}]');
667   });
668
669   QUnit.test('where and findWhere', function(assert) {
670     assert.expect(8);
671     var model = new Backbone.Model({a: 1});
672     var coll = new Backbone.Collection([
673       model,
674       {a: 1},
675       {a: 1, b: 2},
676       {a: 2, b: 2},
677       {a: 3}
678     ]);
679     assert.equal(coll.where({a: 1}).length, 3);
680     assert.equal(coll.where({a: 2}).length, 1);
681     assert.equal(coll.where({a: 3}).length, 1);
682     assert.equal(coll.where({b: 1}).length, 0);
683     assert.equal(coll.where({b: 2}).length, 2);
684     assert.equal(coll.where({a: 1, b: 2}).length, 1);
685     assert.equal(coll.findWhere({a: 1}), model);
686     assert.equal(coll.findWhere({a: 4}), void 0);
687   });
688
689   QUnit.test('Underscore methods', function(assert) {
690     assert.expect(21);
691     assert.equal(col.map(function(model){ return model.get('label'); }).join(' '), 'a b c d');
692     assert.equal(col.some(function(model){ return model.id === 100; }), false);
693     assert.equal(col.some(function(model){ return model.id === 0; }), true);
694     assert.equal(col.reduce(function(m1, m2) {return m1.id > m2.id ? m1 : m2;}).id, 3);
695     assert.equal(col.reduceRight(function(m1, m2) {return m1.id > m2.id ? m1 : m2;}).id, 3);
696     assert.equal(col.indexOf(b), 1);
697     assert.equal(col.size(), 4);
698     assert.equal(col.rest().length, 3);
699     assert.ok(!_.includes(col.rest(), a));
700     assert.ok(_.includes(col.rest(), d));
701     assert.ok(!col.isEmpty());
702     assert.ok(!_.includes(col.without(d), d));
703
704     var wrapped = col.chain();
705     assert.equal(wrapped.map('id').max().value(), 3);
706     assert.equal(wrapped.map('id').min().value(), 0);
707     assert.deepEqual(wrapped
708       .filter(function(o){ return o.id % 2 === 0; })
709       .map(function(o){ return o.id * 2; })
710       .value(),
711       [4, 0]);
712     assert.deepEqual(col.difference([c, d]), [a, b]);
713     assert.ok(col.includes(col.sample()));
714
715     var first = col.first();
716     assert.deepEqual(col.groupBy(function(model){ return model.id; })[first.id], [first]);
717     assert.deepEqual(col.countBy(function(model){ return model.id; }), {0: 1, 1: 1, 2: 1, 3: 1});
718     assert.deepEqual(col.sortBy(function(model){ return model.id; })[0], col.at(3));
719     assert.ok(col.indexBy('id')[first.id] === first);
720   });
721
722   QUnit.test('Underscore methods with object-style and property-style iteratee', function(assert) {
723     assert.expect(26);
724     var model = new Backbone.Model({a: 4, b: 1, e: 3});
725     var coll = new Backbone.Collection([
726       {a: 1, b: 1},
727       {a: 2, b: 1, c: 1},
728       {a: 3, b: 1},
729       model
730     ]);
731     assert.equal(coll.find({a: 0}), undefined);
732     assert.deepEqual(coll.find({a: 4}), model);
733     assert.equal(coll.find('d'), undefined);
734     assert.deepEqual(coll.find('e'), model);
735     assert.equal(coll.filter({a: 0}), false);
736     assert.deepEqual(coll.filter({a: 4}), [model]);
737     assert.equal(coll.some({a: 0}), false);
738     assert.equal(coll.some({a: 1}), true);
739     assert.equal(coll.reject({a: 0}).length, 4);
740     assert.deepEqual(coll.reject({a: 4}), _.without(coll.models, model));
741     assert.equal(coll.every({a: 0}), false);
742     assert.equal(coll.every({b: 1}), true);
743     assert.deepEqual(coll.partition({a: 0})[0], []);
744     assert.deepEqual(coll.partition({a: 0})[1], coll.models);
745     assert.deepEqual(coll.partition({a: 4})[0], [model]);
746     assert.deepEqual(coll.partition({a: 4})[1], _.without(coll.models, model));
747     assert.deepEqual(coll.map({a: 2}), [false, true, false, false]);
748     assert.deepEqual(coll.map('a'), [1, 2, 3, 4]);
749     assert.deepEqual(coll.sortBy('a')[3], model);
750     assert.deepEqual(coll.sortBy('e')[0], model);
751     assert.deepEqual(coll.countBy({a: 4}), {'false': 3, 'true': 1});
752     assert.deepEqual(coll.countBy('d'), {'undefined': 4});
753     assert.equal(coll.findIndex({b: 1}), 0);
754     assert.equal(coll.findIndex({b: 9}), -1);
755     assert.equal(coll.findLastIndex({b: 1}), 3);
756     assert.equal(coll.findLastIndex({b: 9}), -1);
757   });
758
759   QUnit.test('reset', function(assert) {
760     assert.expect(16);
761
762     var resetCount = 0;
763     var models = col.models;
764     col.on('reset', function() { resetCount += 1; });
765     col.reset([]);
766     assert.equal(resetCount, 1);
767     assert.equal(col.length, 0);
768     assert.equal(col.last(), null);
769     col.reset(models);
770     assert.equal(resetCount, 2);
771     assert.equal(col.length, 4);
772     assert.equal(col.last(), d);
773     col.reset(_.map(models, function(m){ return m.attributes; }));
774     assert.equal(resetCount, 3);
775     assert.equal(col.length, 4);
776     assert.ok(col.last() !== d);
777     assert.ok(_.isEqual(col.last().attributes, d.attributes));
778     col.reset();
779     assert.equal(col.length, 0);
780     assert.equal(resetCount, 4);
781
782     var f = new Backbone.Model({id: 20, label: 'f'});
783     col.reset([undefined, f]);
784     assert.equal(col.length, 2);
785     assert.equal(resetCount, 5);
786
787     col.reset(new Array(4));
788     assert.equal(col.length, 4);
789     assert.equal(resetCount, 6);
790   });
791
792   QUnit.test('reset with different values', function(assert) {
793     var collection = new Backbone.Collection({id: 1});
794     collection.reset({id: 1, a: 1});
795     assert.equal(collection.get(1).get('a'), 1);
796   });
797
798   QUnit.test('same references in reset', function(assert) {
799     var model = new Backbone.Model({id: 1});
800     var collection = new Backbone.Collection({id: 1});
801     collection.reset(model);
802     assert.equal(collection.get(1), model);
803   });
804
805   QUnit.test('reset passes caller options', function(assert) {
806     assert.expect(3);
807     var Model = Backbone.Model.extend({
808       initialize: function(attrs, options) {
809         this.modelParameter = options.modelParameter;
810       }
811     });
812     var collection = new (Backbone.Collection.extend({model: Model}))();
813     collection.reset([{astring: 'green', anumber: 1}, {astring: 'blue', anumber: 2}], {modelParameter: 'model parameter'});
814     assert.equal(collection.length, 2);
815     collection.each(function(model) {
816       assert.equal(model.modelParameter, 'model parameter');
817     });
818   });
819
820   QUnit.test('reset does not alter options by reference', function(assert) {
821     assert.expect(2);
822     var collection = new Backbone.Collection([{id: 1}]);
823     var origOpts = {};
824     collection.on('reset', function(coll, opts){
825       assert.equal(origOpts.previousModels, undefined);
826       assert.equal(opts.previousModels[0].id, 1);
827     });
828     collection.reset([], origOpts);
829   });
830
831   QUnit.test('trigger custom events on models', function(assert) {
832     assert.expect(1);
833     var fired = null;
834     a.on('custom', function() { fired = true; });
835     a.trigger('custom');
836     assert.equal(fired, true);
837   });
838
839   QUnit.test('add does not alter arguments', function(assert) {
840     assert.expect(2);
841     var attrs = {};
842     var models = [attrs];
843     new Backbone.Collection().add(models);
844     assert.equal(models.length, 1);
845     assert.ok(attrs === models[0]);
846   });
847
848   QUnit.test('#714: access `model.collection` in a brand new model.', function(assert) {
849     assert.expect(2);
850     var collection = new Backbone.Collection;
851     collection.url = '/test';
852     var Model = Backbone.Model.extend({
853       set: function(attrs) {
854         assert.equal(attrs.prop, 'value');
855         assert.equal(this.collection, collection);
856         return this;
857       }
858     });
859     collection.model = Model;
860     collection.create({prop: 'value'});
861   });
862
863   QUnit.test('#574, remove its own reference to the .models array.', function(assert) {
864     assert.expect(2);
865     var collection = new Backbone.Collection([
866       {id: 1}, {id: 2}, {id: 3}, {id: 4}, {id: 5}, {id: 6}
867     ]);
868     assert.equal(collection.length, 6);
869     collection.remove(collection.models);
870     assert.equal(collection.length, 0);
871   });
872
873   QUnit.test('#861, adding models to a collection which do not pass validation, with validate:true', function(assert) {
874     assert.expect(2);
875     var Model = Backbone.Model.extend({
876       validate: function(attrs) {
877         if (attrs.id === 3) return "id can't be 3";
878       }
879     });
880
881     var Collection = Backbone.Collection.extend({
882       model: Model
883     });
884
885     var collection = new Collection;
886     collection.on('invalid', function() { assert.ok(true); });
887
888     collection.add([{id: 1}, {id: 2}, {id: 3}, {id: 4}, {id: 5}, {id: 6}], {validate: true});
889     assert.deepEqual(collection.pluck('id'), [1, 2, 4, 5, 6]);
890   });
891
892   QUnit.test('Invalid models are discarded with validate:true.', function(assert) {
893     assert.expect(5);
894     var collection = new Backbone.Collection;
895     collection.on('test', function() { assert.ok(true); });
896     collection.model = Backbone.Model.extend({
897       validate: function(attrs){ if (!attrs.valid) return 'invalid'; }
898     });
899     var model = new collection.model({id: 1, valid: true});
900     collection.add([model, {id: 2}], {validate: true});
901     model.trigger('test');
902     assert.ok(collection.get(model.cid));
903     assert.ok(collection.get(1));
904     assert.ok(!collection.get(2));
905     assert.equal(collection.length, 1);
906   });
907
908   QUnit.test('multiple copies of the same model', function(assert) {
909     assert.expect(3);
910     var collection = new Backbone.Collection();
911     var model = new Backbone.Model();
912     collection.add([model, model]);
913     assert.equal(collection.length, 1);
914     collection.add([{id: 1}, {id: 1}]);
915     assert.equal(collection.length, 2);
916     assert.equal(collection.last().id, 1);
917   });
918
919   QUnit.test('#964 - collection.get return inconsistent', function(assert) {
920     assert.expect(2);
921     var collection = new Backbone.Collection();
922     assert.ok(collection.get(null) === undefined);
923     assert.ok(collection.get() === undefined);
924   });
925
926   QUnit.test('#1112 - passing options.model sets collection.model', function(assert) {
927     assert.expect(2);
928     var Model = Backbone.Model.extend({});
929     var collection = new Backbone.Collection([{id: 1}], {model: Model});
930     assert.ok(collection.model === Model);
931     assert.ok(collection.at(0) instanceof Model);
932   });
933
934   QUnit.test('null and undefined are invalid ids.', function(assert) {
935     assert.expect(2);
936     var model = new Backbone.Model({id: 1});
937     var collection = new Backbone.Collection([model]);
938     model.set({id: null});
939     assert.ok(!collection.get('null'));
940     model.set({id: 1});
941     model.set({id: undefined});
942     assert.ok(!collection.get('undefined'));
943   });
944
945   QUnit.test('falsy comparator', function(assert) {
946     assert.expect(4);
947     var Col = Backbone.Collection.extend({
948       comparator: function(model){ return model.id; }
949     });
950     var collection = new Col();
951     var colFalse = new Col(null, {comparator: false});
952     var colNull = new Col(null, {comparator: null});
953     var colUndefined = new Col(null, {comparator: undefined});
954     assert.ok(collection.comparator);
955     assert.ok(!colFalse.comparator);
956     assert.ok(!colNull.comparator);
957     assert.ok(colUndefined.comparator);
958   });
959
960   QUnit.test('#1355 - `options` is passed to success callbacks', function(assert) {
961     assert.expect(2);
962     var m = new Backbone.Model({x: 1});
963     var collection = new Backbone.Collection();
964     var opts = {
965       opts: true,
966       success: function(coll, resp, options) {
967         assert.ok(options.opts);
968       }
969     };
970     collection.sync = m.sync = function( method, coll, options ){
971       options.success({});
972     };
973     collection.fetch(opts);
974     collection.create(m, opts);
975   });
976
977   QUnit.test("#1412 - Trigger 'request' and 'sync' events.", function(assert) {
978     assert.expect(4);
979     var collection = new Backbone.Collection;
980     collection.url = '/test';
981     Backbone.ajax = function(settings){ settings.success(); };
982
983     collection.on('request', function(obj, xhr, options) {
984       assert.ok(obj === collection, "collection has correct 'request' event after fetching");
985     });
986     collection.on('sync', function(obj, response, options) {
987       assert.ok(obj === collection, "collection has correct 'sync' event after fetching");
988     });
989     collection.fetch();
990     collection.off();
991
992     collection.on('request', function(obj, xhr, options) {
993       assert.ok(obj === collection.get(1), "collection has correct 'request' event after one of its models save");
994     });
995     collection.on('sync', function(obj, response, options) {
996       assert.ok(obj === collection.get(1), "collection has correct 'sync' event after one of its models save");
997     });
998     collection.create({id: 1});
999     collection.off();
1000   });
1001
1002   QUnit.test('#3283 - fetch, create calls success with context', function(assert) {
1003     assert.expect(2);
1004     var collection = new Backbone.Collection;
1005     collection.url = '/test';
1006     Backbone.ajax = function(settings) {
1007       settings.success.call(settings.context);
1008     };
1009     var obj = {};
1010     var options = {
1011       context: obj,
1012       success: function() {
1013         assert.equal(this, obj);
1014       }
1015     };
1016
1017     collection.fetch(options);
1018     collection.create({id: 1}, options);
1019   });
1020
1021   QUnit.test('#1447 - create with wait adds model.', function(assert) {
1022     assert.expect(1);
1023     var collection = new Backbone.Collection;
1024     var model = new Backbone.Model;
1025     model.sync = function(method, m, options){ options.success(); };
1026     collection.on('add', function(){ assert.ok(true); });
1027     collection.create(model, {wait: true});
1028   });
1029
1030   QUnit.test('#1448 - add sorts collection after merge.', function(assert) {
1031     assert.expect(1);
1032     var collection = new Backbone.Collection([
1033       {id: 1, x: 1},
1034       {id: 2, x: 2}
1035     ]);
1036     collection.comparator = function(model){ return model.get('x'); };
1037     collection.add({id: 1, x: 3}, {merge: true});
1038     assert.deepEqual(collection.pluck('id'), [2, 1]);
1039   });
1040
1041   QUnit.test('#1655 - groupBy can be used with a string argument.', function(assert) {
1042     assert.expect(3);
1043     var collection = new Backbone.Collection([{x: 1}, {x: 2}]);
1044     var grouped = collection.groupBy('x');
1045     assert.strictEqual(_.keys(grouped).length, 2);
1046     assert.strictEqual(grouped[1][0].get('x'), 1);
1047     assert.strictEqual(grouped[2][0].get('x'), 2);
1048   });
1049
1050   QUnit.test('#1655 - sortBy can be used with a string argument.', function(assert) {
1051     assert.expect(1);
1052     var collection = new Backbone.Collection([{x: 3}, {x: 1}, {x: 2}]);
1053     var values = _.map(collection.sortBy('x'), function(model) {
1054       return model.get('x');
1055     });
1056     assert.deepEqual(values, [1, 2, 3]);
1057   });
1058
1059   QUnit.test('#1604 - Removal during iteration.', function(assert) {
1060     assert.expect(0);
1061     var collection = new Backbone.Collection([{}, {}]);
1062     collection.on('add', function() {
1063       collection.at(0).destroy();
1064     });
1065     collection.add({}, {at: 0});
1066   });
1067
1068   QUnit.test('#1638 - `sort` during `add` triggers correctly.', function(assert) {
1069     var collection = new Backbone.Collection;
1070     collection.comparator = function(model) { return model.get('x'); };
1071     var added = [];
1072     collection.on('add', function(model) {
1073       model.set({x: 3});
1074       collection.sort();
1075       added.push(model.id);
1076     });
1077     collection.add([{id: 1, x: 1}, {id: 2, x: 2}]);
1078     assert.deepEqual(added, [1, 2]);
1079   });
1080
1081   QUnit.test('fetch parses models by default', function(assert) {
1082     assert.expect(1);
1083     var model = {};
1084     var Collection = Backbone.Collection.extend({
1085       url: 'test',
1086       model: Backbone.Model.extend({
1087         parse: function(resp) {
1088           assert.strictEqual(resp, model);
1089         }
1090       })
1091     });
1092     new Collection().fetch();
1093     this.ajaxSettings.success([model]);
1094   });
1095
1096   QUnit.test("`sort` shouldn't always fire on `add`", function(assert) {
1097     assert.expect(1);
1098     var collection = new Backbone.Collection([{id: 1}, {id: 2}, {id: 3}], {
1099       comparator: 'id'
1100     });
1101     collection.sort = function(){ assert.ok(true); };
1102     collection.add([]);
1103     collection.add({id: 1});
1104     collection.add([{id: 2}, {id: 3}]);
1105     collection.add({id: 4});
1106   });
1107
1108   QUnit.test('#1407 parse option on constructor parses collection and models', function(assert) {
1109     assert.expect(2);
1110     var model = {
1111       namespace: [{id: 1}, {id: 2}]
1112     };
1113     var Collection = Backbone.Collection.extend({
1114       model: Backbone.Model.extend({
1115         parse: function(m) {
1116           m.name = 'test';
1117           return m;
1118         }
1119       }),
1120       parse: function(m) {
1121         return m.namespace;
1122       }
1123     });
1124     var collection = new Collection(model, {parse: true});
1125
1126     assert.equal(collection.length, 2);
1127     assert.equal(collection.at(0).get('name'), 'test');
1128   });
1129
1130   QUnit.test('#1407 parse option on reset parses collection and models', function(assert) {
1131     assert.expect(2);
1132     var model = {
1133       namespace: [{id: 1}, {id: 2}]
1134     };
1135     var Collection = Backbone.Collection.extend({
1136       model: Backbone.Model.extend({
1137         parse: function(m) {
1138           m.name = 'test';
1139           return m;
1140         }
1141       }),
1142       parse: function(m) {
1143         return m.namespace;
1144       }
1145     });
1146     var collection = new Collection();
1147     collection.reset(model, {parse: true});
1148
1149     assert.equal(collection.length, 2);
1150     assert.equal(collection.at(0).get('name'), 'test');
1151   });
1152
1153
1154   QUnit.test('Reset includes previous models in triggered event.', function(assert) {
1155     assert.expect(1);
1156     var model = new Backbone.Model();
1157     var collection = new Backbone.Collection([model]);
1158     collection.on('reset', function(coll, options) {
1159       assert.deepEqual(options.previousModels, [model]);
1160     });
1161     collection.reset([]);
1162   });
1163
1164   QUnit.test('set', function(assert) {
1165     var m1 = new Backbone.Model();
1166     var m2 = new Backbone.Model({id: 2});
1167     var m3 = new Backbone.Model();
1168     var collection = new Backbone.Collection([m1, m2]);
1169
1170     // Test add/change/remove events
1171     collection.on('add', function(model) {
1172       assert.strictEqual(model, m3);
1173     });
1174     collection.on('change', function(model) {
1175       assert.strictEqual(model, m2);
1176     });
1177     collection.on('remove', function(model) {
1178       assert.strictEqual(model, m1);
1179     });
1180
1181     // remove: false doesn't remove any models
1182     collection.set([], {remove: false});
1183     assert.strictEqual(collection.length, 2);
1184
1185     // add: false doesn't add any models
1186     collection.set([m1, m2, m3], {add: false});
1187     assert.strictEqual(collection.length, 2);
1188
1189     // merge: false doesn't change any models
1190     collection.set([m1, {id: 2, a: 1}], {merge: false});
1191     assert.strictEqual(m2.get('a'), void 0);
1192
1193     // add: false, remove: false only merges existing models
1194     collection.set([m1, {id: 2, a: 0}, m3, {id: 4}], {add: false, remove: false});
1195     assert.strictEqual(collection.length, 2);
1196     assert.strictEqual(m2.get('a'), 0);
1197
1198     // default options add/remove/merge as appropriate
1199     collection.set([{id: 2, a: 1}, m3]);
1200     assert.strictEqual(collection.length, 2);
1201     assert.strictEqual(m2.get('a'), 1);
1202
1203     // Test removing models not passing an argument
1204     collection.off('remove').on('remove', function(model) {
1205       assert.ok(model === m2 || model === m3);
1206     });
1207     collection.set([]);
1208     assert.strictEqual(collection.length, 0);
1209
1210     // Test null models on set doesn't clear collection
1211     collection.off();
1212     collection.set([{id: 1}]);
1213     collection.set();
1214     assert.strictEqual(collection.length, 1);
1215   });
1216
1217   QUnit.test('set with only cids', function(assert) {
1218     assert.expect(3);
1219     var m1 = new Backbone.Model;
1220     var m2 = new Backbone.Model;
1221     var collection = new Backbone.Collection;
1222     collection.set([m1, m2]);
1223     assert.equal(collection.length, 2);
1224     collection.set([m1]);
1225     assert.equal(collection.length, 1);
1226     collection.set([m1, m1, m1, m2, m2], {remove: false});
1227     assert.equal(collection.length, 2);
1228   });
1229
1230   QUnit.test('set with only idAttribute', function(assert) {
1231     assert.expect(3);
1232     var m1 = {_id: 1};
1233     var m2 = {_id: 2};
1234     var Col = Backbone.Collection.extend({
1235       model: Backbone.Model.extend({
1236         idAttribute: '_id'
1237       })
1238     });
1239     var collection = new Col;
1240     collection.set([m1, m2]);
1241     assert.equal(collection.length, 2);
1242     collection.set([m1]);
1243     assert.equal(collection.length, 1);
1244     collection.set([m1, m1, m1, m2, m2], {remove: false});
1245     assert.equal(collection.length, 2);
1246   });
1247
1248   QUnit.test('set + merge with default values defined', function(assert) {
1249     var Model = Backbone.Model.extend({
1250       defaults: {
1251         key: 'value'
1252       }
1253     });
1254     var m = new Model({id: 1});
1255     var collection = new Backbone.Collection([m], {model: Model});
1256     assert.equal(collection.first().get('key'), 'value');
1257
1258     collection.set({id: 1, key: 'other'});
1259     assert.equal(collection.first().get('key'), 'other');
1260
1261     collection.set({id: 1, other: 'value'});
1262     assert.equal(collection.first().get('key'), 'other');
1263     assert.equal(collection.length, 1);
1264   });
1265
1266   QUnit.test('merge without mutation', function(assert) {
1267     var Model = Backbone.Model.extend({
1268       initialize: function(attrs, options) {
1269         if (attrs.child) {
1270           this.set('child', new Model(attrs.child, options), options);
1271         }
1272       }
1273     });
1274     var Collection = Backbone.Collection.extend({model: Model});
1275     var data = [{id: 1, child: {id: 2}}];
1276     var collection = new Collection(data);
1277     assert.equal(collection.first().id, 1);
1278     collection.set(data);
1279     assert.equal(collection.first().id, 1);
1280     collection.set([{id: 2, child: {id: 2}}].concat(data));
1281     assert.deepEqual(collection.pluck('id'), [2, 1]);
1282   });
1283
1284   QUnit.test('`set` and model level `parse`', function(assert) {
1285     var Model = Backbone.Model.extend({});
1286     var Collection = Backbone.Collection.extend({
1287       model: Model,
1288       parse: function(res) { return _.map(res.models, 'model'); }
1289     });
1290     var model = new Model({id: 1});
1291     var collection = new Collection(model);
1292     collection.set({models: [
1293       {model: {id: 1}},
1294       {model: {id: 2}}
1295     ]}, {parse: true});
1296     assert.equal(collection.first(), model);
1297   });
1298
1299   QUnit.test('`set` data is only parsed once', function(assert) {
1300     var collection = new Backbone.Collection();
1301     collection.model = Backbone.Model.extend({
1302       parse: function(data) {
1303         assert.equal(data.parsed, void 0);
1304         data.parsed = true;
1305         return data;
1306       }
1307     });
1308     collection.set({}, {parse: true});
1309   });
1310
1311   QUnit.test('`set` matches input order in the absence of a comparator', function(assert) {
1312     var one = new Backbone.Model({id: 1});
1313     var two = new Backbone.Model({id: 2});
1314     var three = new Backbone.Model({id: 3});
1315     var collection = new Backbone.Collection([one, two, three]);
1316     collection.set([{id: 3}, {id: 2}, {id: 1}]);
1317     assert.deepEqual(collection.models, [three, two, one]);
1318     collection.set([{id: 1}, {id: 2}]);
1319     assert.deepEqual(collection.models, [one, two]);
1320     collection.set([two, three, one]);
1321     assert.deepEqual(collection.models, [two, three, one]);
1322     collection.set([{id: 1}, {id: 2}], {remove: false});
1323     assert.deepEqual(collection.models, [two, three, one]);
1324     collection.set([{id: 1}, {id: 2}, {id: 3}], {merge: false});
1325     assert.deepEqual(collection.models, [one, two, three]);
1326     collection.set([three, two, one, {id: 4}], {add: false});
1327     assert.deepEqual(collection.models, [one, two, three]);
1328   });
1329
1330   QUnit.test('#1894 - Push should not trigger a sort', function(assert) {
1331     assert.expect(0);
1332     var Collection = Backbone.Collection.extend({
1333       comparator: 'id',
1334       sort: function() { assert.ok(false); }
1335     });
1336     new Collection().push({id: 1});
1337   });
1338
1339   QUnit.test('#2428 - push duplicate models, return the correct one', function(assert) {
1340     assert.expect(1);
1341     var collection = new Backbone.Collection;
1342     var model1 = collection.push({id: 101});
1343     var model2 = collection.push({id: 101});
1344     assert.ok(model2.cid === model1.cid);
1345   });
1346
1347   QUnit.test('`set` with non-normal id', function(assert) {
1348     var Collection = Backbone.Collection.extend({
1349       model: Backbone.Model.extend({idAttribute: '_id'})
1350     });
1351     var collection = new Collection({_id: 1});
1352     collection.set([{_id: 1, a: 1}], {add: false});
1353     assert.equal(collection.first().get('a'), 1);
1354   });
1355
1356   QUnit.test('#1894 - `sort` can optionally be turned off', function(assert) {
1357     assert.expect(0);
1358     var Collection = Backbone.Collection.extend({
1359       comparator: 'id',
1360       sort: function() { assert.ok(false); }
1361     });
1362     new Collection().add({id: 1}, {sort: false});
1363   });
1364
1365   QUnit.test('#1915 - `parse` data in the right order in `set`', function(assert) {
1366     var collection = new (Backbone.Collection.extend({
1367       parse: function(data) {
1368         assert.strictEqual(data.status, 'ok');
1369         return data.data;
1370       }
1371     }));
1372     var res = {status: 'ok', data: [{id: 1}]};
1373     collection.set(res, {parse: true});
1374   });
1375
1376   QUnit.test('#1939 - `parse` is passed `options`', function(assert) {
1377     var done = assert.async();
1378     assert.expect(1);
1379     var collection = new (Backbone.Collection.extend({
1380       url: '/',
1381       parse: function(data, options) {
1382         assert.strictEqual(options.xhr.someHeader, 'headerValue');
1383         return data;
1384       }
1385     }));
1386     var ajax = Backbone.ajax;
1387     Backbone.ajax = function(params) {
1388       _.defer(params.success, []);
1389       return {someHeader: 'headerValue'};
1390     };
1391     collection.fetch({
1392       success: function() { done(); }
1393     });
1394     Backbone.ajax = ajax;
1395   });
1396
1397   QUnit.test('fetch will pass extra options to success callback', function(assert) {
1398     assert.expect(1);
1399     var SpecialSyncCollection = Backbone.Collection.extend({
1400       url: '/test',
1401       sync: function(method, collection, options) {
1402         _.extend(options, {specialSync: true});
1403         return Backbone.Collection.prototype.sync.call(this, method, collection, options);
1404       }
1405     });
1406
1407     var collection = new SpecialSyncCollection();
1408
1409     var onSuccess = function(coll, resp, options) {
1410       assert.ok(options.specialSync, 'Options were passed correctly to callback');
1411     };
1412
1413     collection.fetch({success: onSuccess});
1414     this.ajaxSettings.success();
1415   });
1416
1417   QUnit.test('`add` only `sort`s when necessary', function(assert) {
1418     assert.expect(2);
1419     var collection = new (Backbone.Collection.extend({
1420       comparator: 'a'
1421     }))([{id: 1}, {id: 2}, {id: 3}]);
1422     collection.on('sort', function() { assert.ok(true); });
1423     collection.add({id: 4}); // do sort, new model
1424     collection.add({id: 1, a: 1}, {merge: true}); // do sort, comparator change
1425     collection.add({id: 1, b: 1}, {merge: true}); // don't sort, no comparator change
1426     collection.add({id: 1, a: 1}, {merge: true}); // don't sort, no comparator change
1427     collection.add(collection.models); // don't sort, nothing new
1428     collection.add(collection.models, {merge: true}); // don't sort
1429   });
1430
1431   QUnit.test('`add` only `sort`s when necessary with comparator function', function(assert) {
1432     assert.expect(3);
1433     var collection = new (Backbone.Collection.extend({
1434       comparator: function(m1, m2) {
1435         return m1.get('a') > m2.get('a') ? 1 : (m1.get('a') < m2.get('a') ? -1 : 0);
1436       }
1437     }))([{id: 1}, {id: 2}, {id: 3}]);
1438     collection.on('sort', function() { assert.ok(true); });
1439     collection.add({id: 4}); // do sort, new model
1440     collection.add({id: 1, a: 1}, {merge: true}); // do sort, model change
1441     collection.add({id: 1, b: 1}, {merge: true}); // do sort, model change
1442     collection.add({id: 1, a: 1}, {merge: true}); // don't sort, no model change
1443     collection.add(collection.models); // don't sort, nothing new
1444     collection.add(collection.models, {merge: true}); // don't sort
1445   });
1446
1447   QUnit.test('Attach options to collection.', function(assert) {
1448     assert.expect(2);
1449     var Model = Backbone.Model;
1450     var comparator = function(){};
1451
1452     var collection = new Backbone.Collection([], {
1453       model: Model,
1454       comparator: comparator
1455     });
1456
1457     assert.ok(collection.model === Model);
1458     assert.ok(collection.comparator === comparator);
1459   });
1460
1461   QUnit.test('Pass falsey for `models` for empty Col with `options`', function(assert) {
1462     assert.expect(9);
1463     var opts = {a: 1, b: 2};
1464     _.forEach([undefined, null, false], function(falsey) {
1465       var Collection = Backbone.Collection.extend({
1466         initialize: function(models, options) {
1467           assert.strictEqual(models, falsey);
1468           assert.strictEqual(options, opts);
1469         }
1470       });
1471
1472       var collection = new Collection(falsey, opts);
1473       assert.strictEqual(collection.length, 0);
1474     });
1475   });
1476
1477   QUnit.test('`add` overrides `set` flags', function(assert) {
1478     var collection = new Backbone.Collection();
1479     collection.once('add', function(model, coll, options) {
1480       coll.add({id: 2}, options);
1481     });
1482     collection.set({id: 1});
1483     assert.equal(collection.length, 2);
1484   });
1485
1486   QUnit.test('#2606 - Collection#create, success arguments', function(assert) {
1487     assert.expect(1);
1488     var collection = new Backbone.Collection;
1489     collection.url = 'test';
1490     collection.create({}, {
1491       success: function(model, resp, options) {
1492         assert.strictEqual(resp, 'response');
1493       }
1494     });
1495     this.ajaxSettings.success('response');
1496   });
1497
1498   QUnit.test('#2612 - nested `parse` works with `Collection#set`', function(assert) {
1499
1500     var Job = Backbone.Model.extend({
1501       constructor: function() {
1502         this.items = new Items();
1503         Backbone.Model.apply(this, arguments);
1504       },
1505       parse: function(attrs) {
1506         this.items.set(attrs.items, {parse: true});
1507         return _.omit(attrs, 'items');
1508       }
1509     });
1510
1511     var Item = Backbone.Model.extend({
1512       constructor: function() {
1513         this.subItems = new Backbone.Collection();
1514         Backbone.Model.apply(this, arguments);
1515       },
1516       parse: function(attrs) {
1517         this.subItems.set(attrs.subItems, {parse: true});
1518         return _.omit(attrs, 'subItems');
1519       }
1520     });
1521
1522     var Items = Backbone.Collection.extend({
1523       model: Item
1524     });
1525
1526     var data = {
1527       name: 'JobName',
1528       id: 1,
1529       items: [{
1530         id: 1,
1531         name: 'Sub1',
1532         subItems: [
1533           {id: 1, subName: 'One'},
1534           {id: 2, subName: 'Two'}
1535         ]
1536       }, {
1537         id: 2,
1538         name: 'Sub2',
1539         subItems: [
1540           {id: 3, subName: 'Three'},
1541           {id: 4, subName: 'Four'}
1542         ]
1543       }]
1544     };
1545
1546     var newData = {
1547       name: 'NewJobName',
1548       id: 1,
1549       items: [{
1550         id: 1,
1551         name: 'NewSub1',
1552         subItems: [
1553           {id: 1, subName: 'NewOne'},
1554           {id: 2, subName: 'NewTwo'}
1555         ]
1556       }, {
1557         id: 2,
1558         name: 'NewSub2',
1559         subItems: [
1560           {id: 3, subName: 'NewThree'},
1561           {id: 4, subName: 'NewFour'}
1562         ]
1563       }]
1564     };
1565
1566     var job = new Job(data, {parse: true});
1567     assert.equal(job.get('name'), 'JobName');
1568     assert.equal(job.items.at(0).get('name'), 'Sub1');
1569     assert.equal(job.items.length, 2);
1570     assert.equal(job.items.get(1).subItems.get(1).get('subName'), 'One');
1571     assert.equal(job.items.get(2).subItems.get(3).get('subName'), 'Three');
1572     job.set(job.parse(newData, {parse: true}));
1573     assert.equal(job.get('name'), 'NewJobName');
1574     assert.equal(job.items.at(0).get('name'), 'NewSub1');
1575     assert.equal(job.items.length, 2);
1576     assert.equal(job.items.get(1).subItems.get(1).get('subName'), 'NewOne');
1577     assert.equal(job.items.get(2).subItems.get(3).get('subName'), 'NewThree');
1578   });
1579
1580   QUnit.test('_addReference binds all collection events & adds to the lookup hashes', function(assert) {
1581     assert.expect(8);
1582
1583     var calls = {add: 0, remove: 0};
1584
1585     var Collection = Backbone.Collection.extend({
1586
1587       _addReference: function(model) {
1588         Backbone.Collection.prototype._addReference.apply(this, arguments);
1589         calls.add++;
1590         assert.equal(model, this._byId[model.id]);
1591         assert.equal(model, this._byId[model.cid]);
1592         assert.equal(model._events.all.length, 1);
1593       },
1594
1595       _removeReference: function(model) {
1596         Backbone.Collection.prototype._removeReference.apply(this, arguments);
1597         calls.remove++;
1598         assert.equal(this._byId[model.id], void 0);
1599         assert.equal(this._byId[model.cid], void 0);
1600         assert.equal(model.collection, void 0);
1601       }
1602
1603     });
1604
1605     var collection = new Collection();
1606     var model = collection.add({id: 1});
1607     collection.remove(model);
1608
1609     assert.equal(calls.add, 1);
1610     assert.equal(calls.remove, 1);
1611   });
1612
1613   QUnit.test('Do not allow duplicate models to be `add`ed or `set`', function(assert) {
1614     var collection = new Backbone.Collection();
1615
1616     collection.add([{id: 1}, {id: 1}]);
1617     assert.equal(collection.length, 1);
1618     assert.equal(collection.models.length, 1);
1619
1620     collection.set([{id: 1}, {id: 1}]);
1621     assert.equal(collection.length, 1);
1622     assert.equal(collection.models.length, 1);
1623   });
1624
1625   QUnit.test('#3020: #set with {add: false} should not throw.', function(assert) {
1626     assert.expect(2);
1627     var collection = new Backbone.Collection;
1628     collection.set([{id: 1}], {add: false});
1629     assert.strictEqual(collection.length, 0);
1630     assert.strictEqual(collection.models.length, 0);
1631   });
1632
1633   QUnit.test('create with wait, model instance, #3028', function(assert) {
1634     assert.expect(1);
1635     var collection = new Backbone.Collection();
1636     var model = new Backbone.Model({id: 1});
1637     model.sync = function(){
1638       assert.equal(this.collection, collection);
1639     };
1640     collection.create(model, {wait: true});
1641   });
1642
1643   QUnit.test('modelId', function(assert) {
1644     var Stooge = Backbone.Model.extend();
1645     var StoogeCollection = Backbone.Collection.extend({model: Stooge});
1646
1647     // Default to using `Collection::model::idAttribute`.
1648     assert.equal(StoogeCollection.prototype.modelId({id: 1}), 1);
1649     Stooge.prototype.idAttribute = '_id';
1650     assert.equal(StoogeCollection.prototype.modelId({_id: 1}), 1);
1651   });
1652
1653   QUnit.test('Polymorphic models work with "simple" constructors', function(assert) {
1654     var A = Backbone.Model.extend();
1655     var B = Backbone.Model.extend();
1656     var C = Backbone.Collection.extend({
1657       model: function(attrs) {
1658         return attrs.type === 'a' ? new A(attrs) : new B(attrs);
1659       }
1660     });
1661     var collection = new C([{id: 1, type: 'a'}, {id: 2, type: 'b'}]);
1662     assert.equal(collection.length, 2);
1663     assert.ok(collection.at(0) instanceof A);
1664     assert.equal(collection.at(0).id, 1);
1665     assert.ok(collection.at(1) instanceof B);
1666     assert.equal(collection.at(1).id, 2);
1667   });
1668
1669   QUnit.test('Polymorphic models work with "advanced" constructors', function(assert) {
1670     var A = Backbone.Model.extend({idAttribute: '_id'});
1671     var B = Backbone.Model.extend({idAttribute: '_id'});
1672     var C = Backbone.Collection.extend({
1673       model: Backbone.Model.extend({
1674         constructor: function(attrs) {
1675           return attrs.type === 'a' ? new A(attrs) : new B(attrs);
1676         },
1677
1678         idAttribute: '_id'
1679       })
1680     });
1681     var collection = new C([{_id: 1, type: 'a'}, {_id: 2, type: 'b'}]);
1682     assert.equal(collection.length, 2);
1683     assert.ok(collection.at(0) instanceof A);
1684     assert.equal(collection.at(0), collection.get(1));
1685     assert.ok(collection.at(1) instanceof B);
1686     assert.equal(collection.at(1), collection.get(2));
1687
1688     C = Backbone.Collection.extend({
1689       model: function(attrs) {
1690         return attrs.type === 'a' ? new A(attrs) : new B(attrs);
1691       },
1692
1693       modelId: function(attrs) {
1694         return attrs.type + '-' + attrs.id;
1695       }
1696     });
1697     collection = new C([{id: 1, type: 'a'}, {id: 1, type: 'b'}]);
1698     assert.equal(collection.length, 2);
1699     assert.ok(collection.at(0) instanceof A);
1700     assert.equal(collection.at(0), collection.get('a-1'));
1701     assert.ok(collection.at(1) instanceof B);
1702     assert.equal(collection.at(1), collection.get('b-1'));
1703   });
1704
1705   QUnit.test('Collection with polymorphic models receives default id from modelId', function(assert) {
1706     assert.expect(6);
1707     // When the polymorphic models use 'id' for the idAttribute, all is fine.
1708     var C1 = Backbone.Collection.extend({
1709       model: function(attrs) {
1710         return new Backbone.Model(attrs);
1711       }
1712     });
1713     var c1 = new C1({id: 1});
1714     assert.equal(c1.get(1).id, 1);
1715     assert.equal(c1.modelId({id: 1}), 1);
1716
1717     // If the polymorphic models define their own idAttribute,
1718     // the modelId method should be overridden, for the reason below.
1719     var M = Backbone.Model.extend({
1720       idAttribute: '_id'
1721     });
1722     var C2 = Backbone.Collection.extend({
1723       model: function(attrs) {
1724         return new M(attrs);
1725       }
1726     });
1727     var c2 = new C2({'_id': 1});
1728     assert.equal(c2.get(1), void 0);
1729     assert.equal(c2.modelId(c2.at(0).attributes), void 0);
1730     var m = new M({'_id': 2});
1731     c2.add(m);
1732     assert.equal(c2.get(2), void 0);
1733     assert.equal(c2.modelId(m.attributes), void 0);
1734   });
1735
1736   QUnit.test('#3039 #3951: adding at index fires with correct at', function(assert) {
1737     assert.expect(4);
1738     var collection = new Backbone.Collection([{val: 0}, {val: 4}]);
1739     collection.on('add', function(model, coll, options) {
1740       assert.equal(model.get('val'), options.index);
1741     });
1742     collection.add([{val: 1}, {val: 2}, {val: 3}], {at: 1});
1743     collection.add({val: 5}, {at: 10});
1744   });
1745
1746   QUnit.test('#3039: index is not sent when at is not specified', function(assert) {
1747     assert.expect(2);
1748     var collection = new Backbone.Collection([{at: 0}]);
1749     collection.on('add', function(model, coll, options) {
1750       assert.equal(undefined, options.index);
1751     });
1752     collection.add([{at: 1}, {at: 2}]);
1753   });
1754
1755   QUnit.test('#3199 - Order changing should trigger a sort', function(assert) {
1756     assert.expect(1);
1757     var one = new Backbone.Model({id: 1});
1758     var two = new Backbone.Model({id: 2});
1759     var three = new Backbone.Model({id: 3});
1760     var collection = new Backbone.Collection([one, two, three]);
1761     collection.on('sort', function() {
1762       assert.ok(true);
1763     });
1764     collection.set([{id: 3}, {id: 2}, {id: 1}]);
1765   });
1766
1767   QUnit.test('#3199 - Adding a model should trigger a sort', function(assert) {
1768     assert.expect(1);
1769     var one = new Backbone.Model({id: 1});
1770     var two = new Backbone.Model({id: 2});
1771     var three = new Backbone.Model({id: 3});
1772     var collection = new Backbone.Collection([one, two, three]);
1773     collection.on('sort', function() {
1774       assert.ok(true);
1775     });
1776     collection.set([{id: 1}, {id: 2}, {id: 3}, {id: 0}]);
1777   });
1778
1779   QUnit.test('#3199 - Order not changing should not trigger a sort', function(assert) {
1780     assert.expect(0);
1781     var one = new Backbone.Model({id: 1});
1782     var two = new Backbone.Model({id: 2});
1783     var three = new Backbone.Model({id: 3});
1784     var collection = new Backbone.Collection([one, two, three]);
1785     collection.on('sort', function() {
1786       assert.ok(false);
1787     });
1788     collection.set([{id: 1}, {id: 2}, {id: 3}]);
1789   });
1790
1791   QUnit.test('add supports negative indexes', function(assert) {
1792     assert.expect(1);
1793     var collection = new Backbone.Collection([{id: 1}]);
1794     collection.add([{id: 2}, {id: 3}], {at: -1});
1795     collection.add([{id: 2.5}], {at: -2});
1796     collection.add([{id: 0.5}], {at: -6});
1797     assert.equal(collection.pluck('id').join(','), '0.5,1,2,2.5,3');
1798   });
1799
1800   QUnit.test('#set accepts options.at as a string', function(assert) {
1801     assert.expect(1);
1802     var collection = new Backbone.Collection([{id: 1}, {id: 2}]);
1803     collection.add([{id: 3}], {at: '1'});
1804     assert.deepEqual(collection.pluck('id'), [1, 3, 2]);
1805   });
1806
1807   QUnit.test('adding multiple models triggers `update` event once', function(assert) {
1808     assert.expect(1);
1809     var collection = new Backbone.Collection;
1810     collection.on('update', function() { assert.ok(true); });
1811     collection.add([{id: 1}, {id: 2}, {id: 3}]);
1812   });
1813
1814   QUnit.test('removing models triggers `update` event once', function(assert) {
1815     assert.expect(1);
1816     var collection = new Backbone.Collection([{id: 1}, {id: 2}, {id: 3}]);
1817     collection.on('update', function() { assert.ok(true); });
1818     collection.remove([{id: 1}, {id: 2}]);
1819   });
1820
1821   QUnit.test('remove does not trigger `update` when nothing removed', function(assert) {
1822     assert.expect(0);
1823     var collection = new Backbone.Collection([{id: 1}, {id: 2}]);
1824     collection.on('update', function() { assert.ok(false); });
1825     collection.remove([{id: 3}]);
1826   });
1827
1828   QUnit.test('set triggers `set` event once', function(assert) {
1829     assert.expect(1);
1830     var collection = new Backbone.Collection([{id: 1}, {id: 2}]);
1831     collection.on('update', function() { assert.ok(true); });
1832     collection.set([{id: 1}, {id: 3}]);
1833   });
1834
1835   QUnit.test('set does not trigger `update` event when nothing added nor removed', function(assert) {
1836     var collection = new Backbone.Collection([{id: 1}, {id: 2}]);
1837     collection.on('update', function(coll, options) {
1838       assert.equal(options.changes.added.length, 0);
1839       assert.equal(options.changes.removed.length, 0);
1840       assert.equal(options.changes.merged.length, 2);
1841     });
1842     collection.set([{id: 1}, {id: 2}]);
1843   });
1844
1845   QUnit.test('#3610 - invoke collects arguments', function(assert) {
1846     assert.expect(3);
1847     var Model = Backbone.Model.extend({
1848       method: function(x, y, z) {
1849         assert.equal(x, 1);
1850         assert.equal(y, 2);
1851         assert.equal(z, 3);
1852       }
1853     });
1854     var Collection = Backbone.Collection.extend({
1855       model: Model
1856     });
1857     var collection = new Collection([{id: 1}]);
1858     collection.invoke('method', 1, 2, 3);
1859   });
1860
1861   QUnit.test('#3662 - triggering change without model will not error', function(assert) {
1862     assert.expect(1);
1863     var collection = new Backbone.Collection([{id: 1}]);
1864     var model = collection.first();
1865     collection.on('change', function(m) {
1866       assert.equal(m, undefined);
1867     });
1868     model.trigger('change');
1869   });
1870
1871   QUnit.test('#3871 - falsy parse result creates empty collection', function(assert) {
1872     var collection = new (Backbone.Collection.extend({
1873       parse: function(data, options) {}
1874     }));
1875     collection.set('', {parse: true});
1876     assert.equal(collection.length, 0);
1877   });
1878
1879   QUnit.test("#3711 - remove's `update` event returns one removed model", function(assert) {
1880     var model = new Backbone.Model({id: 1, title: 'First Post'});
1881     var collection = new Backbone.Collection([model]);
1882     collection.on('update', function(context, options) {
1883       var changed = options.changes;
1884       assert.deepEqual(changed.added, []);
1885       assert.deepEqual(changed.merged, []);
1886       assert.strictEqual(changed.removed[0], model);
1887     });
1888     collection.remove(model);
1889   });
1890
1891   QUnit.test("#3711 - remove's `update` event returns multiple removed models", function(assert) {
1892     var model = new Backbone.Model({id: 1, title: 'First Post'});
1893     var model2 = new Backbone.Model({id: 2, title: 'Second Post'});
1894     var collection = new Backbone.Collection([model, model2]);
1895     collection.on('update', function(context, options) {
1896       var changed = options.changes;
1897       assert.deepEqual(changed.added, []);
1898       assert.deepEqual(changed.merged, []);
1899       assert.ok(changed.removed.length === 2);
1900
1901       assert.ok(_.indexOf(changed.removed, model) > -1 && _.indexOf(changed.removed, model2) > -1);
1902     });
1903     collection.remove([model, model2]);
1904   });
1905
1906   QUnit.test("#3711 - set's `update` event returns one added model", function(assert) {
1907     var model = new Backbone.Model({id: 1, title: 'First Post'});
1908     var collection = new Backbone.Collection();
1909     collection.on('update', function(context, options) {
1910       var addedModels = options.changes.added;
1911       assert.ok(addedModels.length === 1);
1912       assert.strictEqual(addedModels[0], model);
1913     });
1914     collection.set(model);
1915   });
1916
1917   QUnit.test("#3711 - set's `update` event returns multiple added models", function(assert) {
1918     var model = new Backbone.Model({id: 1, title: 'First Post'});
1919     var model2 = new Backbone.Model({id: 2, title: 'Second Post'});
1920     var collection = new Backbone.Collection();
1921     collection.on('update', function(context, options) {
1922       var addedModels = options.changes.added;
1923       assert.ok(addedModels.length === 2);
1924       assert.strictEqual(addedModels[0], model);
1925       assert.strictEqual(addedModels[1], model2);
1926     });
1927     collection.set([model, model2]);
1928   });
1929
1930   QUnit.test("#3711 - set's `update` event returns one removed model", function(assert) {
1931     var model = new Backbone.Model({id: 1, title: 'First Post'});
1932     var model2 = new Backbone.Model({id: 2, title: 'Second Post'});
1933     var model3 = new Backbone.Model({id: 3, title: 'My Last Post'});
1934     var collection = new Backbone.Collection([model]);
1935     collection.on('update', function(context, options) {
1936       var changed = options.changes;
1937       assert.equal(changed.added.length, 2);
1938       assert.equal(changed.merged.length, 0);
1939       assert.ok(changed.removed.length === 1);
1940       assert.strictEqual(changed.removed[0], model);
1941     });
1942     collection.set([model2, model3]);
1943   });
1944
1945   QUnit.test("#3711 - set's `update` event returns multiple removed models", function(assert) {
1946     var model = new Backbone.Model({id: 1, title: 'First Post'});
1947     var model2 = new Backbone.Model({id: 2, title: 'Second Post'});
1948     var model3 = new Backbone.Model({id: 3, title: 'My Last Post'});
1949     var collection = new Backbone.Collection([model, model2]);
1950     collection.on('update', function(context, options) {
1951       var removedModels = options.changes.removed;
1952       assert.ok(removedModels.length === 2);
1953       assert.strictEqual(removedModels[0], model);
1954       assert.strictEqual(removedModels[1], model2);
1955     });
1956     collection.set([model3]);
1957   });
1958
1959   QUnit.test("#3711 - set's `update` event returns one merged model", function(assert) {
1960     var model = new Backbone.Model({id: 1, title: 'First Post'});
1961     var model2 = new Backbone.Model({id: 2, title: 'Second Post'});
1962     var model2Update = new Backbone.Model({id: 2, title: 'Second Post V2'});
1963     var collection = new Backbone.Collection([model, model2]);
1964     collection.on('update', function(context, options) {
1965       var mergedModels = options.changes.merged;
1966       assert.ok(mergedModels.length === 1);
1967       assert.strictEqual(mergedModels[0].get('title'), model2Update.get('title'));
1968     });
1969     collection.set([model2Update]);
1970   });
1971
1972   QUnit.test("#3711 - set's `update` event returns multiple merged models", function(assert) {
1973     var model = new Backbone.Model({id: 1, title: 'First Post'});
1974     var modelUpdate = new Backbone.Model({id: 1, title: 'First Post V2'});
1975     var model2 = new Backbone.Model({id: 2, title: 'Second Post'});
1976     var model2Update = new Backbone.Model({id: 2, title: 'Second Post V2'});
1977     var collection = new Backbone.Collection([model, model2]);
1978     collection.on('update', function(context, options) {
1979       var mergedModels = options.changes.merged;
1980       assert.ok(mergedModels.length === 2);
1981       assert.strictEqual(mergedModels[0].get('title'), model2Update.get('title'));
1982       assert.strictEqual(mergedModels[1].get('title'), modelUpdate.get('title'));
1983     });
1984     collection.set([model2Update, modelUpdate]);
1985   });
1986
1987   QUnit.test("#3711 - set's `update` event should not be triggered adding a model which already exists exactly alike", function(assert) {
1988     var fired = false;
1989     var model = new Backbone.Model({id: 1, title: 'First Post'});
1990     var collection = new Backbone.Collection([model]);
1991     collection.on('update', function(context, options) {
1992       fired = true;
1993     });
1994     collection.set([model]);
1995     assert.equal(fired, false);
1996   });
1997
1998 })();