Conditions | 1 |
Paths | 4096 |
Total Lines | 1998 |
Lines | 0 |
Ratio | 0 % |
Changes | 1 | ||
Bugs | 0 | Features | 0 |
Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.
For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.
Commonly applied refactorings include:
If many parameters/temporary variables are present:
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 | })(); |
||
1999 |