PageRenderTime 51ms CodeModel.GetById 35ms app.highlight 13ms RepoModel.GetById 1ms app.codeStats 0ms

/test/collection.js

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