PageRenderTime 43ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/node_modules/ender/test/node_modules/backbone/test/collection.js

http://github.com/projexsys/Jolt
JavaScript | 543 lines | 489 code | 53 blank | 1 comment | 26 complexity | 368ff259f7fcf3dd1a7a2a8b117d1992 MD5 | raw file
Possible License(s): GPL-3.0, LGPL-3.0, Apache-2.0, MIT, BSD-3-Clause
  1. $(document).ready(function() {
  2. var lastRequest = null;
  3. var sync = Backbone.sync;
  4. module("Backbone.Collection", {
  5. setup: function() {
  6. Backbone.sync = function() {
  7. lastRequest = _.toArray(arguments);
  8. };
  9. },
  10. teardown: function() {
  11. Backbone.sync = sync;
  12. }
  13. });
  14. var a = new Backbone.Model({id: 3, label: 'a'});
  15. var b = new Backbone.Model({id: 2, label: 'b'});
  16. var c = new Backbone.Model({id: 1, label: 'c'});
  17. var d = new Backbone.Model({id: 0, label: 'd'});
  18. var e = null;
  19. var col = new Backbone.Collection([a,b,c,d]);
  20. var otherCol = new Backbone.Collection();
  21. test("Collection: new and sort", function() {
  22. equal(col.first(), a, "a should be first");
  23. equal(col.last(), d, "d should be last");
  24. col.comparator = function(a, b) {
  25. return a.id > b.id ? -1 : 1;
  26. };
  27. col.sort();
  28. equal(col.first(), a, "a should be first");
  29. equal(col.last(), d, "d should be last");
  30. col.comparator = function(model) { return model.id; };
  31. col.sort();
  32. equal(col.first(), d, "d should be first");
  33. equal(col.last(), a, "a should be last");
  34. equal(col.length, 4);
  35. });
  36. test("Collection: get, getByCid", function() {
  37. equal(col.get(0), d);
  38. equal(col.get(2), b);
  39. equal(col.getByCid(col.first().cid), col.first());
  40. });
  41. test("Collection: get with non-default ids", function() {
  42. var col = new Backbone.Collection();
  43. var MongoModel = Backbone.Model.extend({
  44. idAttribute: '_id'
  45. });
  46. var model = new MongoModel({_id: 100});
  47. col.add(model);
  48. equal(col.get(100), model);
  49. model.set({_id: 101});
  50. equal(col.get(101), model);
  51. });
  52. test("Collection: add model with attributes modified by set", function() {
  53. var CustomSetModel = Backbone.Model.extend({
  54. defaults: {
  55. number_as_string: null //presence of defaults forces extend
  56. },
  57. validate: function (attributes) {
  58. if (!_.isString(attributes.num_as_string)) {
  59. return 'fail';
  60. }
  61. },
  62. set: function (attributes, options) {
  63. if (attributes.num_as_string) {
  64. attributes.num_as_string = attributes.num_as_string.toString();
  65. }
  66. Backbone.Model.prototype.set.call(this, attributes, options);
  67. }
  68. });
  69. var CustomSetCollection = Backbone.Collection.extend({
  70. model: CustomSetModel
  71. });
  72. raises(function(){
  73. new CustomSetCollection([{ num_as_string: 2 }]);
  74. });
  75. });
  76. test("Collection: update index when id changes", function() {
  77. var col = new Backbone.Collection();
  78. col.add([
  79. {id : 0, name : 'one'},
  80. {id : 1, name : 'two'}
  81. ]);
  82. var one = col.get(0);
  83. equal(one.get('name'), 'one');
  84. one.set({id : 101});
  85. equal(col.get(0), null);
  86. equal(col.get(101).get('name'), 'one');
  87. });
  88. test("Collection: at", function() {
  89. equal(col.at(2), b);
  90. });
  91. test("Collection: pluck", function() {
  92. equal(col.pluck('label').join(' '), 'd c b a');
  93. });
  94. test("Collection: add", function() {
  95. var added = opts = secondAdded = null;
  96. e = new Backbone.Model({id: 10, label : 'e'});
  97. otherCol.add(e);
  98. otherCol.bind('add', function() {
  99. secondAdded = true;
  100. });
  101. col.bind('add', function(model, collection, options){
  102. added = model.get('label');
  103. equal(options.index, 4);
  104. opts = options;
  105. });
  106. col.add(e, {amazing: true});
  107. equal(added, 'e');
  108. equal(col.length, 5);
  109. equal(col.last(), e);
  110. equal(otherCol.length, 1);
  111. equal(secondAdded, null);
  112. ok(opts.amazing);
  113. var f = new Backbone.Model({id: 20, label : 'f'});
  114. var g = new Backbone.Model({id: 21, label : 'g'});
  115. var h = new Backbone.Model({id: 22, label : 'h'});
  116. var atCol = new Backbone.Collection([f, g, h]);
  117. equal(atCol.length, 3);
  118. atCol.add(e, {at: 1});
  119. equal(atCol.length, 4);
  120. equal(atCol.at(1), e);
  121. equal(atCol.last(), h);
  122. });
  123. test("Collection: add multiple models", function() {
  124. var col = new Backbone.Collection([{at: 0}, {at: 1}, {at: 9}]);
  125. col.add([{at: 2}, {at: 3}, {at: 4}, {at: 5}, {at: 6}, {at: 7}, {at: 8}], {at: 2});
  126. for (var i = 0; i <= 5; i++) {
  127. equal(col.at(i).get('at'), i);
  128. }
  129. });
  130. test("Collection: can't add model to collection twice", function() {
  131. raises(function(){
  132. // no id, same cid
  133. var a2 = new Backbone.Model({label: a.label});
  134. a2.cid = a.cid;
  135. col.add(a2);
  136. ok(false, "duplicate; expected add to fail");
  137. }, "Can't add the same model to a collection twice");
  138. });
  139. test("Collection: can't add different model with same id to collection twice", function() {
  140. raises(function(){
  141. var col = new Backbone.Collection;
  142. col.add({id: 101});
  143. col.add({id: 101});
  144. ok(false, "duplicate; expected add to fail");
  145. }, "Can't add the same model to a collection twice");
  146. });
  147. test("Collection: add model to multiple collections", function() {
  148. var counter = 0;
  149. var e = new Backbone.Model({id: 10, label : 'e'});
  150. e.bind('add', function(model, collection) {
  151. counter++;
  152. equal(e, model);
  153. if (counter > 1) {
  154. equal(collection, colF);
  155. } else {
  156. equal(collection, colE);
  157. }
  158. });
  159. var colE = new Backbone.Collection([]);
  160. colE.bind('add', function(model, collection) {
  161. equal(e, model);
  162. equal(colE, collection);
  163. });
  164. var colF = new Backbone.Collection([]);
  165. colF.bind('add', function(model, collection) {
  166. equal(e, model);
  167. equal(colF, collection);
  168. });
  169. colE.add(e);
  170. equal(e.collection, colE);
  171. colF.add(e);
  172. equal(e.collection, colE);
  173. });
  174. test("Collection: add model with parse", function() {
  175. var Model = Backbone.Model.extend({
  176. parse: function(obj) {
  177. obj.value += 1;
  178. return obj;
  179. }
  180. });
  181. var Col = Backbone.Collection.extend({model: Model});
  182. var col = new Col;
  183. col.add({value: 1}, {parse: true});
  184. equal(col.at(0).get('value'), 2);
  185. });
  186. test("Collection: add model to collection with sort()-style comparator", function() {
  187. var col = new Backbone.Collection;
  188. col.comparator = function(a, b) {
  189. return a.get('name') < b.get('name') ? -1 : 1;
  190. };
  191. var tom = new Backbone.Model({name: 'Tom'});
  192. var rob = new Backbone.Model({name: 'Rob'});
  193. var tim = new Backbone.Model({name: 'Tim'});
  194. col.add(tom);
  195. col.add(rob);
  196. col.add(tim);
  197. equal(col.indexOf(rob), 0);
  198. equal(col.indexOf(tim), 1);
  199. equal(col.indexOf(tom), 2);
  200. });
  201. test("Collection: comparator that depends on `this`", function() {
  202. var col = new Backbone.Collection;
  203. col.negative = function(num) {
  204. return -num;
  205. };
  206. col.comparator = function(a) {
  207. return this.negative(a.id);
  208. };
  209. col.add([{id: 1}, {id: 2}, {id: 3}]);
  210. equal(col.pluck('id').join(' '), '3 2 1');
  211. });
  212. test("Collection: remove", function() {
  213. var removed = otherRemoved = null;
  214. col.bind('remove', function(model, col, options) {
  215. removed = model.get('label');
  216. equal(options.index, 4);
  217. });
  218. otherCol.bind('remove', function(model, col, options) {
  219. otherRemoved = true;
  220. });
  221. col.remove(e);
  222. equal(removed, 'e');
  223. equal(col.length, 4);
  224. equal(col.first(), d);
  225. equal(otherRemoved, null);
  226. });
  227. test("Collection: events are unbound on remove", function() {
  228. var counter = 0;
  229. var dj = new Backbone.Model();
  230. var emcees = new Backbone.Collection([dj]);
  231. emcees.bind('change', function(){ counter++; });
  232. dj.set({name : 'Kool'});
  233. equal(counter, 1);
  234. emcees.reset([]);
  235. equal(dj.collection, undefined);
  236. dj.set({name : 'Shadow'});
  237. equal(counter, 1);
  238. });
  239. test("Collection: remove in multiple collections", function() {
  240. var modelData = {
  241. id : 5,
  242. title : 'Othello'
  243. };
  244. var passed = false;
  245. var e = new Backbone.Model(modelData);
  246. var f = new Backbone.Model(modelData);
  247. f.bind('remove', function() {
  248. passed = true;
  249. });
  250. var colE = new Backbone.Collection([e]);
  251. var colF = new Backbone.Collection([f]);
  252. ok(e != f);
  253. ok(colE.length == 1);
  254. ok(colF.length == 1);
  255. colE.remove(e);
  256. equal(passed, false);
  257. ok(colE.length == 0);
  258. colF.remove(e);
  259. ok(colF.length == 0);
  260. equal(passed, true);
  261. });
  262. test("Collection: remove same model in multiple collection", function() {
  263. var counter = 0;
  264. var e = new Backbone.Model({id: 5, title: 'Othello'});
  265. e.bind('remove', function(model, collection) {
  266. counter++;
  267. equal(e, model);
  268. if (counter > 1) {
  269. equal(collection, colE);
  270. } else {
  271. equal(collection, colF);
  272. }
  273. });
  274. var colE = new Backbone.Collection([e]);
  275. colE.bind('remove', function(model, collection) {
  276. equal(e, model);
  277. equal(colE, collection);
  278. });
  279. var colF = new Backbone.Collection([e]);
  280. colF.bind('remove', function(model, collection) {
  281. equal(e, model);
  282. equal(colF, collection);
  283. });
  284. equal(colE, e.collection);
  285. colF.remove(e);
  286. ok(colF.length == 0);
  287. ok(colE.length == 1);
  288. equal(counter, 1);
  289. equal(colE, e.collection);
  290. colE.remove(e);
  291. equal(null, e.collection);
  292. ok(colE.length == 0);
  293. equal(counter, 2);
  294. });
  295. test("Collection: model destroy removes from all collections", function() {
  296. var e = new Backbone.Model({id: 5, title: 'Othello'});
  297. e.sync = function(method, model, options) { options.success({}); };
  298. var colE = new Backbone.Collection([e]);
  299. var colF = new Backbone.Collection([e]);
  300. e.destroy();
  301. ok(colE.length == 0);
  302. ok(colF.length == 0);
  303. equal(undefined, e.collection);
  304. });
  305. test("Colllection: non-persisted model destroy removes from all collections", function() {
  306. var e = new Backbone.Model({title: 'Othello'});
  307. e.sync = function(method, model, options) { throw "should not be called"; };
  308. var colE = new Backbone.Collection([e]);
  309. var colF = new Backbone.Collection([e]);
  310. e.destroy();
  311. ok(colE.length == 0);
  312. ok(colF.length == 0);
  313. equal(undefined, e.collection);
  314. });
  315. test("Collection: fetch", function() {
  316. col.fetch();
  317. equal(lastRequest[0], 'read');
  318. equal(lastRequest[1], col);
  319. equal(lastRequest[2].parse, true);
  320. col.fetch({parse: false});
  321. equal(lastRequest[2].parse, false);
  322. });
  323. test("Collection: create", function() {
  324. var model = col.create({label: 'f'}, {wait: true});
  325. equal(lastRequest[0], 'create');
  326. equal(lastRequest[1], model);
  327. equal(model.get('label'), 'f');
  328. equal(model.collection, col);
  329. });
  330. test("Collection: create enforces validation", function() {
  331. var ValidatingModel = Backbone.Model.extend({
  332. validate: function(attrs) {
  333. return "fail";
  334. }
  335. });
  336. var ValidatingCollection = Backbone.Collection.extend({
  337. model: ValidatingModel
  338. });
  339. var col = new ValidatingCollection();
  340. equal(col.create({"foo":"bar"}), false);
  341. });
  342. test("Collection: a failing create runs the error callback", function() {
  343. var ValidatingModel = Backbone.Model.extend({
  344. validate: function(attrs) {
  345. return "fail";
  346. }
  347. });
  348. var ValidatingCollection = Backbone.Collection.extend({
  349. model: ValidatingModel
  350. });
  351. var flag = false;
  352. var callback = function(model, error) { flag = true; };
  353. var col = new ValidatingCollection();
  354. col.create({"foo":"bar"}, { error: callback });
  355. equal(flag, true);
  356. });
  357. test("collection: initialize", function() {
  358. var Collection = Backbone.Collection.extend({
  359. initialize: function() {
  360. this.one = 1;
  361. }
  362. });
  363. var coll = new Collection;
  364. equal(coll.one, 1);
  365. });
  366. test("Collection: toJSON", function() {
  367. equal(JSON.stringify(col), '[{"id":0,"label":"d"},{"id":1,"label":"c"},{"id":2,"label":"b"},{"id":3,"label":"a"}]');
  368. });
  369. test("Collection: Underscore methods", function() {
  370. equal(col.map(function(model){ return model.get('label'); }).join(' '), 'd c b a');
  371. equal(col.any(function(model){ return model.id === 100; }), false);
  372. equal(col.any(function(model){ return model.id === 0; }), true);
  373. equal(col.indexOf(b), 2);
  374. equal(col.size(), 4);
  375. equal(col.rest().length, 3);
  376. ok(!_.include(col.rest()), a);
  377. ok(!_.include(col.rest()), d);
  378. ok(!col.isEmpty());
  379. ok(!_.include(col.without(d)), d);
  380. equal(col.max(function(model){ return model.id; }).id, 3);
  381. equal(col.min(function(model){ return model.id; }).id, 0);
  382. same(col.chain()
  383. .filter(function(o){ return o.id % 2 === 0; })
  384. .map(function(o){ return o.id * 2; })
  385. .value(),
  386. [0, 4]);
  387. });
  388. test("Collection: reset", function() {
  389. var resetCount = 0;
  390. var models = col.models;
  391. col.bind('reset', function() { resetCount += 1; });
  392. col.reset([]);
  393. equal(resetCount, 1);
  394. equal(col.length, 0);
  395. equal(col.last(), null);
  396. col.reset(models);
  397. equal(resetCount, 2);
  398. equal(col.length, 4);
  399. equal(col.last(), a);
  400. col.reset(_.map(models, function(m){ return m.attributes; }));
  401. equal(resetCount, 3);
  402. equal(col.length, 4);
  403. ok(col.last() !== a);
  404. ok(_.isEqual(col.last().attributes, a.attributes));
  405. });
  406. test("Collection: trigger custom events on models", function() {
  407. var fired = null;
  408. a.bind("custom", function() { fired = true; });
  409. a.trigger("custom");
  410. equal(fired, true);
  411. });
  412. test("Collection: add does not alter arguments", function(){
  413. var attrs = {};
  414. var models = [attrs];
  415. new Backbone.Collection().add(models);
  416. equal(models.length, 1);
  417. ok(attrs === models[0]);
  418. });
  419. test("#714: access `model.collection` in a brand new model.", 2, function() {
  420. var col = new Backbone.Collection;
  421. var Model = Backbone.Model.extend({
  422. set: function(attrs) {
  423. equal(attrs.prop, 'value');
  424. equal(this.collection, col);
  425. return this;
  426. }
  427. });
  428. col.model = Model;
  429. col.create({prop: 'value'});
  430. });
  431. test("#574, remove its own reference to the .models array.", function() {
  432. var col = new Backbone.Collection([
  433. {id: 1}, {id: 2}, {id: 3}, {id: 4}, {id: 5}, {id: 6}
  434. ]);
  435. equal(col.length, 6);
  436. col.remove(col.models);
  437. equal(col.length, 0);
  438. });
  439. test("#861, adding models to a collection which do not pass validation", function() {
  440. raises(function() {
  441. var Model = Backbone.Model.extend({
  442. validate: function(attrs) {
  443. if (attrs.id == 3) return "id can't be 3";
  444. }
  445. });
  446. var Collection = Backbone.Collection.extend({
  447. model: Model
  448. });
  449. var col = new Collection;
  450. col.add([{id: 1}, {id: 2}, {id: 3}, {id: 4}, {id: 5}, {id: 6}]);
  451. }, "Can't add an invalid model to a collection");
  452. });
  453. test("Collection: index with comparator", function() {
  454. expect(4);
  455. var counter = 0;
  456. var col = new Backbone.Collection([{id: 2}, {id: 4}], {
  457. comparator: function(model){ return model.id; }
  458. }).on('add', function(model, colleciton, options){
  459. if (model.id == 1) {
  460. equal(options.index, 0);
  461. equal(counter++, 0);
  462. }
  463. if (model.id == 3) {
  464. equal(options.index, 2);
  465. equal(counter++, 1);
  466. }
  467. });
  468. col.add([{id: 3}, {id: 1}]);
  469. });
  470. test("Collection: throwing during add leaves consistent state", function() {
  471. expect(4);
  472. var col = new Backbone.Collection();
  473. col.bind('test', function() { ok(false); });
  474. col.model = Backbone.Model.extend({
  475. validate: function(attrs){ if (!attrs.valid) return 'invalid'; }
  476. });
  477. var model = new col.model({id: 1, valid: true});
  478. raises(function() { col.add([model, {id: 2}]); });
  479. model.trigger('test');
  480. ok(!col.getByCid(model.cid));
  481. ok(!col.get(1));
  482. equal(col.length, 0);
  483. });
  484. test("Collection: multiple copies of the same model", function() {
  485. var col = new Backbone.Collection();
  486. var model = new Backbone.Model();
  487. raises(function() { col.add([model, model]); });
  488. raises(function() { col.add([{id: 1}, {id: 1}]); });
  489. });
  490. });