PageRenderTime 188ms CodeModel.GetById 24ms app.highlight 149ms RepoModel.GetById 1ms app.codeStats 0ms

/test/collection.js

https://github.com/adrianpillinger/backbone
JavaScript | 345 lines | 314 code | 30 blank | 1 comment | 16 complexity | cae9a650ea497899f41b647e4eb45320 MD5 | raw file
  1$(document).ready(function() {
  2
  3  module("Backbone.Collection");
  4
  5  window.lastRequest = null;
  6
  7  Backbone.sync = function() {
  8    lastRequest = _.toArray(arguments);
  9  };
 10
 11  var a         = new Backbone.Model({id: 3, label: 'a'});
 12  var b         = new Backbone.Model({id: 2, label: 'b'});
 13  var c         = new Backbone.Model({id: 1, label: 'c'});
 14  var d         = new Backbone.Model({id: 0, label: 'd'});
 15  var e         = null;
 16  var col       = new Backbone.Collection([a,b,c,d]);
 17  var otherCol  = new Backbone.Collection();
 18
 19  test("Collection: new and sort", function() {
 20    equals(col.first(), a, "a should be first");
 21    equals(col.last(), d, "d should be last");
 22    col.comparator = function(model) { return model.id; };
 23    col.sort();
 24    equals(col.first(), d, "d should be first");
 25    equals(col.last(), a, "a should be last");
 26    equals(col.length, 4);
 27  });
 28
 29  test("Collection: get, getByCid", function() {
 30    equals(col.get(0), d);
 31    equals(col.get(2), b);
 32    equals(col.getByCid(col.first().cid), col.first());
 33  });
 34
 35  test("Collection: get with non-default ids", function() {
 36    var col = new Backbone.Collection();
 37    var MongoModel = Backbone.Model.extend({
 38      idAttribute: '_id'
 39    });
 40    var model = new MongoModel({_id: 100});
 41    col.add(model);
 42    equals(col.get(100), model);
 43    model.set({_id: 101});
 44    equals(col.get(101), model);
 45  });
 46
 47  test("Collection: update index when id changes", function() {
 48    var col = new Backbone.Collection();
 49    col.add([
 50      {id : 0, name : 'one'},
 51      {id : 1, name : 'two'}
 52    ]);
 53    var one = col.get(0);
 54    equals(one.get('name'), 'one');
 55    one.set({id : 101});
 56    equals(col.get(0), null);
 57    equals(col.get(101).get('name'), 'one');
 58  });
 59
 60  test("Collection: at", function() {
 61    equals(col.at(2), b);
 62  });
 63
 64  test("Collection: pluck", function() {
 65    equals(col.pluck('label').join(' '), 'd c b a');
 66  });
 67
 68  test("Collection: add", function() {
 69    var added = opts = secondAdded = null;
 70    e = new Backbone.Model({id: 10, label : 'e'});
 71    otherCol.add(e);
 72    otherCol.bind('add', function() {
 73      secondAdded = true;
 74    });
 75    col.bind('add', function(model, collection, options){
 76      added = model.get('label');
 77      opts = options;
 78    });
 79    col.add(e, {amazing: true});
 80    equals(added, 'e');
 81    equals(col.length, 5);
 82    equals(col.last(), e);
 83    equals(otherCol.length, 1);
 84    equals(secondAdded, null);
 85    ok(opts.amazing);
 86
 87    var f = new Backbone.Model({id: 20, label : 'f'});
 88    var g = new Backbone.Model({id: 21, label : 'g'});
 89    var h = new Backbone.Model({id: 22, label : 'h'});
 90    var atCol = new Backbone.Collection([f, g, h]);
 91    equals(atCol.length, 3);
 92    atCol.add(e, {at: 1});
 93    equals(atCol.length, 4);
 94    equals(atCol.at(1), e);
 95    equals(atCol.last(), h);
 96  });
 97
 98  test("Collection: add model to collection twice", function() {
 99    try {
100      // no id, same cid
101      var a2 = new Backbone.Model({label: a.label});
102      a2.cid = a.cid;
103      col.add(a2);
104      ok(false, "duplicate; expected add to fail");
105    } catch (e) {
106      equals(e.message, "Can't add the same model to a set twice,3");
107    }
108  });
109
110  test("Collection: add model to multiple collections", function() {
111    var counter = 0;
112    var e = new Backbone.Model({id: 10, label : 'e'});
113    e.bind('add', function(model, collection) {
114      counter++;
115      equals(e, model);
116      if (counter > 1) {
117        equals(collection, colF);
118      } else {
119        equals(collection, colE);
120      }
121    });
122    var colE = new Backbone.Collection([]);
123    colE.bind('add', function(model, collection) {
124      equals(e, model);
125      equals(colE, collection);
126    });
127    var colF = new Backbone.Collection([]);
128    colF.bind('add', function(model, collection) {
129      equals(e, model);
130      equals(colF, collection);
131    });
132    colE.add(e);
133    equals(e.collection, colE);
134    colF.add(e);
135    equals(e.collection, colE);
136  });
137
138  test("Collection: remove", function() {
139    var removed = otherRemoved = null;
140    col.bind('remove', function(model){ removed = model.get('label'); });
141    otherCol.bind('remove', function(){ otherRemoved = true; });
142    col.remove(e);
143    equals(removed, 'e');
144    equals(col.length, 4);
145    equals(col.first(), d);
146    equals(otherRemoved, null);
147  });
148
149  test("Collection: events are unbound on remove", function() {
150    var counter = 0;
151    var dj = new Backbone.Model();
152    var emcees = new Backbone.Collection([dj]);
153    emcees.bind('change', function(){ counter++; });
154    dj.set({name : 'Kool'});
155    equals(counter, 1);
156    emcees.reset([]);
157    equals(dj.collection, undefined);
158    dj.set({name : 'Shadow'});
159    equals(counter, 1);
160  });
161
162  test("Collection: remove in multiple collections", function() {
163    var modelData = {
164      id : 5,
165      title : 'Othello'
166    };
167    var passed = false;
168    var e = new Backbone.Model(modelData);
169    var f = new Backbone.Model(modelData);
170    f.bind('remove', function() {
171      passed = true;
172    });
173    var colE = new Backbone.Collection([e]);
174    var colF = new Backbone.Collection([f]);
175    ok(e != f);
176    ok(colE.length == 1);
177    ok(colF.length == 1);
178    colE.remove(e);
179    equals(passed, false);
180    ok(colE.length == 0);
181    colF.remove(e);
182    ok(colF.length == 0);
183    equals(passed, true);
184  });
185
186  test("Collection: remove same model in multiple collection", function() {
187    var counter = 0;
188    var e = new Backbone.Model({id: 5, title: 'Othello'});
189    e.bind('remove', function(model, collection) {
190      counter++;
191      equals(e, model);
192      if (counter > 1) {
193        equals(collection, colE);
194      } else {
195        equals(collection, colF);
196      }
197    });
198    var colE = new Backbone.Collection([e]);
199    colE.bind('remove', function(model, collection) {
200      equals(e, model);
201      equals(colE, collection);
202    });
203    var colF = new Backbone.Collection([e]);
204    colF.bind('remove', function(model, collection) {
205      equals(e, model);
206      equals(colF, collection);
207    });
208    equals(colE, e.collection);
209    colF.remove(e);
210    ok(colF.length == 0);
211    ok(colE.length == 1);
212    equals(counter, 1);
213    equals(colE, e.collection);
214    colE.remove(e);
215    equals(null, e.collection);
216    ok(colE.length == 0);
217    equals(counter, 2);
218  });
219
220  test("Collection: model destroy removes from all collections", function() {
221    var e = new Backbone.Model({id: 5, title: 'Othello'});
222    e.sync = function(method, model, options) { options.success({}); };
223    var colE = new Backbone.Collection([e]);
224    var colF = new Backbone.Collection([e]);
225    e.destroy();
226    ok(colE.length == 0);
227    ok(colF.length == 0);
228    equals(null, e.collection);
229  });
230
231  test("Colllection: non-persisted model destroy removes from all collections", function() {
232    var e = new Backbone.Model({title: 'Othello'});
233    e.sync = function(method, model, options) { throw "should not be called"; };
234    var colE = new Backbone.Collection([e]);
235    var colF = new Backbone.Collection([e]);
236    e.destroy();
237    ok(colE.length == 0);
238    ok(colF.length == 0);
239    equals(null, e.collection);
240  });
241
242  test("Collection: fetch", function() {
243    col.fetch();
244    equals(lastRequest[0], 'read');
245    equals(lastRequest[1], col);
246  });
247
248  test("Collection: create", function() {
249    var model = col.create({label: 'f'});
250    equals(lastRequest[0], 'create');
251    equals(lastRequest[1], model);
252    equals(model.get('label'), 'f');
253    equals(model.collection, col);
254  });
255
256  test("Collection: create enforces validation", function() {
257    var ValidatingModel = Backbone.Model.extend({
258      validate: function(attrs) {
259        return "fail";
260      }
261    });
262    var ValidatingCollection = Backbone.Collection.extend({
263      model: ValidatingModel
264    });
265    var col = new ValidatingCollection();
266    equals(col.create({"foo":"bar"}),false);
267  });
268
269  test("Collection: a failing create runs the error callback", function() {
270    var ValidatingModel = Backbone.Model.extend({
271      validate: function(attrs) {
272        return "fail";
273      }
274    });
275    var ValidatingCollection = Backbone.Collection.extend({
276      model: ValidatingModel
277    });
278    var flag = false;
279    var callback = function(model, error) { flag = true; };
280    var col = new ValidatingCollection();
281    col.create({"foo":"bar"}, { error: callback });
282    equals(flag, true);
283  });
284
285  test("collection: initialize", function() {
286    var Collection = Backbone.Collection.extend({
287      initialize: function() {
288        this.one = 1;
289      }
290    });
291    var coll = new Collection;
292    equals(coll.one, 1);
293  });
294
295  test("Collection: toJSON", function() {
296    equals(JSON.stringify(col), '[{"id":0,"label":"d"},{"id":1,"label":"c"},{"id":2,"label":"b"},{"id":3,"label":"a"}]');
297  });
298
299  test("Collection: Underscore methods", function() {
300    equals(col.map(function(model){ return model.get('label'); }).join(' '), 'd c b a');
301    equals(col.any(function(model){ return model.id === 100; }), false);
302    equals(col.any(function(model){ return model.id === 0; }), true);
303    equals(col.indexOf(b), 2);
304    equals(col.size(), 4);
305    equals(col.rest().length, 3);
306    ok(!_.include(col.rest()), a);
307    ok(!_.include(col.rest()), d);
308    ok(!col.isEmpty());
309    ok(!_.include(col.without(d)), d);
310    equals(col.max(function(model){ return model.id; }).id, 3);
311    equals(col.min(function(model){ return model.id; }).id, 0);
312    same(col.chain()
313            .filter(function(o){ return o.id % 2 === 0; })
314            .map(function(o){ return o.id * 2; })
315            .value(),
316         [0, 4]);
317  });
318
319  test("Collection: reset", function() {
320    var resetCount = 0;
321    var models = col.models;
322    col.bind('reset', function() { resetCount += 1; });
323    col.reset([]);
324    equals(resetCount, 1);
325    equals(col.length, 0);
326    equals(col.last(), null);
327    col.reset(models);
328    equals(resetCount, 2);
329    equals(col.length, 4);
330    equals(col.last(), a);
331    col.reset(_.map(models, function(m){ return m.attributes; }));
332    equals(resetCount, 3);
333    equals(col.length, 4);
334    ok(col.last() !== a);
335    ok(_.isEqual(col.last().attributes, a.attributes));
336  });
337
338  test("Collection: trigger custom events on models", function() {
339    var fired = null;
340    a.bind("custom", function() { fired = true; });
341    a.trigger("custom");
342    equals(fired, true);
343  });
344
345});